plotters-statistical 0.2.0

Statistical chart primitives (box, violin, ROC, PR, regularization-path, residual) as native plotters series
Documentation
//! Multi-model precision–recall comparison rendered to
//! `precision_recall_curve.svg`, with each curve labeled by its average
//! precision and the first model showing the prevalence baseline.

use plotters::prelude::*;
use plotters_statistical::style::palette_color;
use plotters_statistical::PrecisionRecallCurve;

fn noise(i: usize) -> f64 {
    ((i as f64 * 12.9898).sin() * 43758.5453).rem_euclid(1.0)
}

fn dataset(sep: f64) -> (Vec<f64>, Vec<bool>) {
    let n = 200;
    let mut scores = Vec::with_capacity(n);
    let mut labels = Vec::with_capacity(n);
    for i in 0..n {
        // ~30% positive prevalence so the baseline sits visibly below 0.5.
        let pos = i % 10 < 3;
        let base = if pos { sep } else { 0.0 };
        scores.push(base + noise(i));
        labels.push(pos);
    }
    (scores, labels)
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let root = SVGBackend::new("precision_recall_curve.svg", (640, 600)).into_drawing_area();
    root.fill(&WHITE)?;

    let mut chart = ChartBuilder::on(&root)
        .caption("Precision–recall comparison", ("sans-serif", 24))
        .margin(20)
        .set_label_area_size(LabelAreaPosition::Left, 50)
        .set_label_area_size(LabelAreaPosition::Bottom, 45)
        .build_cartesian_2d(0f64..1f64, 0f64..1.05f64)?;

    chart
        .configure_mesh()
        .x_desc("Recall")
        .y_desc("Precision")
        .draw()?;

    let models = [("Strong model", 0.9), ("Weak model", 0.35)];
    for (i, (name, sep)) in models.iter().enumerate() {
        let (scores, labels) = dataset(*sep);
        let mut curve = PrecisionRecallCurve::from_scores(&scores, &labels)?
            .color(palette_color(i))
            .stroke_width(2);
        if i == 0 {
            curve = curve.with_baseline().shade_area(true);
        }
        let label = curve.legend_label(name);
        chart
            .draw_series(std::iter::once(curve))?
            .label(label)
            .legend(move |(x, y)| PathElement::new(vec![(x, y), (x + 18, y)], palette_color(i)));
    }

    chart
        .configure_series_labels()
        .position(SeriesLabelPosition::LowerLeft)
        .border_style(BLACK)
        .background_style(WHITE.mix(0.85))
        .draw()?;

    root.present()?;
    println!("wrote precision_recall_curve.svg");
    Ok(())
}