Bump Chart

A bump chart shows how the rank of each series changes across discrete time points or conditions. Lines connect consecutive ranks; the best rank (1) appears at the top.

Basic usage (pre-ranked)

#![allow(unused)]
fn main() {
use kuva::plot::bump::BumpPlot;
use kuva::render::{plots::Plot, layout::Layout, render::render_multiple};
use kuva::backend::svg::SvgBackend;

let plot = BumpPlot::new()
    .with_series("Alpha", vec![1, 3, 2, 1])
    .with_series("Beta",  vec![2, 1, 1, 3])
    .with_series("Gamma", vec![3, 2, 3, 2])
    .with_x_labels(["2021", "2022", "2023", "2024"]);

let plots = vec![Plot::Bump(plot)];
let layout = Layout::auto_from_plots(&plots).with_title("Rank over time");
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write("bump.svg", svg).unwrap();
}

Auto-ranking from raw values

Instead of supplying pre-computed ranks you can provide raw values; kuva ranks them per time point automatically.

#![allow(unused)]
fn main() {
use kuva::plot::bump::BumpPlot;

let plot = BumpPlot::new()
    .with_raw_series("A", vec![95.0, 80.0, 88.0])
    .with_raw_series("B", vec![80.0, 95.0, 72.0])
    .with_raw_series("C", vec![70.0, 85.0, 95.0])
    .with_x_labels(["Q1", "Q2", "Q3"]);
}

By default, higher value = rank 1 (better). Pass .with_rank_ascending(true) to flip this so lower value = rank 1.

Builder reference

MethodDefaultDescription
.with_series(name, ranks)Add a pre-ranked series (integer or float ranks).
.with_ranked_series(name, ranks)Pre-ranked series that allows None gaps.
.with_raw_series(name, values)Raw values; ranks computed automatically.
.with_raw_series_opt(name, values)Raw values with optional gaps (None breaks the line).
.with_x_labels(labels)Labels for each time point / condition on the x-axis.
.with_curve_style(style)SigmoidLine style between rank points: Sigmoid or Straight.
.with_show_rank_labels(bool)falseDraw the rank number inside each dot.
.with_show_series_labels(bool)trueDraw series name labels at the left and right edges.
.with_dot_radius(f64)6.0Dot radius in pixels.
.with_stroke_width(f64)2.5Line stroke width in pixels.
.with_highlight(name)NoneHighlight one series; all others are muted to 20 % opacity.
.with_legend(bool)trueShow / hide the legend.
.with_rank_ascending(bool)falseIf true, lower raw value → better (lower) rank number.
.with_tie_break(mode)AverageTie-breaking for auto-ranking: Average, Min, Max, Stable.

Highlight mode

Highlighting one series draws it with a thicker stroke and bolder endpoint labels; all others are rendered at reduced opacity and with muted grey labels.

#![allow(unused)]
fn main() {
let plot = BumpPlot::new()
    .with_series("Alpha", vec![1, 3, 2, 1])
    .with_series("Beta",  vec![2, 1, 1, 3])
    .with_series("Gamma", vec![3, 2, 3, 2])
    .with_highlight("Alpha");
}

Missing time points

Supply None entries via .with_ranked_series or .with_raw_series_opt to produce line breaks at absent time points:

#![allow(unused)]
fn main() {
let plot = BumpPlot::new()
    .with_ranked_series("Alpha", vec![Some(1.0), None, Some(2.0), Some(1.0)])
    .with_x_labels(["A", "B", "C", "D"]);
}

Tie-breaking modes

ModeBehavior
Average (default)Tied series share the average of the occupied rank positions (e.g. 2.5, 2.5).
MinAll tied series receive the best (minimum) rank number.
MaxAll tied series receive the worst (maximum) rank number.
StableTied series retain their insertion order.