Error bars overlay
Show measurement uncertainty alongside a central tendency — confidence intervals on a bar chart, standard errors on a scatter, fixed-value error bars on a measurement series. Lifts a chart from "looks confident" to "is honest about uncertainty".
The demo plots Robert Millikan's published electron-charge values from the oil-drop experiment, 1909 → 1913, with the uncertainty bands he reported each year. Millikan's 1913 figure of 4.774 × 10⁻¹⁰ statcoulomb won him the 1923 Nobel and held as the canonical value until later re-analyses. The visible year-to-year drift — bars that don't overlap one another's intervals as you'd expect them to — is the cautionary tale Richard Feynman cited in Cargo Cult Science: error bars don't include systematic bias.
Source: Oil drop experiment — Wikipedia
Public surface
use wisp_chart::overlay::{ErrorBars, ErrorPoint, ErrorKind};
use wisp_chart::plot::{self, Mark, Plot, ScaleKind};
use wisp::math::Rect;
// 1. Render the primary chart (Bar, Point, Line — anything cartesian).
let bar = Plot::new(rows)
.mark(Mark::Bar { value_labels: false })
.encode(plot::x("quarter", ScaleKind::Band))
.encode(plot::y("revenue", ScaleKind::Linear));
let bar_g = bar.render(&theme, viewport);
let _ = stage.add_child(root, bar_g);
// 2. Build the error-bars overlay with one entry per primary mark.
// `x_fraction` is the position along the plot's x extent (0..1).
let bars = ErrorBars::new(
vec![
ErrorPoint::symmetric(0.125, 38.0, 5.0),
ErrorPoint::symmetric(0.375, 52.0, 7.0),
ErrorPoint::symmetric(0.625, 47.0, 6.0),
ErrorPoint::symmetric(0.875, 64.0, 9.0),
],
(0.0, 64.0), // Y domain matching the bar chart
);
// 3. Overlay using the SAME plot rect so whiskers land on bar centres.
let plot_rect = Rect::new(60.0, 40.0, viewport.x - 80.0, viewport.y - 80.0);
let overlay = bars.emit_graphics_in_rect(&theme, viewport, plot_rect);
let _ = stage.add_child(root, overlay);
Three error kinds
[ErrorKind] documents the three input flavours ErrorPoint
helpers convert into the absolute (lower, upper) representation
used at render time:
Symmetric(half_width)— standard deviation or±huncertainty. Helper:ErrorPoint::symmetric(x_fraction, mean, half_width).Asymmetric { lower, upper }— skewed distributions, quantile intervals. Helper:ErrorPoint::asymmetric(x_fraction, mean, below, above).ConfidenceInterval(half_width)— caller pre-multiplies the standard error by the z-score (1.96 × SEfor a 95% CI). The enum carries the half-width; the caller does the stats.
Plot-rect alignment
The most common slip-up is calling
[ErrorBars::emit_graphics] (16-px pad default) when overlaying
on a Plot::Bar chart, which uses a 60-px gutter + 40-px header
/ footer. The whiskers land off-centre. Always use
[ErrorBars::emit_graphics_in_rect] with the underlying
chart's plot rectangle — for a default Plot bar chart that's
Rect::new(60.0, 40.0, viewport.x - 80.0, viewport.y - 80.0).
Why this is an overlay, not a mark
v1 ships ErrorBars as a self-contained value type rather than
a Mark::ErrorBar variant on the Plot facade. The
overlay use case spans multiple mark families (bar / point /
line / box) and doesn't fit cleanly into the (X, Y, Color)
channel model — the per-point lower/upper are extra dimensions.
A future ticket can add Plot::overlay(ErrorBars) once enough
real callers settle on a common ergonomic shape.