| 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 | |