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