use plotters::prelude::*;
use plotters_statistical::ResidualPlot;
fn noise(i: usize) -> f64 {
(((i as f64 * 78.233).sin() * 43758.5453).rem_euclid(1.0)) * 2.0 - 1.0
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let root = SVGBackend::new("residual_plot.svg", (760, 520)).into_drawing_area();
root.fill(&WHITE)?;
let n = 220;
let mut fitted = Vec::with_capacity(n);
let mut residuals = Vec::with_capacity(n);
for i in 0..n {
let x = 10.0 * i as f64 / (n as f64 - 1.0);
let r = 0.45 * (x - 5.0) + noise(i) * (0.6 + 0.35 * x);
fitted.push(x);
residuals.push(r);
}
let mut chart = ChartBuilder::on(&root)
.caption("Residual plot (structured residuals)", ("sans-serif", 22))
.margin(20)
.set_label_area_size(LabelAreaPosition::Left, 50)
.set_label_area_size(LabelAreaPosition::Bottom, 45)
.build_cartesian_2d(0f64..10f64, -8f64..8f64)?;
chart
.configure_mesh()
.x_desc("fitted value")
.y_desc("residual")
.draw()?;
chart.draw_series(std::iter::once(
ResidualPlot::from_residuals(&fitted, &residuals)?.trend(true),
))?;
root.present()?;
println!("wrote residual_plot.svg");
Ok(())
}