1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
use plotlib::page::Page; use plotlib::scatter::{Scatter, Style}; use plotlib::style::Point; use plotlib::view::View; use rand::{self, Rng}; use std::path::Path; use trackable::error::Failed; use task::TaskResult; use Result; #[derive(Debug)] pub struct PlotOptions { sampling_rate: f64, y_max: Option<f64>, } impl PlotOptions { pub fn new() -> PlotOptions { PlotOptions { sampling_rate: 1.0, y_max: None, } } pub fn sampling_rate(&mut self, sampling_rate: f64) -> &mut Self { self.sampling_rate = sampling_rate; self } pub fn y_max(&mut self, y_max: f64) -> &mut Self { self.y_max = Some(y_max); self } pub fn plot_text(&self, results: &[TaskResult]) -> Result<String> { track!(self.with_view(results, |v| Page::single(&v).to_text())) } pub fn plot_svg<P: AsRef<Path>>(&self, results: &[TaskResult], svg_file: P) -> Result<()> { track!(self.with_view(results, |v| Page::single(&v).save(svg_file))) } fn with_view<F, T>(&self, results: &[TaskResult], f: F) -> Result<T> where F: FnOnce(View) -> T, { track_assert!(self.sampling_rate > 0.0, Failed; self.sampling_rate); track_assert!(self.sampling_rate <= 1.0, Failed; self.sampling_rate); let times = results.iter().map(|r| r.elapsed).collect::<Vec<_>>(); let data = times .iter() .cloned() .enumerate() .map(|(x, y)| (x as f64, y.as_f64())) .filter(|_| rand::thread_rng().gen_range(0.0, 1.0) < self.sampling_rate) .filter(|t| self.y_max.is_none() || Some(t.1) <= self.y_max) .collect::<Vec<_>>(); let s = Scatter::from_vec(&data).style(&Style::new().size(1.0)); let y_max = self .y_max .unwrap_or_else(|| times.iter().max().map(|x| x.as_f64()).unwrap_or(0.0)); let v = View::new() .add(&s) .x_range(0.0, times.len() as f64) .y_range(0.0, y_max) .x_label("Sequence Number") .y_label("Latency Seconds"); Ok(f(v)) } }