use plotters::prelude::*;
use plotters_statistical::RegularizationPath;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let root = SVGBackend::new("regularization_path.svg", (760, 520)).into_drawing_area();
root.fill(&WHITE)?;
let n = 30;
let strengths: Vec<f64> = (0..n)
.map(|i| {
let t = i as f64 / (n as f64 - 1.0);
10f64.powf(-3.0 + 4.0 * t)
})
.collect();
let specs = [
("x1", 3.0f64, 3.0f64),
("x2", -2.0, 0.3),
("x3", 1.5, 1.0),
("x4", 2.5, 0.05),
];
let coefficients: Vec<Vec<f64>> = strengths
.iter()
.map(|&s| {
specs
.iter()
.map(|&(_, base, thr)| base * (1.0 - s / thr).max(0.0))
.collect()
})
.collect();
let mut chart = ChartBuilder::on(&root)
.caption("Regularization path (L1)", ("sans-serif", 24))
.margin(20)
.set_label_area_size(LabelAreaPosition::Left, 50)
.set_label_area_size(LabelAreaPosition::Bottom, 45)
.build_cartesian_2d((1e-3f64..1e1f64).log_scale(), -2.5f64..3.5f64)?;
chart
.configure_mesh()
.x_desc("regularization strength (log)")
.y_desc("coefficient")
.draw()?;
let path = RegularizationPath::new(&strengths, &coefficients)?
.feature_names(specs.iter().map(|s| s.0))
.stroke_width(2);
for line in path.lines() {
let color = line.color();
let name = line.name().unwrap_or_default().to_string();
chart
.draw_series(std::iter::once(line))?
.label(name)
.legend(move |(x, y)| PathElement::new(vec![(x, y), (x + 18, y)], color));
}
chart
.configure_series_labels()
.position(SeriesLabelPosition::UpperRight)
.border_style(BLACK)
.background_style(WHITE.mix(0.85))
.draw()?;
root.present()?;
println!("wrote regularization_path.svg");
Ok(())
}