use kuva::backend::svg::SvgBackend;
use kuva::plot::scatter::ScatterPlot;
use kuva::plot::LinePlot;
use kuva::render::annotations::{ReferenceLine, ShadedRegion, TextAnnotation};
use kuva::render::layout::Layout;
use kuva::render::plots::Plot;
use kuva::render::render::render_multiple;
use kuva::TickFormat;
const OUT: &str = "docs/src/assets/layout";
fn main() {
std::fs::create_dir_all(OUT).expect("could not create docs/src/assets/layout");
log_scale();
tick_formats();
tick_controls();
annotations();
text_annotation();
reference_line();
shaded_region();
println!("Layout SVGs written to {OUT}/");
}
fn log_scale() {
let data: Vec<(f64, f64)> = vec![
(1.0, 0.001),
(3.0, 0.02),
(10.0, 0.5),
(30.0, 8.0),
(100.0, 150.0),
(300.0, 3_000.0),
(1000.0, 60_000.0),
];
let scatter = ScatterPlot::new()
.with_data(data)
.with_color("steelblue")
.with_size(5.0);
let plots = vec![Plot::Scatter(scatter)];
let layout = Layout::auto_from_plots(&plots)
.with_log_scale()
.with_title("Log-Scale Axes")
.with_x_label("X (log₁₀)")
.with_y_label("Y (log₁₀)");
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/log_scale.svg"), svg).unwrap();
}
fn tick_formats() {
let data_linear = vec![
(0.0_f64, 0.0_f64),
(0.25, 0.25),
(0.5, 0.5),
(0.75, 0.75),
(1.0, 1.0),
];
let data_large = vec![
(0.0_f64, 0.0_f64),
(25_000.0, 50_000.0),
(50_000.0, 100_000.0),
];
{
let plot = ScatterPlot::new()
.with_data(data_linear.clone())
.with_color("steelblue")
.with_size(5.0);
let plots = vec![Plot::Scatter(plot)];
let layout = Layout::auto_from_plots(&plots).with_title("Auto");
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/tick_auto.svg"), svg).unwrap();
}
{
let plot = ScatterPlot::new()
.with_data(data_linear.clone())
.with_color("steelblue")
.with_size(5.0);
let plots = vec![Plot::Scatter(plot)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Fixed(2)")
.with_tick_format(TickFormat::Fixed(2));
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/tick_fixed.svg"), svg).unwrap();
}
{
let plot = ScatterPlot::new()
.with_data(data_linear.clone())
.with_color("steelblue")
.with_size(5.0);
let plots = vec![Plot::Scatter(plot)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Percent")
.with_tick_format(TickFormat::Percent);
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/tick_percent.svg"), svg).unwrap();
}
{
let plot = ScatterPlot::new()
.with_data(data_large.clone())
.with_color("steelblue")
.with_size(5.0);
let plots = vec![Plot::Scatter(plot)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Sci")
.with_tick_format(TickFormat::Sci);
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/tick_sci.svg"), svg).unwrap();
}
}
fn tick_controls() {
let data: Vec<(f64, f64)> = (0..=10)
.map(|i| (i as f64, (i as f64 * 0.6).sin() * 3.0 + 4.0))
.collect();
let save = |name: &str, title: &str, axis_w: f64, tick_w: f64, tick_len: f64, grid_w: f64| {
let plot = ScatterPlot::new()
.with_data(data.clone())
.with_color("steelblue")
.with_size(4.0);
let plots = vec![Plot::Scatter(plot)];
let layout = Layout::auto_from_plots(&plots)
.with_title(title)
.with_width(280.0)
.with_height(220.0)
.with_axis_line_width(axis_w)
.with_tick_width(tick_w)
.with_tick_length(tick_len)
.with_grid_line_width(grid_w);
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/{name}.svg"), svg).unwrap();
};
save("tick_controls_default", "Defaults", 1.0, 1.0, 5.0, 1.0);
save(
"tick_controls_heavy",
"Heavy / long ticks",
2.0,
1.5,
10.0,
0.5,
);
}
fn text_annotation() {
let data = vec![
(1.0_f64, 1.2_f64),
(1.8, 2.5),
(2.4, 1.9),
(3.1, 3.4),
(3.8, 2.8),
(4.5, 4.1),
(5.2, 3.9),
(6.0, 9.0),
];
let plot = ScatterPlot::new()
.with_data(data)
.with_color("steelblue")
.with_size(5.0);
let plots = vec![Plot::Scatter(plot)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Text Annotation")
.with_x_label("X")
.with_y_label("Y")
.with_annotation(
TextAnnotation::new("Outlier", 5.0, 7.5)
.with_arrow(6.0, 9.0)
.with_color("crimson")
.with_font_size(12),
);
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/text_annotation.svg"), svg).unwrap();
}
fn reference_line() {
let data = vec![
(0.5_f64, 0.28_f64),
(1.2, 0.14),
(1.8, 0.04),
(2.4, 0.19),
(2.9, 0.08),
(3.8, 0.21),
(4.5, 0.12),
(5.1, 0.07),
(5.8, 0.25),
(6.5, 0.09),
];
let plot = ScatterPlot::new()
.with_data(data)
.with_color("steelblue")
.with_size(5.0);
let plots = vec![Plot::Scatter(plot)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Reference Lines")
.with_x_label("X")
.with_y_label("p-value")
.with_reference_line(
ReferenceLine::horizontal(0.05)
.with_color("crimson")
.with_label("p = 0.05"),
)
.with_reference_line(
ReferenceLine::vertical(3.5)
.with_color("steelblue")
.with_label("cutoff")
.with_stroke_width(1.5)
.with_dasharray("8 4"),
);
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/reference_line.svg"), svg).unwrap();
}
fn shaded_region() {
let data = vec![
(2.0_f64, 1.0_f64),
(5.0, 3.2),
(8.0, 0.8),
(12.0, 5.5),
(15.0, 2.1),
(18.0, 6.3),
(22.0, 3.8),
(25.0, 1.5),
(28.0, 4.7),
];
let plot = ScatterPlot::new()
.with_data(data)
.with_color("steelblue")
.with_size(5.0);
let plots = vec![Plot::Scatter(plot)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Shaded Regions")
.with_x_label("X")
.with_y_label("Y")
.with_shaded_region(
ShadedRegion::horizontal(2.0, 4.0)
.with_color("gold")
.with_opacity(0.2),
)
.with_shaded_region(
ShadedRegion::vertical(10.0, 20.0)
.with_color("steelblue")
.with_opacity(0.15),
);
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/shaded_region.svg"), svg).unwrap();
}
fn annotations() {
let xs: Vec<f64> = (0..=60).map(|i| i as f64 * 0.1).collect();
let line = LinePlot::new()
.with_data(xs.iter().map(|&x| (x, x.sin())))
.with_color("steelblue")
.with_stroke_width(2.0);
let plots = vec![Plot::Line(line)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Annotations")
.with_x_label("X")
.with_y_label("Y")
.with_shaded_region(
ShadedRegion::horizontal(0.0, 1.1)
.with_color("steelblue")
.with_opacity(0.08),
)
.with_reference_line(
ReferenceLine::horizontal(0.0)
.with_color("black")
.with_label("y = 0"),
)
.with_reference_line(
ReferenceLine::vertical(1.57)
.with_color("crimson")
.with_label("π/2"),
)
.with_annotation(
TextAnnotation::new("peak", 1.0, 1.15)
.with_arrow(1.57, 1.0)
.with_color("crimson"),
);
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write(format!("{OUT}/annotations.svg"), svg).unwrap();
}