ScatterChart
Points, with optional data-driven radius and colour. For discrete events, or a two-encoding cloud (a vol smile keyed by strike on a value axis).
src/examples/gallery-scatter.tsx
import {
ChartContainer,
ChartRow,
Layers,
ScatterChart,
YAxis,
} from '@pond-ts/charts';
import { useSiteChartTheme } from '@site/src/theme/useSiteChartTheme';
import { tradeTicks, tradeTicksRange } from './lib/gallery-fixtures';
/** Trade ticks: a data-driven scatter — radius encodes size, colour encodes
* up/down — pond's signed-off exception to "style is never data-driven". */
export default function GalleryScatter({ width }: { width: number }) {
const theme = useSiteChartTheme();
const series = tradeTicks();
// The candle up/down pair is the theme's existing source of truth for
// this exact semantic (down, up) — reused rather than re-declaring hex.
const down = theme.candle.default.falling.body;
const up = theme.candle.default.rising.body;
return (
<ChartContainer range={tradeTicksRange()} width={width} theme={theme}>
<ChartRow height={220}>
<YAxis id="price" side="right" format="$,.0f" width={50} />
<Layers>
<ScatterChart
series={series}
column="price"
axis="price"
radius={{ column: 'size', range: [3, 14] }}
color={{ column: 'change', range: [down, up] }}
/>
</Layers>
</ChartRow>
</ChartContainer>
);
}
Data contract
Takes a TimeSeries or ValueSeries and one numeric column (the y); x comes
from the key/axis. Points may share an x. Adapter: fromTimeSeries /
fromValueSeries; the radius / color encodings read their own columns.
Props
| Prop | Type | Default | Purpose |
|---|---|---|---|
series | TimeSeries | ValueSeries | — (req) | The source series. |
column | string | — (req) | Numeric column → each point's y. |
as | string | 'default' | Style role → theme.scatter[as]. |
id | string | — | Stable identity — gates selection + hover. Unique per layer. |
axis | string | row default | Which <YAxis id> to scale against. |
radius | number | { column, range } | style base | Fixed px, or data-driven size from a column's extent → [min, max]. |
color | { column, range: [hex, hex] } | style base | Data-driven colour ramp between two hex stops. |
label | string | boolean | none | Per-point text: a column name, or true for the plotted value. |
offset | number | 0 | Pixel x-shift (zoom-stable) for pairing nudges. |
Variants
radius— a fixed number, or{ column, range: [minR, maxR] }to size each point from a numeric column.color—{ column, range: [hex, hex] }to colour each point along a two-stop ramp.idpresent vs absent — withid, points are selectable and hover-lit; without it, the layer is display-only.
Interaction & theming
- Cursor: the tracker dot snaps to the nearest drawn point; its swatch uses the point's encoded colour, matching the mark.
- Selection: id-gated — set
idto make points clickable (onSelect) and hover-highlightable. One of only two selectable layers (withBarChart). - Theming: the
theme.scatterslot (ScatterStylewith basecolor/radius/outline+ selected-outline).
Cautions
- Data-driven
radius/colorare column + range only — the deliberate, signed-off exception to one-channel styling; there's no per-datum callback. - Ramp stops must be CSS hex — a non-hex stop disables interpolation for that point.
- Keep
labelsparse — a label per point on a dense scatter is noise.
See also
- Value axis — a natively value-keyed scatter (vol smile).
- Selection & hover — the id-gated selection model.
- Storybook:
Charts/ScatterChart—Encoded,Labelled,ControlledSelect, the value-axis variants. - The generated API reference — the full
ScatterChartPropstype.