1use std::collections::{
7 HashMap,
8 VecDeque,
9};
10use std::sync::{
11 Arc,
12 Mutex,
13};
14
15use crossbeam_channel::{
16 Receiver,
17 };
19
20use ratatui::prelude::*;
21use ratatui::symbols::Marker;
22
23use ratatui::Frame;
24use ratatui::layout::Rect;
25use ratatui::widgets::{
26 Block,
27 BorderType,
28 Borders,
29 Paragraph,
30 List,
31 ListItem,
32 ListState,
33 canvas::{
34 Canvas,
35 Points},
38};
39
40use ndhistogram::{
41 ndhistogram,
42 Histogram,
43 Hist1D,
44};
45use ndhistogram::axis::{
46 Uniform,
47};
48
49use gondola_core::prelude::*;
50
51
52use crate::colors::ColorTheme;
68use crate::menu::{
69 PaddleMenu,
70 UIMenu,
71 UIMenuItem
72};
73
74use crate::widgets::{
75 prep_data,
76 create_labels,
77 histogram,
78 timeseries,
79};
80
81#[derive(Debug, Clone)]
82pub struct PaddleTab<'a> {
83 pub theme : ColorTheme,
84 pub te_receiver : Receiver<TofEvent>,
85 pub event_queue : VecDeque<TofEvent>,
86 pub wf_receiver : Receiver<TofPacket>,
87 pub queue_size : usize,
88 pub menu : PaddleMenu<'a>,
89 pub wf : HashMap<u8, RBWaveform>,
90 pub last_wf_ch_a : HashMap<u8, VecDeque<(f64, f64)>>,
91 pub last_wf_ch_b : HashMap<u8, VecDeque<(f64, f64)>>,
92 pub wf_label_a : String,
93 pub wf_label_b : String,
94 pub calibrations : HashMap<u8, RBCalibrations>,
96 pub baseline_ch_a : HashMap<u8, Hist1D<Uniform<f32>>>,
97 pub baseline_ch_b : HashMap<u8, Hist1D<Uniform<f32>>>,
98 pub baseline_rms_ch_a : HashMap<u8, Hist1D<Uniform<f32>>>,
99 pub baseline_rms_ch_b : HashMap<u8, Hist1D<Uniform<f32>>>,
100
101 pub h_edep : HashMap<u8, Hist1D<Uniform<f32>>>,
103 pub h_rel_pos : HashMap<u8, Hist1D<Uniform<f32>>>,
104
105 pub pca_histo : HashMap<u8, Hist1D<Uniform<f32>>>,
106 pub pcb_histo : HashMap<u8, Hist1D<Uniform<f32>>>,
107 pub pha_histo : HashMap<u8, Hist1D<Uniform<f32>>>,
108 pub phb_histo : HashMap<u8, Hist1D<Uniform<f32>>>,
109 pub pta_histo : HashMap<u8, Hist1D<Uniform<f32>>>,
110 pub ptb_histo : HashMap<u8, Hist1D<Uniform<f32>>>,
111
112 pub charge_a : HashMap<u8, VecDeque<f64>>,
114 pub charge_b : HashMap<u8, VecDeque<f64>>,
115
116 pub all_paddles : HashMap<u8, TofPaddle>,
118 pub pdl_state : ListState,
119 pub current_paddle : TofPaddle,
121 pub pdl_items : Vec::<ListItem<'a>>,
122 pub pdl_active : bool,
123 pub pdl_selector : usize,
124 pub pdl_changed : bool,
125}
126
127impl PaddleTab<'_> {
128 pub fn new(te_receiver : Receiver<TofEvent>,
129 wf_receiver : Receiver<TofPacket>,
130 all_paddles : HashMap<u8, TofPaddle>,
131 calibrations: Arc<Mutex<HashMap<u8, RBCalibrations>>>,
132 theme : ColorTheme) -> Self {
133 let theme_c = theme.clone();
134 let mut pd_select_items = Vec::<ListItem>::new();
135 for k in 1..161 {
136 let this_item = format!(" Paddle{:0>3}", k);
137 pd_select_items.push(ListItem::new(Line::from(this_item)));
138 }
139 let mut calibrations_cloned = HashMap::<u8, RBCalibrations>::new();
141 match calibrations.lock() {
142 Err(_err) => error!("Unable to get lock on rbcalibrations!"),
143 Ok(cali) => {
144 calibrations_cloned = cali.clone();
145 }
146 }
147 let mut charge_a = HashMap::<u8, VecDeque<f64>>::new();
148 let mut charge_b = HashMap::<u8, VecDeque<f64>>::new();
149 let mut wf = HashMap::<u8, RBWaveform>::new();
150 let mut bl_ch_a = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
151 let mut bl_ch_b = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
152 let mut blrms_ch_a = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
153 let mut blrms_ch_b = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
154 let mut h_edep_ = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
155 let mut h_rel_pos_ = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
156 let mut pca_histo = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
157 let mut pcb_histo = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
158 let mut pha_histo = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
159 let mut phb_histo = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
160 let mut pta_histo = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
161 let mut ptb_histo = HashMap::<u8, Hist1D<Uniform<f32>>>::new();
162 let bins_bl = Uniform::new(20, -2.0, 2.0).unwrap();
163 let bins_bl_rms = Uniform::new(20, 0.0, 2.0).unwrap();
164 let bins_edep = Uniform::new(50, 0.0, 25.0).unwrap();
165 let bins_relpos = Uniform::new(50, 0.0, 1.2).unwrap();
166 let bins_ph = Uniform::new(50, 0.0, 200.0).unwrap();
167 let bins_pt = Uniform::new(50, 25.0, 350.0).unwrap();
168 let bins_pc = Uniform::new(30, 0.0, 40.0).unwrap();
169 let mut lwf_ch_a = HashMap::<u8, VecDeque<(f64, f64)>>::new();
170 let mut lwf_ch_b = HashMap::<u8, VecDeque<(f64, f64)>>::new();
171 for pid in 1..161 {
172 charge_a.insert(pid, VecDeque::<f64>::new());
173 charge_b.insert(pid, VecDeque::<f64>::new());
174 wf.insert(pid, RBWaveform::new());
176 bl_ch_a.insert(pid, ndhistogram!(bins_bl.clone()));
177 bl_ch_b.insert(pid, ndhistogram!(bins_bl.clone()));
178 blrms_ch_a.insert(pid, ndhistogram!(bins_bl_rms.clone()));
179 blrms_ch_b.insert(pid, ndhistogram!(bins_bl_rms.clone()));
180 h_edep_.insert(pid, ndhistogram!(bins_edep.clone()));
181 h_rel_pos_.insert(pid, ndhistogram!(bins_relpos.clone()));
182 pca_histo.insert(pid, ndhistogram!(bins_pc .clone()));
183 pcb_histo.insert(pid, ndhistogram!(bins_pc .clone()));
184 pha_histo.insert(pid, ndhistogram!(bins_ph .clone()));
185 phb_histo.insert(pid, ndhistogram!(bins_ph .clone()));
186 pta_histo.insert(pid, ndhistogram!(bins_pt .clone()));
187 ptb_histo.insert(pid, ndhistogram!(bins_pt .clone()));
188 lwf_ch_a.insert(pid, VecDeque::<(f64,f64)>::new());
189 lwf_ch_b.insert(pid, VecDeque::<(f64,f64)>::new());
190 }
191
192 Self {
193 theme,
194 te_receiver,
195 wf_receiver,
196 event_queue : VecDeque::<TofEvent>::new(),
197 queue_size : 10000, menu : PaddleMenu::new(theme_c),
200 wf : wf,
201 wf_label_a : String::from("A"),
202 wf_label_b : String::from("B"),
203 last_wf_ch_a : lwf_ch_a,
204 last_wf_ch_b : lwf_ch_b,
205 calibrations : calibrations_cloned,
206 baseline_ch_a : bl_ch_a,
207 baseline_ch_b : bl_ch_b,
208 baseline_rms_ch_a : blrms_ch_a,
209 baseline_rms_ch_b : blrms_ch_b,
210 h_edep : h_edep_,
211 h_rel_pos : h_rel_pos_,
212 pca_histo,
213 pcb_histo,
214 pha_histo,
215 phb_histo,
216 pta_histo,
217 ptb_histo,
218 charge_a ,
219 charge_b ,
220 all_paddles,
221 pdl_items : pd_select_items,
222 pdl_state : ListState::default(),
223 current_paddle : TofPaddle::new(),
224 pdl_active : false,
225 pdl_selector : 1,
226 pdl_changed : false,
227 }
228 }
229
230 pub fn next_pd(&mut self) {
231 let i = match self.pdl_state.selected() {
232 Some(i) => {
233 if i >= self.pdl_items.len() - 1 {
234 self.pdl_items.len() - 1
235 } else {
236 i + 1
237 }
238 }
239 None => 0,
240 };
241 self.pdl_state.select(Some(i));
242 }
243
244 pub fn prev_pd(&mut self) {
245 let i = match self.pdl_state.selected() {
246 Some(i) => {
247 if i == 0 {
248 0
249 } else {
250 i - 1
251 }
252 }
253 None => 0,
254 };
255 self.pdl_state.select(Some(i));
256 }
257
258 pub fn unselect_pdl(&mut self) {
259 self.pdl_state.select(None);
260 }
261
262 pub fn receive_packet(&mut self) -> Result<(), SerializationError> {
263 match self.wf_receiver.try_recv() {
264 Err(_err) => {
265 }
266 Ok(wf_pack) => {
267 let mut wf : RBWaveform = wf_pack.unpack()?;
268 match self.calibrations.get(&wf.rb_id) {
269 None => error!("RBCalibrations for board {} not available!", wf.rb_id),
270 Some(rbcal) => {
271 match wf.calibrate(rbcal) {
272 Err(err) => error!("Calibration error! {err}"),
273 Ok(_) => ()
274 }
275 }
276 }
277 if wf.paddle_id == self.current_paddle.paddle_id as u8 {
278 let rb_channel_a = wf.rb_channel_a + 1;
279 let rb_channel_b = wf.rb_channel_b + 1;
280 if (rb_channel_a != self.current_paddle.rb_chA as u8 )
281 || (rb_channel_b != self.current_paddle.rb_chB as u8 ) {
282 error!("Inconsistent paddle RB channels! Maybe A and B are switched!");
283 }
284 }
285 if wf.paddle_id == 0 {
286 error!("Got waveform with padle id 0!");
287 } else if wf.paddle_id > 160 {
288 error!("Got paddle id which is too large! {}", wf.paddle_id);
289 } else {
290 let pid = wf.paddle_id as u8;
291 *self.wf.get_mut(&pid).unwrap() = wf;
292 }
293 }
294 }
295 match self.te_receiver.try_recv() {
296 Err(_err) => {
297 return Ok(());
298 },
299 Ok(mut ev) => {
300 for h in &mut ev.hits {
303 self.h_edep.get_mut(&(h.paddle_id as u8)).unwrap().fill(&h.get_edep());
304 h.set_paddle(&self.current_paddle);
305 let rel_pos = h.get_pos()/(self.current_paddle.length*10.0);
306 self.h_rel_pos.get_mut(&h.paddle_id).unwrap().fill(&rel_pos);
307 self.pha_histo.get_mut(&h.paddle_id).unwrap().fill(&h.get_peak_a());
308 self.phb_histo.get_mut(&h.paddle_id).unwrap().fill(&h.get_peak_b());
309 self.pca_histo.get_mut(&h.paddle_id).unwrap().fill(&h.get_charge_a());
310 self.pcb_histo.get_mut(&h.paddle_id).unwrap().fill(&h.get_charge_b());
311 self.pta_histo.get_mut(&h.paddle_id).unwrap().fill(&h.get_time_a());
312 self.ptb_histo.get_mut(&h.paddle_id).unwrap().fill(&h.get_time_a());
313
314 self.charge_a.get_mut(&(h.paddle_id as u8)).unwrap().push_back(h.get_charge_a() as f64);
315 self.charge_b.get_mut(&(h.paddle_id as u8)).unwrap().push_back(h.get_charge_b() as f64);
316 if self.charge_a.get_mut(&(h.paddle_id as u8)).unwrap().len() > self.queue_size {
317 self.charge_a.get_mut(&(h.paddle_id as u8)).unwrap().pop_front();
318 }
319 if self.charge_b.get_mut(&(h.paddle_id as u8)).unwrap().len() > self.queue_size {
320 self.charge_b.get_mut(&(h.paddle_id as u8)).unwrap().pop_front();
321 }
322 let ch_a_bl = h.get_bl_a();
323 let ch_b_bl = h.get_bl_b();
324 if -2.0 < ch_a_bl && ch_b_bl < 2.0 {
328 self.baseline_ch_a.get_mut(&(h.paddle_id as u8)).unwrap().fill(&ch_a_bl);
329 }
330 if -2.0 < ch_b_bl && ch_b_bl < 2.0 {
331 self.baseline_ch_b.get_mut(&(h.paddle_id as u8)).unwrap().fill(&ch_b_bl);
332 }
333 self.baseline_rms_ch_a.get_mut(&(h.paddle_id as u8)).unwrap().fill(&h.get_bl_a_rms());
335 self.baseline_rms_ch_b.get_mut(&(h.paddle_id as u8)).unwrap().fill(&h.get_bl_b_rms());
337 }
338 return Ok(());
339 }
340 }
341 }
342
343 pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
345
346 match self.menu.get_active_menu_item() {
347 UIMenuItem::Back => {
348 let main_lo = Layout::default()
350 .direction(Direction::Horizontal)
351 .constraints(
352 [Constraint::Percentage(15), Constraint::Percentage(85)].as_ref(),
353 )
354 .split(*main_window);
355 let pdl = Block::default()
356 .borders(Borders::ALL)
357 .style(self.theme.style())
358 .title("Select Paddle")
359 .border_type(BorderType::Plain);
360 let pd_select_list = List::new(self.pdl_items.clone()).block(pdl)
361 .highlight_style(self.theme.highlight().add_modifier(Modifier::BOLD))
362 .highlight_symbol(">>")
363 .repeat_highlight_symbol(true);
364 match self.pdl_state.selected() {
365 None => {
366 let selector = 1;
367 if self.pdl_selector != selector {
368 self.pdl_changed = true;
369 self.pdl_selector = selector;
370 } else {
371 self.pdl_changed = false;
372 }
373 },
374 Some(_pid) => {
375 let selector = _pid + 1;
376 if self.pdl_selector != selector {
377 self.pdl_changed = true;
378 self.pdl_selector = selector;
379 } else {
380 self.pdl_changed = false;
381 }
382 }
383 }
384 let view_string : String;
385 match self.all_paddles.get(&(self.pdl_selector as u8)) {
386 Some(_pd) => {
387 view_string = format!("{}", _pd);
388 self.current_paddle = _pd.clone();
389 }
390 None => {
391 view_string = format!("No information for Paddle {} in DB or DB not available!", self.pdl_selector);
392 }
393 }
394 let pd_view = Paragraph::new(view_string)
395 .style(self.theme.style())
396 .alignment(Alignment::Left)
397 .block(
399 Block::default()
400 .borders(Borders::ALL)
401 .style(self.theme.style())
402 .title("Paddle")
403 .border_type(BorderType::Rounded),
404 );
405 frame.render_stateful_widget(pd_select_list, main_lo[0], &mut self.pdl_state );
406 frame.render_widget(pd_view, main_lo[1]);
407 }
408 UIMenuItem::Signal => {
409 let main_lo = Layout::default()
410 .direction(Direction::Horizontal)
411 .constraints(
412 [Constraint::Percentage(50),
413 Constraint::Percentage(50)].as_ref(),
414 )
415 .split(*main_window);
416 let wf_lo = Layout::default()
417 .direction(Direction::Vertical)
418 .constraints(
419 [Constraint::Percentage(40),
420 Constraint::Percentage(40),
421 Constraint::Percentage(20)].as_ref(),
422 )
423 .split(main_lo[0]);
424 let ch_lo = Layout::default()
425 .direction(Direction::Vertical)
426 .constraints(
427 [Constraint::Percentage(80),
428 Constraint::Percentage(20)].as_ref(),
429 )
430 .split(main_lo[1]);
431 let bla_lo = Layout::default()
432 .direction(Direction::Horizontal)
433 .constraints(
434 [Constraint::Percentage(50),
435 Constraint::Percentage(50)].as_ref(),
436 )
437 .split(wf_lo[2]);
438 let blb_lo = Layout::default()
439 .direction(Direction::Horizontal)
440 .constraints(
441 [Constraint::Percentage(50),
442 Constraint::Percentage(50)].as_ref(),
443 )
444 .split(ch_lo[1]);
445
446 let mut wf_data_a = VecDeque::<(f64, f64)>::new();
447 let mut wf_data_b = VecDeque::<(f64, f64)>::new();
448 let wf_theme = self.theme.clone();
451 match self.wf.get_mut(&(self.current_paddle.paddle_id as u8)) {
452 None => {
453 }
457 Some(wf) => {
458 if wf.voltages_a.len() == 0 {
460 for (i,k) in wf.adc_a.iter().enumerate() {
461 wf_data_a.push_back((i as f64, *k as f64));
462 }
463 } else {
464 for k in 0..wf.nanoseconds_a.len() {
465 wf_data_a.push_back((wf.nanoseconds_a[k] as f64, wf.voltages_a[k] as f64));
466 }
467 }
468 if wf.voltages_b.len() == 0 {
471 for (i,k) in wf.adc_b.iter().enumerate() {
472 wf_data_b.push_back((i as f64, *k as f64));
473 }
474 } else {
475 for k in 0..wf.nanoseconds_b.len() {
476 wf_data_b.push_back((wf.nanoseconds_b[k] as f64, wf.voltages_b[k] as f64));
477 }
478 }
479 }
481 }
482
483 let wf_chart_a = timeseries(&mut wf_data_a,
484 self.wf_label_a.clone(),
485 self.wf_label_a.clone(),
486 &wf_theme);
487 let wf_chart_b = timeseries(&mut wf_data_b,
488 self.wf_label_b.clone(),
489 self.wf_label_b.clone(),
490 &wf_theme);
491 frame.render_widget(wf_chart_a, wf_lo[0]);
492 frame.render_widget(wf_chart_b, wf_lo[1]);
493
494 let mut ch2d_points = Vec::<(f64, f64)>::new();
496 for k in 0..self.charge_a.get(&(self.current_paddle.paddle_id as u8)).unwrap().len() {
497 ch2d_points.push((self.charge_a.get(&(self.current_paddle.paddle_id as u8)).unwrap()[k],
498 self.charge_b.get(&(self.current_paddle.paddle_id as u8)).unwrap()[k]));
499 }
500
501 let charge_plot = Canvas::default()
502 .block(Block::bordered().title("Charge AvsB"))
503 .marker(Marker::Braille)
504 .paint(|ctx| {
505 let points = Points {
520 coords : &ch2d_points.as_slice(),
521 color : self.theme.hc,
522 };
523 ctx.draw(&points);
524 })
527 .x_bounds([0.0, 200.0])
528 .y_bounds([0.0, 200.0]);
529 frame.render_widget(charge_plot, ch_lo[0]);
530
531 let bl_a_labels = create_labels(&self.baseline_ch_a.get(&(self.current_paddle.paddle_id as u8)).unwrap());
534 let bl_a_data = prep_data(&self.baseline_ch_a.get(&(self.current_paddle.paddle_id as u8)).unwrap(), &bl_a_labels, 1, false);
535 let bl_a_chart = histogram(bl_a_data, String::from("Baseline Side A [mV]"), 2, 0, &self.theme);
536 frame.render_widget(bl_a_chart, bla_lo[0]);
537
538 let bl_a_rms_data = prep_data(&self.baseline_rms_ch_a.get(&(self.current_paddle.paddle_id as u8)).unwrap(), &bl_a_labels, 1, false);
539 let bl_a_rms_chart = histogram(bl_a_rms_data, String::from("Baseline RMS Side A [mV]"), 2, 0, &self.theme);
540 frame.render_widget(bl_a_rms_chart, bla_lo[1]);
541
542 let bl_b_data = prep_data(&self.baseline_ch_b.get(&(self.current_paddle.paddle_id as u8)).unwrap(), &bl_a_labels, 1, false);
545 let bl_b_chart = histogram(bl_b_data, String::from("Baseline Side B [mV]"), 2, 0, &self.theme);
546 frame.render_widget(bl_b_chart, blb_lo[0]);
547
548 let bl_b_rms_data = prep_data(&self.baseline_rms_ch_b.get(&(self.current_paddle.paddle_id as u8)).unwrap(), &bl_a_labels, 1, false);
550 let bl_b_rms_chart = histogram(bl_b_rms_data, String::from("Baseline RMS Side B [mV]"), 2, 0, &self.theme);
551 frame.render_widget(bl_b_rms_chart, blb_lo[1]);
552 }
553 UIMenuItem::RecoVars => {
554 let main_lo = Layout::default()
555 .direction(Direction::Horizontal)
556 .constraints(
557 [Constraint::Percentage(60), Constraint::Percentage(40)].as_ref(),
558 )
559 .split(*main_window);
560 let col_left = Layout::default()
561 .direction(Direction::Horizontal)
562 .constraints(
563 [Constraint::Percentage(50), Constraint::Percentage(50)].as_ref(),
564 )
565 .split(main_lo[0]);
566 let rows_right = Layout::default()
567 .direction(Direction::Vertical)
568 .constraints(
569 [Constraint::Percentage(33),
570 Constraint::Percentage(33),
571 Constraint::Percentage(34)].as_ref(),
572 )
573 .split(main_lo[1]);
574 let rows_left_left = Layout::default()
575 .direction(Direction::Vertical)
576 .constraints(
577 [Constraint::Percentage(33),
578 Constraint::Percentage(33),
579 Constraint::Percentage(34)].as_ref(),
580 )
581 .split(col_left[0]);
582 let rows_left_right = Layout::default()
583 .direction(Direction::Vertical)
584 .constraints(
585 [Constraint::Percentage(33),
586 Constraint::Percentage(33),
587 Constraint::Percentage(34)].as_ref(),
588 )
589 .split(col_left[1]);
590
591 let pid = self.current_paddle.paddle_id as u8;
593
594 let ph_labels = create_labels(&self.pha_histo.get(&pid).unwrap());
595 let pha_data = prep_data(&self.pha_histo.get(&pid).unwrap(), &ph_labels, 5, false);
596 let pha_chart = histogram(pha_data, String::from("Pulse height SideA [mV]"), 2, 0, &self.theme);
597 frame.render_widget(pha_chart, rows_left_left[0]);
598 let phb_data = prep_data(&self.phb_histo.get(&pid).unwrap(), &ph_labels, 5, false);
599 let phb_chart = histogram(phb_data, String::from("Pulse height SideB [mV]"), 2, 0, &self.theme);
600 frame.render_widget(phb_chart, rows_left_right[0]);
601
602 let pt_labels = create_labels(&self.pta_histo.get(&pid).unwrap());
603 let pta_data = prep_data(&self.pta_histo.get(&pid).unwrap(), &pt_labels, 5, false);
604 let pta_chart = histogram(pta_data, String::from("Pulse time SideA [a.u.]"), 2, 0, &self.theme);
605 frame.render_widget(pta_chart, rows_left_left[1]);
606
607 let ptb_data = prep_data(&self.ptb_histo.get(&pid).unwrap(), &pt_labels, 5, false);
608 let ptb_chart = histogram(ptb_data, String::from("Pulse time SideB [a.u.]"), 2, 0, &self.theme);
609 frame.render_widget(ptb_chart, rows_left_right[1]);
610
611 let pc_labels = create_labels(&self.pca_histo.get(&pid).unwrap());
612 let pca_data = prep_data(&self.pca_histo.get(&pid).unwrap(), &pc_labels, 5, false);
613 let pca_chart = histogram(pca_data, String::from("Pulse charge SideA [mC]"), 2, 0, &self.theme);
614 frame.render_widget(pca_chart, rows_left_left[2]);
615
616 let pcb_data = prep_data(&self.pcb_histo.get(&pid).unwrap(), &pc_labels, 5, false);
617 let pcb_chart = histogram(pcb_data, String::from("Pulse charge SideB [mC]"), 2, 0, &self.theme);
618 frame.render_widget(pcb_chart, rows_left_right[2]);
619
620 let edep_labels = create_labels(&self.h_edep.get(&(self.current_paddle.paddle_id as u8)).unwrap());
622 let edep_data = prep_data(&self.h_edep.get (&(self.current_paddle.paddle_id as u8)).unwrap(), &edep_labels, 1, false);
623 let edep_chart = histogram(edep_data, String::from("Reco. Energy Deposition [minI]"), 1, 0, &self.theme);
624 frame.render_widget(edep_chart, rows_right[0]);
625 let relpos_labels = create_labels(&self.h_rel_pos.get(&(self.current_paddle.paddle_id as u8)).unwrap());
627 let relpos_data = prep_data(&self.h_rel_pos.get (&(self.current_paddle.paddle_id as u8)).unwrap(), &relpos_labels, 1, false);
628 let relpos_chart = histogram(relpos_data, String::from("Rel. pos. (1 = B side)"), 1, 0, &self.theme);
629 frame.render_widget(relpos_chart, rows_right[1]);
630 }
631 _ => ()
632 } }
634}