plotters-statistical 0.2.0

Statistical chart primitives (box, violin, ROC, PR, regularization-path, residual) as native plotters series
Documentation
//! Multi-model ROC comparison rendered to `roc_curve.svg`.
//!
//! Each curve is labeled with its AUC in the legend; the first model also shows
//! the AUC shading and the random-chance diagonal.

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

/// Deterministic pseudo-random value in `[0, 1)`.
fn noise(i: usize) -> f64 {
    ((i as f64 * 12.9898).sin() * 43758.5453).rem_euclid(1.0)
}

/// A synthetic binary-classification dataset whose positive class is shifted by
/// `sep` — larger `sep` means a more separable (higher-AUC) model.
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 {
        let pos = i % 2 == 0;
        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("roc_curve.svg", (640, 600)).into_drawing_area();
    root.fill(&WHITE)?;

    let mut chart = ChartBuilder::on(&root)
        .caption("ROC 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..1f64)?;

    chart
        .configure_mesh()
        .x_desc("False positive rate")
        .y_desc("True positive rate")
        .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 = RocCurve::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::LowerRight)
        .border_style(BLACK)
        .background_style(WHITE.mix(0.85))
        .draw()?;

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