use kuva::backend::svg::SvgBackend;
use kuva::plot::{ColorMap, Heatmap};
use kuva::render::layout::Layout;
use kuva::render::plots::Plot;
use kuva::render::render::render_multiple;
const OUT: &str = "docs/src/assets/heatmap";
fn main() {
std::fs::create_dir_all(OUT).expect("could not create docs/src/assets/heatmap");
basic();
labeled();
values();
colormaps();
scalar_field();
println!("Heatmap SVGs written to {OUT}/");
}
fn basic() {
let data = vec![
vec![0.8, 0.3, 0.9, 0.2, 0.6],
vec![0.4, 0.7, 0.1, 0.8, 0.3],
vec![0.5, 0.9, 0.4, 0.6, 0.1],
vec![0.2, 0.5, 0.8, 0.3, 0.7],
];
let heatmap = Heatmap::new().with_data(data);
let plots = vec![Plot::Heatmap(heatmap)];
let layout = Layout::auto_from_plots(&plots).with_title("Heatmap");
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/basic.svg"), svg).unwrap();
}
fn labeled() {
let data = vec![
vec![2.1, 0.4, 3.2, 1.1, 2.8],
vec![0.9, 3.5, 0.3, 2.7, 1.2],
vec![1.8, 2.9, 1.5, 0.6, 3.1],
vec![3.3, 1.1, 2.0, 3.8, 0.5],
];
let row_labels = ["GeneA", "GeneB", "GeneC", "GeneD"]
.map(String::from)
.to_vec();
let col_labels = ["Ctrl", "T1", "T2", "T3", "T4"].map(String::from).to_vec();
let heatmap = Heatmap::new().with_data(data);
let plots = vec![Plot::Heatmap(heatmap)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Gene Expression Heatmap")
.with_x_categories(col_labels)
.with_y_categories(row_labels);
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/labeled.svg"), svg).unwrap();
}
fn values() {
let data = vec![
vec![10.0, 20.0, 30.0, 15.0],
vec![45.0, 55.0, 25.0, 60.0],
vec![70.0, 35.0, 80.0, 40.0],
vec![50.0, 90.0, 65.0, 20.0],
];
let heatmap = Heatmap::new().with_data(data).with_values();
let plots = vec![Plot::Heatmap(heatmap)];
let layout = Layout::auto_from_plots(&plots).with_title("Value Overlay");
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/values.svg"), svg).unwrap();
}
fn scalar_field() {
use std::f64::consts::PI;
let rows = 16usize;
let cols = 40usize;
let data: Vec<Vec<f64>> = (0..rows)
.map(|i| {
let y = 4.0 - (i as f64 + 0.5) * 8.0 / rows as f64;
(0..cols)
.map(|j| {
let x = -10.0 + (j as f64 + 0.5) * 20.0 / cols as f64;
let r2 = x * x / 16.0 + y * y / 4.0;
((-r2 / 2.0).exp() + 0.3 * (x * PI / 5.0).sin()).clamp(0.0, 1.0)
})
.collect()
})
.collect();
let hm = Heatmap::new()
.with_data(data)
.with_color_map(ColorMap::Inferno)
.with_x_range(-10.0, 10.0)
.with_y_range(-4.0, 4.0)
.with_cell_size(1.0);
let plots = vec![Plot::Heatmap(hm)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Temperature Field")
.with_x_label("x (m)")
.with_y_label("y (m)")
.with_legend_entries(vec![]);
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/scalar_field.svg"), svg).unwrap();
}
fn colormaps() {
let data = vec![
vec![10.0, 20.0, 30.0, 40.0],
vec![50.0, 60.0, 70.0, 80.0],
vec![90.0, 75.0, 55.0, 35.0],
vec![15.0, 40.0, 65.0, 85.0],
];
for (cmap, name, title) in [
(ColorMap::Viridis, "viridis", "Viridis"),
(ColorMap::Inferno, "inferno", "Inferno"),
(ColorMap::Grayscale, "greyscale", "Greyscale"),
] {
let heatmap = Heatmap::new().with_data(data.clone()).with_color_map(cmap);
let plots = vec![Plot::Heatmap(heatmap)];
let layout = Layout::auto_from_plots(&plots).with_title(title);
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/colormap_{name}.svg"), svg).unwrap();
}
}