• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::*;
2 
3 use std::path::Path;
4 
5 use crate::estimate::{ConfidenceInterval, Estimate};
6 use crate::stats::bivariate::regression::Slope;
7 use crate::stats::bivariate::Data;
8 
regression_figure( title: Option<&str>, path: &Path, formatter: &dyn ValueFormatter, measurements: &MeasurementData<'_>, size: Option<(u32, u32)>, )9 pub(crate) fn regression_figure(
10     title: Option<&str>,
11     path: &Path,
12     formatter: &dyn ValueFormatter,
13     measurements: &MeasurementData<'_>,
14     size: Option<(u32, u32)>,
15 ) {
16     let slope_estimate = measurements.absolute_estimates.slope.as_ref().unwrap();
17     let slope_dist = measurements.distributions.slope.as_ref().unwrap();
18     let (lb, ub) =
19         slope_dist.confidence_interval(slope_estimate.confidence_interval.confidence_level);
20 
21     let data = &measurements.data;
22     let (max_iters, typical) = (data.x().max(), data.y().max());
23     let mut scaled_y: Vec<f64> = data.y().iter().cloned().collect();
24     let unit = formatter.scale_values(typical, &mut scaled_y);
25     let scaled_y = Sample::new(&scaled_y);
26 
27     let point_estimate = Slope::fit(&measurements.data).0;
28     let mut scaled_points = [point_estimate * max_iters, lb * max_iters, ub * max_iters];
29     let _ = formatter.scale_values(typical, &mut scaled_points);
30     let [point, lb, ub] = scaled_points;
31 
32     let exponent = (max_iters.log10() / 3.).floor() as i32 * 3;
33 
34     let x_scale = 10f64.powi(-exponent);
35     let x_label = if exponent == 0 {
36         "Iterations".to_owned()
37     } else {
38         format!("Iterations (x 10^{})", exponent)
39     };
40 
41     let size = size.unwrap_or(SIZE);
42     let root_area = SVGBackend::new(path, size).into_drawing_area();
43 
44     let mut cb = ChartBuilder::on(&root_area);
45     if let Some(title) = title {
46         cb.caption(title, (DEFAULT_FONT, 20));
47     }
48 
49     let x_range = plotters::data::fitting_range(data.x().iter());
50     let y_range = plotters::data::fitting_range(scaled_y.iter());
51 
52     let mut chart = cb
53         .margin((5).percent())
54         .set_label_area_size(LabelAreaPosition::Left, (5).percent_width().min(60))
55         .set_label_area_size(LabelAreaPosition::Bottom, (5).percent_height().min(40))
56         .build_cartesian_2d(x_range, y_range)
57         .unwrap();
58 
59     chart
60         .configure_mesh()
61         .x_desc(x_label)
62         .y_desc(format!("Total sample time ({})", unit))
63         .x_label_formatter(&|x| pretty_print_float(x * x_scale, true))
64         .light_line_style(&TRANSPARENT)
65         .draw()
66         .unwrap();
67 
68     chart
69         .draw_series(
70             data.x()
71                 .iter()
72                 .zip(scaled_y.iter())
73                 .map(|(x, y)| Circle::new((*x, *y), POINT_SIZE, DARK_BLUE.filled())),
74         )
75         .unwrap()
76         .label("Sample")
77         .legend(|(x, y)| Circle::new((x + 10, y), POINT_SIZE, DARK_BLUE.filled()));
78 
79     chart
80         .draw_series(std::iter::once(PathElement::new(
81             vec![(0.0, 0.0), (max_iters, point)],
82             &DARK_BLUE,
83         )))
84         .unwrap()
85         .label("Linear regression")
86         .legend(|(x, y)| {
87             PathElement::new(
88                 vec![(x, y), (x + 20, y)],
89                 DARK_BLUE.filled().stroke_width(2),
90             )
91         });
92 
93     chart
94         .draw_series(std::iter::once(Polygon::new(
95             vec![(0.0, 0.0), (max_iters, lb), (max_iters, ub)],
96             DARK_BLUE.mix(0.25).filled(),
97         )))
98         .unwrap()
99         .label("Confidence interval")
100         .legend(|(x, y)| {
101             Rectangle::new([(x, y - 5), (x + 20, y + 5)], DARK_BLUE.mix(0.25).filled())
102         });
103 
104     if title.is_some() {
105         chart
106             .configure_series_labels()
107             .position(SeriesLabelPosition::UpperLeft)
108             .draw()
109             .unwrap();
110     }
111 }
112 
regression_comparison_figure( title: Option<&str>, path: &Path, formatter: &dyn ValueFormatter, measurements: &MeasurementData<'_>, comparison: &ComparisonData, base_data: &Data<'_, f64, f64>, size: Option<(u32, u32)>, )113 pub(crate) fn regression_comparison_figure(
114     title: Option<&str>,
115     path: &Path,
116     formatter: &dyn ValueFormatter,
117     measurements: &MeasurementData<'_>,
118     comparison: &ComparisonData,
119     base_data: &Data<'_, f64, f64>,
120     size: Option<(u32, u32)>,
121 ) {
122     let data = &measurements.data;
123     let max_iters = base_data.x().max().max(data.x().max());
124     let typical = base_data.y().max().max(data.y().max());
125 
126     let exponent = (max_iters.log10() / 3.).floor() as i32 * 3;
127     let x_scale = 10f64.powi(-exponent);
128 
129     let x_label = if exponent == 0 {
130         "Iterations".to_owned()
131     } else {
132         format!("Iterations (x 10^{})", exponent)
133     };
134 
135     let Estimate {
136         confidence_interval:
137             ConfidenceInterval {
138                 lower_bound: base_lb,
139                 upper_bound: base_ub,
140                 ..
141             },
142         point_estimate: base_point,
143         ..
144     } = comparison.base_estimates.slope.as_ref().unwrap();
145 
146     let Estimate {
147         confidence_interval:
148             ConfidenceInterval {
149                 lower_bound: lb,
150                 upper_bound: ub,
151                 ..
152             },
153         point_estimate: point,
154         ..
155     } = measurements.absolute_estimates.slope.as_ref().unwrap();
156 
157     let mut points = [
158         base_lb * max_iters,
159         base_point * max_iters,
160         base_ub * max_iters,
161         lb * max_iters,
162         point * max_iters,
163         ub * max_iters,
164     ];
165     let unit = formatter.scale_values(typical, &mut points);
166     let [base_lb, base_point, base_ub, lb, point, ub] = points;
167 
168     let y_max = point.max(base_point);
169 
170     let size = size.unwrap_or(SIZE);
171     let root_area = SVGBackend::new(path, size).into_drawing_area();
172 
173     let mut cb = ChartBuilder::on(&root_area);
174     if let Some(title) = title {
175         cb.caption(title, (DEFAULT_FONT, 20));
176     }
177 
178     let mut chart = cb
179         .margin((5).percent())
180         .set_label_area_size(LabelAreaPosition::Left, (5).percent_width().min(60))
181         .set_label_area_size(LabelAreaPosition::Bottom, (5).percent_height().min(40))
182         .build_cartesian_2d(0.0..max_iters, 0.0..y_max)
183         .unwrap();
184 
185     chart
186         .configure_mesh()
187         .x_desc(x_label)
188         .y_desc(format!("Total sample time ({})", unit))
189         .x_label_formatter(&|x| pretty_print_float(x * x_scale, true))
190         .light_line_style(&TRANSPARENT)
191         .draw()
192         .unwrap();
193 
194     chart
195         .draw_series(vec![
196             PathElement::new(vec![(0.0, 0.0), (max_iters, base_point)], &DARK_RED).into_dyn(),
197             Polygon::new(
198                 vec![(0.0, 0.0), (max_iters, base_lb), (max_iters, base_ub)],
199                 DARK_RED.mix(0.25).filled(),
200             )
201             .into_dyn(),
202         ])
203         .unwrap()
204         .label("Base Sample")
205         .legend(|(x, y)| {
206             PathElement::new(vec![(x, y), (x + 20, y)], DARK_RED.filled().stroke_width(2))
207         });
208 
209     chart
210         .draw_series(vec![
211             PathElement::new(vec![(0.0, 0.0), (max_iters, point)], &DARK_BLUE).into_dyn(),
212             Polygon::new(
213                 vec![(0.0, 0.0), (max_iters, lb), (max_iters, ub)],
214                 DARK_BLUE.mix(0.25).filled(),
215             )
216             .into_dyn(),
217         ])
218         .unwrap()
219         .label("New Sample")
220         .legend(|(x, y)| {
221             PathElement::new(
222                 vec![(x, y), (x + 20, y)],
223                 DARK_BLUE.filled().stroke_width(2),
224             )
225         });
226 
227     if title.is_some() {
228         chart
229             .configure_series_labels()
230             .position(SeriesLabelPosition::UpperLeft)
231             .draw()
232             .unwrap();
233     }
234 }
235