liftof_tui/tabs/
tab_paddles.rs

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