Skip to content
microcharts
ReferenceFrontierBiasStrip

BiasStrip

React bias strip chart — bland–Altman offset between two measurement methods. Tiny accessible SVG microchart; RSC-safe static or /interactive.

BiasStrip answers "do two ways of measuring the same thing systematically disagree?" — the agreement story a scatter can't tell. Each dot is one pair placed at its mean and its difference; the dashed line is perfect agreement, the accent line is the measured bias, and the faint band is the limits of agreement. Dots render at 75% opacity so overplot reads as density, and pairs beyond the limits are enlarged and re-inked so outliers read on shape, not color alone.

BiasStrip
interactive · 5.12 kB · static · 2.63 kB

Install

Import & usereact/bias-strip
import { BiasStrip } from "@microcharts/react/bias-strip";// pairs — real values under “Sample data” below<BiasStrip data={pairs} title="Device vs reference" />
Sample data
// a ~+2 bias with noise and two pairs beyond the limits of agreementconst pairs = [  1.8, 2.4, 1.5, 2.9, 2.1, 1.2, 2.6, 3.0, 1.9, 2.3, 6.5, 2.0, 1.7, 2.8, 2.2, -1.5, 2.5, 1.6, 2.7,  2.0,].map((d, i) => ({ a: i + d, b: i }));
Needs package + stylesheetSet up with AI

Try it

When to use it

  • Good for — checking whether a new instrument, method, or model agrees with a reference; instrument drift in a KPI card.
  • Avoid for — unpaired samples (use MicroScatter) or a single time series (Sparkline).

A correlation plot answers "do these move together?" — but two methods can correlate perfectly and still disagree by a constant offset. BiasStrip is built for that offset: it plots the difference, so a bias jumps off the zero line where a scatter would hide it on the diagonal.

Sizing

Variants

99% limits of agreement
no caption
bigger dots

Edge cases

empty
fewer than 5 pairs — dots only, no band
perfect agreement — band collapses to a hair

Empty data draws just the frame with "No data." as the summary. Under 5 pairs the limits aren't meaningful, so the band and bias line drop out and only the dots and the zero reference remain — the mean difference is still stated in the summary. When the two methods agree perfectly the band collapses to a hair around the zero line rather than vanishing, so "nothing to see" still reads as a deliberate, measured result. Pairs with a non-finite value are dropped before the stats and the count; past 40 pairs the dots are uniformly downsampled for display while the bias and limits still use every pair.

Four homes

Why this default

The y-axis is symmetric about zero so perfect agreement is always the visual center: a systematic offset then reads as the whole cloud drifting up or down, which is exactly the decision the chart exists to surface. The band is the classic ±1.96σ limits of agreement, and limits widens or tightens it (2.58 for ~99%) without ever redefining what the marks mean. Under five pairs the chart makes no interval claim at all — too little evidence to draw one honestly.

Accessibility

The accessible name is the bias plus the evidence-backed agreement share — "Bias +2.21 across 20 pairs; 90% within the limits of agreement." — or the shorter "Bias +2 across 4 pairs." when there are too few pairs to draw limits. Localizing carries the number format through: with locale="de-DE" the same chart reads "Bias +2,21 across 20 pairs; 90% within the limits of agreement." The interactive entry steps pairs ordered by mean and announces each pair's mean, difference, and whether it clears the limits.

The interactive entry follows the shared interaction contract: arrow keys rove between units on both axes, Home and End jump to the ends, and a click, tap, Enter or Space selects a unit — pinning its readout so it survives blur, until you select it again or press Escape. On touch, a tap pins and a drag scrubs.

Props

PropTypeNotes
data*{ a; b }[]Paired measurements.
limitsnumberk in bias ± k·σ (default 1.96 ≈ 95% limits of agreement).
label"bias" | "none"Seat-gated bias caption (default) or hidden.
rnumberBase dot radius, clamped [1, 3].
animatebooleaninteractiveOpt-in entrance motion when the chart mounts client-side — add import "@microcharts/react/motion" once. Inert on the server, on hydrated server HTML, and under prefers-reduced-motion.

Plus the shared grammar — data, domain, color, title, summary, format — and the layout props (width, height, className, style) that every chart accepts. Interactive entries also share animate and live, and — wherever a chart has more than one navigable unit — onActive, onSelect, selectedIndex and defaultSelectedIndex; and — wherever the chart shows a hover value — readout. See the shared grammar.

Related charts