Box Plot

A box plot (box-and-whisker plot) displays the five-number summary of one or more groups of values. Boxes show the interquartile range (Q1–Q3) with a median line; whiskers extend to the most extreme values within 1.5×IQR of the box edges (Tukey style). Individual data points can optionally be overlaid as a jittered strip or beeswarm.

Import path: kuva::plot::BoxPlot


Basic usage

Add one group per category with .with_group(label, values). Groups are rendered left-to-right in the order they are added.

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

let plot = BoxPlot::new()
    .with_group("Control",     vec![4.1, 5.0, 5.3, 5.8, 6.2, 7.0, 5.5, 4.8])
    .with_group("Treatment A", vec![5.5, 6.1, 6.4, 7.2, 7.8, 8.5, 6.9, 7.0])
    .with_group("Treatment B", vec![3.2, 4.0, 4.5, 4.8, 5.1, 5.9, 4.3, 4.7])
    .with_group("Treatment C", vec![6.0, 7.2, 7.5, 8.1, 8.8, 9.5, 7.9, 8.2])
    .with_color("steelblue");

let plots = vec![Plot::Box(plot)];
let layout = Layout::auto_from_plots(&plots)
    .with_title("Box Plot")
    .with_y_label("Value");

let scene = render_multiple(plots, layout);
let svg = SvgBackend.render_scene(&scene);
std::fs::write("boxplot.svg", svg).unwrap();
}
Basic box plot

What the box shows

ElementMeaning
Bottom of boxQ1 — 25th percentile
Line in boxQ2 — median (50th percentile)
Top of boxQ3 — 75th percentile
Lower whiskerSmallest value ≥ Q1 − 1.5×IQR
Upper whiskerLargest value ≤ Q3 + 1.5×IQR

Values outside the whisker range are not drawn automatically — use an overlay to show them.


Point overlays

Overlaying the raw data on top of each box makes the sample size and distribution shape immediately visible. Both modes accept an optional color and point size.

Jittered strip

.with_strip(jitter) scatters points randomly within a horizontal band. The jitter argument controls the spread width (in data-axis units; 0.2 is a reasonable starting value).

#![allow(unused)]
fn main() {
use kuva::plot::BoxPlot;
use kuva::render::plots::Plot;

let plot = BoxPlot::new()
    .with_group("Control",     vec![/* values */])
    .with_group("Treatment A", vec![/* values */])
    .with_color("steelblue")
    .with_strip(0.2)
    .with_overlay_color("rgba(0,0,0,0.4)")
    .with_overlay_size(3.0);
}
Box plot with strip overlay

Beeswarm

.with_swarm_overlay() uses a beeswarm algorithm to spread points horizontally to avoid overlap. This gives a clearer picture of data density and is particularly useful for smaller datasets (roughly N < 200 per group).

#![allow(unused)]
fn main() {
use kuva::plot::BoxPlot;
use kuva::render::plots::Plot;

let plot = BoxPlot::new()
    .with_group("Control",     vec![/* values */])
    .with_group("Treatment A", vec![/* values */])
    .with_color("steelblue")
    .with_swarm_overlay()
    .with_overlay_color("rgba(0,0,0,0.4)")
    .with_overlay_size(3.0);
}
Box plot with swarm overlay

A semi-transparent overlay_color is recommended so the box remains visible beneath the points.


Per-group colors

Color each group independently within a single BoxPlot using .with_group_colors(). Colors are matched to groups by position — the first color applies to the first group added, and so on. The uniform .with_color() value is used as a fallback for any group without an entry. All elements of a group (box, whiskers, caps) share the same color.

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

let plot = BoxPlot::new()
    .with_group("Control",     samples(5.0, 1.0, 60, 1))
    .with_group("Treatment A", samples(6.5, 1.2, 60, 2))
    .with_group("Treatment B", samples(4.2, 0.9, 60, 3))
    .with_group("Treatment C", samples(7.1, 1.5, 60, 4))
    .with_group_colors(["steelblue", "tomato", "seagreen", "goldenrod"]);

let plots = vec![Plot::Box(plot)];
let layout = Layout::auto_from_plots(&plots)
    .with_title("Box Plot — Per-group Colors")
    .with_y_label("Value");

let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
}
Box plot with per-group colors

A partial list is also valid — groups beyond the list length fall back to the uniform .with_color() value:

#![allow(unused)]
fn main() {
use kuva::plot::BoxPlot;
let plot = BoxPlot::new()
    .with_group("Control",     vec![/* values */])
    .with_group("Treatment A", vec![/* values */])
    .with_group("Treatment B", vec![/* values */])
    .with_color("steelblue")          // fallback for groups 1 and 2
    .with_group_colors(["tomato"]);   // only group 0 gets this color
}

Legend note: the legend entry uses the uniform .with_color() value. For a fully labeled per-group legend, create one BoxPlot per group and attach .with_legend() to each, then use a Layout::with_palette() to auto-assign colors.


Horizontal mode

.with_horizontal(true) rotates the chart so categories appear on the Y-axis and values on the X-axis.

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

let plot = BoxPlot::new()
    .with_group("Control",     vec![4.1, 5.0, 5.3, 5.8, 6.2, 7.0])
    .with_group("Treatment A", vec![5.5, 6.1, 6.4, 7.2, 7.8, 8.5])
    .with_group("Treatment B", vec![3.2, 4.0, 4.5, 4.8, 5.1, 5.9])
    .with_group("Treatment C", vec![6.0, 7.2, 7.5, 8.1, 8.8, 9.5])
    .with_group_colors(["steelblue", "tomato", "seagreen", "goldenrod"])
    .with_horizontal(true);

let plots = vec![Plot::Box(plot)];
let layout = Layout::auto_from_plots(&plots)
    .with_title("Horizontal Box Plot")
    .with_x_label("Value");

let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
}
Horizontal box plot

API reference

MethodDescription
BoxPlot::new()Create a box plot with defaults
.with_group(label, values)Add a group; accepts any Into<f64> iterable
.with_color(s)Box fill color (CSS color string)
.with_group_colors(iter)Per-group fill colors; falls back to .with_color for out-of-range indices
.with_width(f)Box width as a fraction of the category slot (default 0.8)
.with_legend(s)Attach a legend label
.with_strip(jitter)Overlay jittered strip points; jitter is horizontal spread width
.with_swarm_overlay()Overlay beeswarm points (spread to avoid overlap)
.with_overlay_color(s)Color for overlay points (default "rgba(0,0,0,0.45)")
.with_overlay_size(r)Radius of overlay points in pixels (default 3.0)
.with_horizontal(bool)Rotate chart: categories on Y-axis, values on X-axis (default false)

See also: Violin Plot for the full density shape, Raincloud Plot for box + density + points combined, Strip Plot for the raw points alone.


CLI

Box-and-whisker plot. Groups are taken from one column; values from another.

Input: two columns — group label and numeric value, one observation per row.

FlagDefaultDescription
--group-col <COL>0Group label column
--value-col <COL>1Numeric value column
--y <COL>[,<COL>…]Comma-separated columns; each column becomes a separate group (column name = group label). Overrides --group-col + --value-col when 2+ columns given
--color <CSS>steelblueBox fill color (uniform, all groups)
--group-colors <CSS,...>Per-group colors, comma-separated; falls back to --color for unlisted groups
--overlay-pointsoffOverlay individual points as a jittered strip
--overlay-swarmoffOverlay individual points as a non-overlapping beeswarm
--horizontaloffRender groups on the Y-axis, values on the X-axis
kuva box samples.tsv --group-col group --value-col expression

kuva box samples.tsv --group-col group --value-col expression \
    --overlay-swarm --color "rgba(70,130,180,0.6)"

kuva box samples.tsv --group-col group --value-col expression \
    --group-colors "steelblue,tomato,seagreen,goldenrod,mediumpurple"

# multi-column: each numeric column is a group
kuva box data.tsv --y col_a,col_b,col_c

# horizontal layout
kuva box samples.tsv --group-col group --value-col expression --horizontal

See also: Shared flags — output, appearance, axes, log scale.