use plotters::prelude::*;
use plotters_statistical::style::palette_color;
use plotters_statistical::RocCurve;
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 {
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(())
}