(
root: &DrawingArea<DB, plotters::coord::Shift>,
layout: &LayoutIR,
traces: &[TraceIR],
unsupported: &mut Vec<String>,
)
| 88 | } |
| 89 | |
| 90 | pub(super) fn render_boxplot<DB: DrawingBackend>( |
| 91 | root: &DrawingArea<DB, plotters::coord::Shift>, |
| 92 | layout: &LayoutIR, |
| 93 | traces: &[TraceIR], |
| 94 | unsupported: &mut Vec<String>, |
| 95 | ) { |
| 96 | let config = extract_layout_config(layout, unsupported); |
| 97 | let horiz = is_horizontal(traces); |
| 98 | |
| 99 | // Collect unique category labels across all traces |
| 100 | let mut categories: Vec<String> = Vec::new(); |
| 101 | for trace in traces { |
| 102 | if let TraceIR::BoxPlot(ir) = trace { |
| 103 | for label in extract_strings(&ir.labels) { |
| 104 | if !categories.contains(&label) { |
| 105 | categories.push(label); |
| 106 | } |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | let n_cats = categories.len(); |
| 111 | let n_groups = traces |
| 112 | .iter() |
| 113 | .filter(|t| matches!(t, TraceIR::BoxPlot(_))) |
| 114 | .count(); |
| 115 | |
| 116 | // Compute value range from all box data |
| 117 | let mut v_min = f64::INFINITY; |
| 118 | let mut v_max = f64::NEG_INFINITY; |
| 119 | for trace in traces { |
| 120 | if let TraceIR::BoxPlot(ir) = trace { |
| 121 | for v in extract_f64(&ir.values) { |
| 122 | v_min = v_min.min(v); |
| 123 | v_max = v_max.max(v); |
| 124 | } |
| 125 | } |
| 126 | } |
| 127 | let v_margin = (v_max - v_min).abs() * 0.05; |
| 128 | v_min -= v_margin.max(0.01); |
| 129 | v_max += v_margin.max(0.01); |
| 130 | |
| 131 | // Apply user-specified ranges |
| 132 | if horiz { |
| 133 | if let Some((lo, hi)) = config.x_range { |
| 134 | v_min = lo; |
| 135 | v_max = hi; |
| 136 | } |
| 137 | } else if let Some((lo, hi)) = config.y_range { |
| 138 | v_min = lo; |
| 139 | v_max = hi; |
| 140 | } |
| 141 | |
| 142 | let cat_range = -0.5..(n_cats as f64 - 0.5); |
| 143 | |
| 144 | let (w, h) = resolve_dimensions(layout); |
| 145 | draw_plot_title(root, &config, w, h); |
| 146 | |
| 147 | let mut builder = ChartBuilder::on(root); |
no test coverage detected