From 7ada5aea4a4225ba9bc106fc0b474bd1aa08c7e7 Mon Sep 17 00:00:00 2001 From: karencfv Date: Mon, 9 Dec 2024 19:40:01 +1300 Subject: [PATCH] Clean up value handling --- dev-tools/clickana/src/lib.rs | 114 ++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 38 deletions(-) diff --git a/dev-tools/clickana/src/lib.rs b/dev-tools/clickana/src/lib.rs index 454ef38297..9b4d0a07e1 100644 --- a/dev-tools/clickana/src/lib.rs +++ b/dev-tools/clickana/src/lib.rs @@ -212,29 +212,47 @@ impl ChartMetadata { } #[derive(Debug)] -struct ChartData { - metadata: ChartMetadata, - data_points: Vec<(f64, f64)>, - mid_time_utc: DateTime, - start_time_utc: DateTime, - end_time_utc: DateTime, - start_time_unix: f64, - end_time_unix: f64, - lower_label_value: f64, - mid_label_value: f64, - upper_label_value: f64, - lower_bound_value: f64, - upper_bound_value: f64, +struct TimeSeriesValues { + values: Vec, } -impl ChartData { - fn new( - raw_data: Vec, - metadata: ChartMetadata, - ) -> Result { +impl TimeSeriesValues { + fn new(raw_data: &Vec) -> Self { + let values: Vec = raw_data.iter().map(|ts| ts.value).collect(); + Self { values } + } + + fn min(&self) -> Result<&f64> { + let Some(min_value) = + self.values.iter().min_by(|a, b| a.partial_cmp(b).unwrap()) + else { + bail!("no values have been retrieved") + }; + + Ok(min_value) + } + + fn max(&self) -> Result<&f64> { + let Some(max_value) = + self.values.iter().max_by(|a, b| a.partial_cmp(b).unwrap()) + else { + bail!("no values have been retrieved") + }; + + Ok(max_value) + } +} + +#[derive(Debug)] +struct DataPoints { + data: Vec<(f64, f64)>, +} + +impl DataPoints { + fn new(timeseries: &Vec) -> Self { // These values will be used to render the graph and ratatui // requires them to be f64 - let data_points: Vec<(f64, f64)> = raw_data + let data: Vec<(f64, f64)> = timeseries .iter() .map(|ts| { ( @@ -250,35 +268,52 @@ impl ChartData { ) }) .collect(); + Self { data } + } +} - // These values will be used to calculate maximum and minimum values in order - // to create labels and set bounds for the Y axis. - let values: Vec = raw_data.iter().map(|ts| ts.value).collect(); - let Some(min_value_bytes) = - values.iter().min_by(|a, b| a.partial_cmp(b).unwrap()) - else { - bail!("no values have been retrieved") - }; +#[derive(Debug)] +struct ChartData { + metadata: ChartMetadata, + data_points: DataPoints, + mid_time_utc: DateTime, + start_time_utc: DateTime, + end_time_utc: DateTime, + start_time_unix: f64, + end_time_unix: f64, + lower_label_value: f64, + mid_label_value: f64, + upper_label_value: f64, + lower_bound_value: f64, + upper_bound_value: f64, +} - let Some(max_value_bytes) = - values.iter().max_by(|a, b| a.partial_cmp(b).unwrap()) - else { - bail!("no values have been retrieved") - }; +impl ChartData { + fn new( + raw_data: Vec, + metadata: ChartMetadata, + ) -> Result { + // Retrieve datapoints that will be charted + let data_points = DataPoints::new(&raw_data); + + // Retrieve values only to create chart bouds and labels + let values = TimeSeriesValues::new(&raw_data); + let max_value = values.max()?; + let min_value = values.min()?; // In case there is very little variance in the y axis, we will be adding some // padding to the bounds and labels so we don't end up with repeated labels or // straight lines too close to the upper bounds. let upper_bound_value = - metadata.unit.padded_max_value_raw(max_value_bytes)?; + metadata.unit.padded_max_value_raw(max_value)?; let upper_label_value = - metadata.unit.padded_max_value_unit(max_value_bytes)?; + metadata.unit.padded_max_value_unit(max_value)?; let lower_bound_value = - metadata.unit.padded_min_value_raw(min_value_bytes)?; + metadata.unit.padded_min_value_raw(min_value)?; let lower_label_value = - metadata.unit.padded_min_value_unit(min_value_bytes)?; + metadata.unit.padded_min_value_unit(min_value)?; let mid_label_value = - metadata.unit.avg_value_unit(min_value_bytes, max_value_bytes)?; + metadata.unit.avg_value_unit(min_value, max_value)?; // These timestamps will be used to calculate maximum and minimum values in order // to create labels and set bounds for the X axis. As above, some of these conversions @@ -347,7 +382,7 @@ impl ChartData { .marker(Marker::Braille) .style(Style::default().fg(Color::LightGreen)) .graph_type(GraphType::Line) - .data(&self.data_points)]; + .data(&self.data_points.data)]; let chart = Chart::new(datasets) .block( @@ -363,6 +398,8 @@ impl ChartData { .style(Style::default().gray()) .bounds([self.start_time_unix, self.end_time_unix]) .labels([ + // TODO: Remove start time and print the interval at the top of the + // dashboard format!("{}", self.start_time_utc).bold(), format!("{}", self.mid_time_utc).bold(), format!("{}", self.end_time_utc).bold(), @@ -378,6 +415,7 @@ impl ChartData { self.lower_label_value, self.metadata.unit ) .bold(), + // TODO: Only show fractional number if not .0 ? format!( "{:.1} {}", self.mid_label_value, self.metadata.unit