Skip to main content

BarChart

Bars — buckets, histograms, stacks, and categories. One component with three input modes; the histogram is BarChart in its bins mode, not a separate component.

src/examples/gallery-histogram.tsx
import {
BarChart,
ChartContainer,
ChartRow,
Layers,
YAxis,
} from '@pond-ts/charts';
import { useSiteChartTheme } from '@site/src/theme/useSiteChartTheme';
import { responseTimeDistribution } from './lib/gallery-fixtures';

/** Response-time distribution: a value-axis histogram (`byColumn`, 10ms-wide
* bins) — the x axis is inferred from the bins, not declared. */
export default function GalleryHistogram({ width }: { width: number }) {
const theme = useSiteChartTheme();
const bins = responseTimeDistribution();

return (
<ChartContainer range={[0, 280]} width={width} theme={theme}>
<ChartRow height={220}>
<YAxis id="count" label="samples" min={0} pad={0.06} width={44} />
<Layers>
<BarChart bins={bins} column="count" gap={2} />
</Layers>
</ChartRow>
</ChartContainer>
);
}

Data contract

Provide exactly one of:

  • series — a TimeSeries / ValueSeries (interval-keyed; each [begin, end) is a bar's span) with column, or a wide series with columns (stacked segments), or a Map<group, TimeSeries> with column (a series per group).
  • binsbyColumn records { start, end, ...aggregates } — the value-axis histogram.
  • categoriesCategoryDatum[] ({ label, value }) → an ordinal category axis, vertical only.

View builder (for custom draw code): barsFromTimeSeries / barsFromValueSeries (single), stacksFromColumns / stacksFromGroups / stacksFromBins (stacked), categoryStack (categories), transposeRow (a wide row → categories).

Props

PropTypeDefaultPurpose
seriesTimeSeries | ValueSeries | Map<string, TS>one-ofSource (single, stacked-by-columns, or per-group Map).
binsBinRecord[]one-ofbyColumn bins — the histogram mode.
categoriesCategoryDatum[]one-ofOrdinal category bars (vertical only).
columnstringwith series/binsValue column (single). column xor columns.
columnsreadonly string[]Stacked segment columns, bottom → top.
asstring'default'Style role (single series only — ignored on stacks).
colorsRecord<string, string>Per-group fill override for stacks.
binColorsreadonly (string | undefined)[]Per-bar fill for a single series (zones, up/down volume).
orientation'vertical' | 'horizontal''vertical'Bar direction.
ordinalbooleanfalseFor bins: uniform [i, i+1] slots instead of numeric edges.
idstringStable identity — gates selection + hover.
axisstringrow defaultWhich <YAxis id> to scale against.
gapnumbertheme (1)Px gap between bars.

Which path a bar takes

Capabilities follow the mark drawn, not the prop that fed it ([PND-BARSEM]). A one-segment vertical bar — series + column, a one-column bins histogram, or a one-entry columns — takes the single-series path and with it whole-slot hit-testing, the theme.bar.hover colour, the cursor readout, stable per-bar identity and per-bar decimation.

Horizontal categorical charts (categories + orientation="horizontal") are the funnel / ranking shape: the categories land on the y axis as unit slots, the value runs along x, and a <YAxis> with no ticks labels one slot per category automatically — no hand-built i + 0.5 list ([PND-HCAT]).

Genuinely multi-segment shapes keep the stacked path: a multi-group stack (columns / a Map series), categories, and any horizontal chart. There the segments share a bin's x-range and only y tells them apart, so the hit target is the drawn segment rather than the slot.

Variants

  • Data modeseries (single / stacked / Map) vs bins (histogram) vs categories (ordinal). This is the axis-behaviour fork.
  • orientation'vertical' (default) or 'horizontal'.
  • column vs columns — a single value column, or stacked segments.
  • colors (per-group stacks) vs binColors (per-bar single-series: value-band zones, or a direction-coloured financial volume row — derive the array from open vs close and the bars read green / red under the candles, keeping their own colour in the hover / click readout). binColors draws every visible bar (the dense-bar envelope decimation is skipped — one envelope rect can't carry many colours).
  • ordinalbins on a uniform ordinal band instead of their numeric spans.

Interaction & theming

  • Cursor: the in-chart value cursor (flag / crosshair) is single-series vertical only — stacked and horizontal bars don't report a per-point readout.
  • Hit target (single-series vertical): a bar's hover / click region is its whole slot — the full interval width and the full plot height — not the drawn rect. The gap only separates the ink, so pointing between columns or above a short bar still selects the bar you're over, and hover agrees with the cursor readout. A shared edge goes to the left bar. Because the region spans the plot height, declare a bar layer below any <ScatterChart> / <BoxPlot> that should stay clickable. Stacked, bins, categories and horizontal charts instead hit the drawn segment — a stack's segments share a bin's x-range, so only y distinguishes them.
  • Selection: id-gated — set id for clickable / hover-lit bars (a stack segment's identity is (id, key, group)). A single-series bar also reports a stable mark — its own axis key, stringified — and a controlled selected carrying one matches on that instead of the bar's key. Pin by mark on a point-keyed series, where the bar's key is the derived left edge of a neighbour-spaced span (t - halfGap) rather than the sample's own time; pinning by key still works and is unchanged.
  • Theming: the theme.bar slot (BarStyle); stacks colour per group via colors, so as is single-series only.

Cautions

  • Histogram is a mode, not a componentbins + orientation.
  • Stacks baseline from 0 — the value axis must include 0; a <YAxis min> above 0 is unsupported for stacks. Negative/zero segments are skipped (diverging stacks are out of scope).
  • Horizontal puts value on x (x-kind 'value') — a horizontal histogram can't share a <ChartContainer> with time-series rows; it stands alone.
  • Exactly one of series / bins / categories, and column xor columns — violations throw.

See also