1 | use super::*; |
2 | |
3 | use std::path::Path; |
4 | |
5 | pub(crate) fn iteration_times_figure( |
6 | title: Option<&str>, |
7 | path: &Path, |
8 | formatter: &dyn ValueFormatter, |
9 | measurements: &MeasurementData<'_>, |
10 | size: Option<(u32, u32)>, |
11 | ) { |
12 | let data = &measurements.avg_times; |
13 | let max_avg_time = data.max(); |
14 | let mut scaled_y: Vec<_> = data.iter().map(|(f, _)| f).collect(); |
15 | let unit = formatter.scale_values(max_avg_time, &mut scaled_y); |
16 | let scaled_y = Sample::new(&scaled_y); |
17 | |
18 | let size = size.unwrap_or(SIZE); |
19 | let root_area = SVGBackend::new(path, size).into_drawing_area(); |
20 | |
21 | let mut cb = ChartBuilder::on(&root_area); |
22 | if let Some(title) = title { |
23 | cb.caption(title, (DEFAULT_FONT, 20)); |
24 | } |
25 | |
26 | let x_range = (1.0)..((data.len() + 1) as f64); |
27 | let y_range = plotters::data::fitting_range(scaled_y.iter()); |
28 | |
29 | let mut chart = cb |
30 | .margin((5).percent()) |
31 | .set_label_area_size(LabelAreaPosition::Left, (5).percent_width().min(60)) |
32 | .set_label_area_size(LabelAreaPosition::Bottom, (5).percent_height().min(40)) |
33 | .build_cartesian_2d(x_range, y_range) |
34 | .unwrap(); |
35 | |
36 | chart |
37 | .configure_mesh() |
38 | .y_desc(format!("Average Iteration Time ({})" , unit)) |
39 | .x_label_formatter(&|x| pretty_print_float(*x, true)) |
40 | .light_line_style(TRANSPARENT) |
41 | .draw() |
42 | .unwrap(); |
43 | |
44 | chart |
45 | .draw_series( |
46 | (1..=data.len()) |
47 | .zip(scaled_y.iter()) |
48 | .map(|(x, y)| Circle::new((x as f64, *y), POINT_SIZE, DARK_BLUE.filled())), |
49 | ) |
50 | .unwrap() |
51 | .label("Sample" ) |
52 | .legend(|(x, y)| Circle::new((x + 10, y), POINT_SIZE, DARK_BLUE.filled())); |
53 | |
54 | if title.is_some() { |
55 | chart |
56 | .configure_series_labels() |
57 | .position(SeriesLabelPosition::UpperLeft) |
58 | .draw() |
59 | .unwrap(); |
60 | } |
61 | } |
62 | |
63 | pub(crate) fn iteration_times_comparison_figure( |
64 | title: Option<&str>, |
65 | path: &Path, |
66 | formatter: &dyn ValueFormatter, |
67 | measurements: &MeasurementData<'_>, |
68 | comparison: &ComparisonData, |
69 | size: Option<(u32, u32)>, |
70 | ) { |
71 | let current_data = &measurements.avg_times; |
72 | let base_data = &comparison.base_avg_times; |
73 | |
74 | let mut all_data: Vec<f64> = current_data.iter().map(|(f, _)| f).collect(); |
75 | all_data.extend_from_slice(base_data); |
76 | |
77 | let typical_value = Sample::new(&all_data).max(); |
78 | let unit = formatter.scale_values(typical_value, &mut all_data); |
79 | |
80 | let (scaled_current_y, scaled_base_y) = all_data.split_at(current_data.len()); |
81 | let scaled_current_y = Sample::new(scaled_current_y); |
82 | let scaled_base_y = Sample::new(scaled_base_y); |
83 | |
84 | let size = size.unwrap_or(SIZE); |
85 | let root_area = SVGBackend::new(path, size).into_drawing_area(); |
86 | |
87 | let mut cb = ChartBuilder::on(&root_area); |
88 | if let Some(title) = title { |
89 | cb.caption(title, (DEFAULT_FONT, 20)); |
90 | } |
91 | |
92 | let max_samples = current_data.len().max(base_data.len()) as f64; |
93 | |
94 | let y_range = plotters::data::fitting_range(all_data.iter()); |
95 | |
96 | let mut chart = cb |
97 | .margin((5).percent()) |
98 | .set_label_area_size(LabelAreaPosition::Left, (5).percent_width().min(60)) |
99 | .set_label_area_size(LabelAreaPosition::Bottom, (5).percent_height().min(40)) |
100 | .build_cartesian_2d(0.0..max_samples, y_range) |
101 | .unwrap(); |
102 | |
103 | chart |
104 | .configure_mesh() |
105 | .y_desc(format!("Average Iteration Time ({})" , unit)) |
106 | .x_label_formatter(&|x| pretty_print_float(*x, true)) |
107 | .light_line_style(TRANSPARENT) |
108 | .draw() |
109 | .unwrap(); |
110 | |
111 | chart |
112 | .draw_series( |
113 | (1..=current_data.len()) |
114 | .zip(scaled_current_y.iter()) |
115 | .map(|(x, y)| Circle::new((x as f64, *y), POINT_SIZE, DARK_BLUE.filled())), |
116 | ) |
117 | .unwrap() |
118 | .label("Current" ) |
119 | .legend(|(x, y)| Circle::new((x + 10, y), POINT_SIZE, DARK_BLUE.filled())); |
120 | |
121 | chart |
122 | .draw_series( |
123 | (1..=base_data.len()) |
124 | .zip(scaled_base_y.iter()) |
125 | .map(|(x, y)| Circle::new((x as f64, *y), POINT_SIZE, DARK_RED.filled())), |
126 | ) |
127 | .unwrap() |
128 | .label("Base" ) |
129 | .legend(|(x, y)| Circle::new((x + 10, y), POINT_SIZE, DARK_RED.filled())); |
130 | |
131 | if title.is_some() { |
132 | chart |
133 | .configure_series_labels() |
134 | .position(SeriesLabelPosition::UpperLeft) |
135 | .draw() |
136 | .unwrap(); |
137 | } |
138 | } |
139 | |