Skip to main content

BoxPlot

Box-and-whisker per bucket, drawn from pre-computed quantile columns. For a distribution over time (a latency percentile fan) or over a value axis.

src/examples/gallery-boxplot.tsx
import {
BoxPlot,
ChartContainer,
ChartRow,
Layers,
YAxis,
} from '@pond-ts/charts';
import { useSiteChartTheme } from '@site/src/theme/useSiteChartTheme';
import { hourlyLatencyBoxes, hourlyLatencyRange } from './lib/gallery-fixtures';

/** Latency percentiles: hourly box-and-whisker buckets from five
* pre-computed quantile columns — the shape a percentile rollup produces. */
export default function GalleryBoxplot({ width }: { width: number }) {
const theme = useSiteChartTheme();
const series = hourlyLatencyBoxes();

return (
<ChartContainer range={hourlyLatencyRange()} width={width} theme={theme}>
<ChartRow height={220}>
<YAxis id="ms" side="right" label="ms" format=",.0f" width={44} />
<Layers>
<BoxPlot
series={series}
lower="p5"
q1="p25"
median="p50"
q3="p75"
upper="p95"
axis="ms"
gap={10}
/>
</Layers>
</ChartRow>
</ChartContainer>
);
}

Data contract

Takes a TimeSeries or ValueSeries whose columns are already the quantiles — the chart does not compute them (feed a rolling / aggregate percentile pass). lower and upper are required; q1 + q3 (both or neither) and median are optional. A full box is five columns; a range-only box is just lower / upper. The box's x-span is the interval key [begin, end) or neighbour spacing. Adapter: boxFromTimeSeries(series, { lower, q1, median, q3, upper }) / boxFromValueSeries.

Props

PropTypeDefaultPurpose
seriesTimeSeries | ValueSeries— (req)The source series.
lowerstring— (req)Lower whisker column (e.g. p5 / min).
upperstring— (req)Upper whisker column (e.g. p95 / max).
q1stringBox bottom (Q1). Both-or-neither with q3.
q3stringBox top (Q3).
medianstringMedian line column; omit for no centre line.
asstring'default'Style role → theme.box[as].
axisstringrow defaultWhich <YAxis id> to scale against.
shape'whisker' | 'solid' | 'none''whisker'Box presentation (see variants).
showMedianbooleantrueDraw the median line (no-op without a median column).
gapnumber0Total horizontal inset px.
capWidthnumberhalf box widthWhisker cap width (whisker shape only).
offsetnumber0Pixel x-shift — only the draw shifts, not the readout (keep small).

Variants

  • shape'whisker' (default: stems + caps), 'solid' (candlestick look: outer bar + darker q1q3 inner, no stems), 'none' (the q1q3 box only).
  • Full box vs range-only — omit q1 + q3 for a min/max range box.
  • showMedian — hide the centre line even when a median column is present.

Interaction & theming

  • Cursor: reads the box under the cursor (span containment) and shows a single consolidated flag at the box top with every quantile in one row, each coloured to its piece. This opts the box out of the crosshair reticle x-snap (unlike Candlestick, which opts in).
  • Selection: not selectable.
  • Theming: the theme.box slot (BoxStyle with fill / stroke / median / whisker).

Cautions

  • The chart doesn't compute quantiles — supply them from a percentile rollup.
  • q1 / q3 are both-or-neither — passing one throws.
  • Range-only + shape='none' draws nothing — use 'whisker' or 'solid'.
  • offset shifts only the draw, not the readout — keep it small.

See also

  • Candlestick — the OHLC counterpart (supersedes shape='solid' for price bars).
  • Storybook: Charts/BoxPlotPercentiles, Solid, WithGap, the vol-smile variants.
  • The generated API reference — the full BoxPlotProps type.