use rand::SeedableRng;
use rand_distr::{Distribution, Normal};
use kuva::plot::Histogram2D;
use kuva::plot::histogram2d::ColorMap;
use kuva::backend::svg::SvgBackend;
use kuva::render::render::render_multiple;
use kuva::render::layout::Layout;
use kuva::render::plots::Plot;
const OUT: &str = "docs/src/assets/histogram2d";
fn bivariate(n: usize, mx: f64, my: f64, sx: f64, sy: f64, seed: u64) -> Vec<(f64, f64)> {
let mut rng = rand::rngs::SmallRng::seed_from_u64(seed);
let dx = Normal::new(mx, sx).unwrap();
let dy = Normal::new(my, sy).unwrap();
(0..n).map(|_| (dx.sample(&mut rng), dy.sample(&mut rng))).collect()
}
fn correlated(n: usize, mx: f64, my: f64, sx: f64, sy: f64, rho: f64, seed: u64) -> Vec<(f64, f64)> {
let mut rng = rand::rngs::SmallRng::seed_from_u64(seed);
let std = Normal::new(0.0_f64, 1.0).unwrap();
let k = (1.0 - rho * rho).sqrt();
(0..n).map(|_| {
let z1 = std.sample(&mut rng);
let z2 = std.sample(&mut rng);
let x = mx + sx * z1;
let y = my + sy * (rho * z1 + k * z2);
(x, y)
}).collect()
}
fn main() {
std::fs::create_dir_all(OUT).expect("could not create docs/src/assets/histogram2d");
basic();
correlation();
bimodal();
bin_resolution();
println!("Histogram2D SVGs written to {OUT}/");
}
fn basic() {
let data = bivariate(5_000, 15.0, 15.0, 3.0, 3.0, 1);
let hist = Histogram2D::new()
.with_data(data, (0.0, 30.0), (0.0, 30.0), 30, 30);
let plots = vec![Plot::Histogram2d(hist)];
let layout = Layout::auto_from_plots(&plots)
.with_title("2D Histogram — Viridis")
.with_x_label("X")
.with_y_label("Y");
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/basic.svg"), svg).unwrap();
}
fn correlation() {
let data = correlated(4_000, 10.0, 10.0, 2.0, 2.0, 0.85, 2);
let hist = Histogram2D::new()
.with_data(data, (0.0, 20.0), (0.0, 20.0), 25, 25)
.with_correlation();
let plots = vec![Plot::Histogram2d(hist)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Correlated Variables (r ≈ 0.85)")
.with_x_label("X")
.with_y_label("Y");
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/correlation.svg"), svg).unwrap();
}
fn bimodal() {
let mut data = bivariate(3_000, 9.0, 9.0, 2.0, 2.0, 3);
data.extend(bivariate(3_000, 21.0, 21.0, 2.0, 2.0, 4));
let hist = Histogram2D::new()
.with_data(data, (0.0, 30.0), (0.0, 30.0), 30, 30)
.with_color_map(ColorMap::Inferno);
let plots = vec![Plot::Histogram2d(hist)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Bimodal — Inferno")
.with_x_label("X")
.with_y_label("Y");
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/bimodal.svg"), svg).unwrap();
}
fn bin_resolution() {
let data = bivariate(8_000, 15.0, 15.0, 3.5, 3.5, 5);
let configs: &[(usize, &str, ColorMap, &str)] = &[
(10, "coarse", ColorMap::Grayscale, "Grayscale — 10×10 bins"),
(50, "fine", ColorMap::Viridis, "Viridis — 50×50 bins"),
];
for &(bins, name, ref cmap, title) in configs {
let hist = Histogram2D::new()
.with_data(data.clone(), (0.0, 30.0), (0.0, 30.0), bins, bins)
.with_color_map(cmap.clone());
let plots = vec![Plot::Histogram2d(hist)];
let layout = Layout::auto_from_plots(&plots)
.with_title(title)
.with_x_label("X")
.with_y_label("Y");
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/bins_{name}.svg"), svg).unwrap();
}
}