Skip to main content

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

PropTypeDefaultPurpose
seriesTimeSeries | ValueSeries— (req)The source series.
columnstring— (req)Numeric column → each point's y.
asstring'default'Style role → theme.scatter[as].
idstringStable identity — gates selection + hover. Unique per layer.
axisstringrow defaultWhich <YAxis id> to scale against.
radiusnumber | { column, range }style baseFixed px, or data-driven size from a column's extent → [min, max].
color{ column, range: [hex, hex] }style baseData-driven colour ramp between two hex stops.
labelstring | booleannonePer-point text: a column name, or true for the plotted value.
offsetnumber0Pixel 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.
  • id present vs absent — with id, 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 id to make points clickable (onSelect) and hover-highlightable. One of only two selectable layers (with BarChart).
  • Theming: the theme.scatter slot (ScatterStyle with base color/radius/outline + selected-outline).

Cautions

  • Data-driven radius/color are 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 label sparse — a label per point on a dense scatter is noise.

See also