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
49use gondola_core::prelude::*;
50
51
52////use tof_dataclasses::serialization::Serialization;
53//use tof_dataclasses::errors::SerializationError;
54//use tof_dataclasses::packets::TofPacket;
55//use tof_dataclasses::events::{
56//  //RBEvent,
57//  //TofEvent,
58//  TofEvent,
59//  //TofHit,
60//  //TofEventHeader,
61//  //MasterTriggerEvent,
62//  RBWaveform,
63//};
64//use tof_dataclasses::calibrations::RBCalibrations;
65//use tof_dataclasses::database::Paddle;
66
67use 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  // baseline histograms
95  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  // energy depostion & relative position histograms
102  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  // charges
113  pub charge_a           : HashMap<u8, VecDeque<f64>>,
114  pub charge_b           : HashMap<u8, VecDeque<f64>>, 
115
116  // list for the paddle selector
117  pub all_paddles        : HashMap<u8, TofPaddle>,
118  pub pdl_state          : ListState,
119  // Fix me, should be a pointer
120  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    // get calibrations
140    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, VecDeque::<RBWaveform>::new());
175      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, // enough points for histograms! 
198                                 
199      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        //let hits = ev.get_hits();
301        // FIXME - get baselines from hits
302        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          //let ch_a_bl_rms = h.get_bl_a_rms();
325          //let ch_b_bl_rms = h.get_bl_b_rms();
326          // cut on the range
327          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_ch_a.get_mut(&(h.paddle_id as u8)).unwrap().fill(&h.get_bl_a());
334          self.baseline_rms_ch_a.get_mut(&(h.paddle_id as u8)).unwrap().fill(&h.get_bl_a_rms());
335          //self.baseline_ch_b.get_mut(&(h.paddle_id as u8)).unwrap().fill(&h.get_bl_b());
336          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  // Color::Blue was nice for background
344  pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
345   
346    match self.menu.get_active_menu_item() {
347      UIMenuItem::Back => {
348        // as usual, layout first
349        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          //.scroll((5, 10))
398          .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 mut label_a   = String::from("");
449        //let mut label_b   = String::from("");
450        let wf_theme      = self.theme.clone();
451        match self.wf.get_mut(&(self.current_paddle.paddle_id as u8)) {
452          None => {
453            //for (i,k) in wf.adc.iter().enumerate() {
454            //  wf_data_a.push_back((i as f64, *k as f64));
455            //}
456          }
457          Some(wf) => {
458            //label_a  = format!("Paddle {}A, RB {}-{}",self.current_paddle.paddle_id, wf.rb_id, wf.rb_channel_a + 1);
459            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            //*self.last_wf_ch_a.get_mut(&wf.paddle_id).unwrap() = wf_data_a;
469            //label_b  = format!("Paddle {}B, RB {}-{}",self.current_paddle.paddle_id, wf.rb_id, wf.rb_channel_b + 1);
470            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            //*self.last_wf_ch_b.get_mut(&wf.paddle_id).unwrap() = wf_data_b;
480          }
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        // 2d charge plot
495        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 xaxis  = canvas::Line {
506            //   x1 : 0.0,
507            //   x2 : 30.0,
508            //   y1 : 0.0,
509            //   y2 : 0.0,
510            //   color : self.theme.fg0
511            // };
512            // let yaxis  = canvas::Line {
513            //   x1 : 0.0,
514            //   x2 : 0.0,
515            //   y1 : 0.0,
516            //   y2 : 30.0,
517            //   color : self.theme.fg0
518            // };
519            let points = Points {
520              coords : &ch2d_points.as_slice(),
521              color  : self.theme.hc,
522            };
523            ctx.draw(&points);
524            //ctx.draw(&xaxis);
525            //ctx.draw(&yaxis);
526          })
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        // baseline histos
532        //println!("{:?}", self.baseline_ch_a.get(&(self.current_paddle.paddle_id as u8)).unwrap());
533        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        // B side
543        // let bl_b_labels = create_labels(&self.baseline_ch_b.get(&(self.current_paddle.paddle_id as u8)).unwrap());
544        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_labels = create_labels(&self.baseline_rms_ch_b.get(&(self.current_paddle.paddle_id as u8)).unwrap());
549        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        // histograms
592        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        // edep hist
621        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        // norm_pos
626        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    } // end match
633  } 
634}