Skip to main content

<ScatterChart>

component@pond-ts/chartssource

A scatter draw layer: one mark per finite point at (x, column-value) — x from the series' key / axis column (time or value axis) — with data-driven radius + colour (the signed-off exception — encode from columns via scales, not a per-event style callback). Reads column into a ChartSeries (gaps as NaN → no mark), registers into the enclosing Layers (scaling against its axis), and renders nothing to the DOM — the row draws it.

Interactions. Hover snaps the tracker dot to the nearest point (sampleAt), and that sample flows to the container's onTrackerChanged — the nearest-point readout. Scatter reuses the shared tracker rather than adding a separate onNearest channel, so a scatter reads out exactly like a line. Click selection hit-tests each point's disc (hitTest) — opt-in via id; the selected point (matching the selection's series id and the sample key) gets a highlight ring. Without an id the scatter is display-only.

<Layers>
  <ScatterChart
    series={s}
    column="price"
    radius={{ column: 'volume', range: [3, 14] }}
    color={{ column: 'change', range: ['#e8836b', '#15B3A6'] }}
  />
</Layers>

Props

columnstringrequired

Name of the numeric value column — each point's y.

seriesTimeSeriesTimeSeriesclasspond-ts

An immutable, schema-typed, ordered collection of events — the batch layer's core primitive. A series is constructed whole from complete data and never mutated: every transform (filter, align, rollup, …) returns a new TimeSeries, so the full analytical surface can sort, scan, or index freely. Example: new TimeSeries({ name, schema, rows }).

<S> | ValueSeriesValueSeriesclasspond-ts

A value-keyed series — the closed value-axis counterpart of TimeSeries. Its key is a monotonic non-time axis (distance, cumulative work, …). Two doors in: project a TimeSeries onto one of its monotonic columns (TimeSeries.byValue(axis) — a track re-keyed by cumulative distance), or construct directly from columnar arrays (`ValueSeries.fromC…

<VS>
required

The source series. A TimeSeries scatters against the time axis; a ValueSeries (series.byValue('cumDist'), or ValueSeries.fromColumns for natively value-keyed data — IV marks keyed by strike) against its value axis — the container infers which from the data, no axis-type prop (mirrors <LineChart>). Either way the key / axis column supplies each point's x and column supplies y.

Live charts: series.byValue(…) mints a fresh projection each call, so passing series={s.byValue('dist')} inline re-registers this layer every render — memoize the projection (useMemo) on a frequently re-rendering chart.

asstring

The scatter's semantic identifier — what the marks are / how they should read. The theme maps it to a ScatterStyle (theme.scatter[as] ?? theme.scatter.default) — the base fill, radius, outline, and label colour. Omitted ⇒ the default style. This is the single styling channel for the base mark; per-point size / colour come from the data-driven radius / color encodings below (the deliberate, signed-off scatter exception), not a per-component style override.

axisstring

Which <YAxis> (by its id) this scatter scales against — picks the scale, where as picks the style. Omitted ⇒ the row's default axis.

colorColorEncodingColorEncodinginterface@pond-ts/charts{ column: string; range: readonly [string, string] }

Per-point colour encoding — { column, range }: map the column's finite extent linearly onto a two-stop colour ramp [atMin, atMax] (interpolated in sRGB). A point whose colour column is non-finite falls back to the base colour (the single styling channel — theme.scatter[as].color).

Data-driven point colour{ column, range }: colour each point from a numeric column (its finite extent → a two-stop hex ramp via a linear scale). A point whose colour column is non-finite falls back to the base colour. Omitted ⇒ the style's base colour for every point (the single styling channel). Same discipline as radius: a column + range, not a callback.

idstring

The stable series identity for selection + hover. Optional, and it gates interactivity: the scatter is selectable/hoverable only when given an id — omit it and the points render + read out but can't be clicked (a click on them reads as empty space ⇒ deselect). Distinct from as (a theme role that can repeat): id must be unique among the selectable layers, and it is the key the controlled selected echo, dedup, and (later) multi-select all match on — so a selection survives a data update where a sample key goes stale.

A point's identity within the series is its x (key / axis value). The key contract allows duplicate x's (equal timestamps; a value-axis plateau from byValue('cumDist')) — points sharing an x share identity, so selecting one highlights the last drawn point at that x.

labelstring | boolean

An optional per-point text label, drawn just right of each mark, in the style's label colour + the theme font. Two forms:

  • a column name ⇒ that column's value at each point, stringified;
  • true ⇒ the plotted column's value, stringified.

Omitted / false ⇒ no labels. Keep it sparse — a label per point on a dense scatter is noise; this is for a handful of called-out marks.

offsetnumber

A pixel shift applied to every point's x — zoom-stable. Default 0. For pairing marks that share a key side by side (a call and a put mark at one strike: offset={-4} / offset={+4}). Pairs with <BoxPlot offset>; on the scatter the shift is exact — both the draw and the click hit-test move together, so a nudged point still selects.

radiusRadiusEncodingRadiusEncodingtype@pond-ts/chartsnumber | { column: string; range: readonly [number, number] }

Per-point radius encoding. Either:

  • a fixed radius in CSS px (every point the same size — the common case), or
  • { column, range }: map the column's finite extent linearly onto [minR, maxR] px. A point whose radius column is non-finite falls back to the base radius (it still draws, at the default size).

Data-driven point radius — the signed-off exception to one-channel styling. Either a fixed px radius, or { column, range } to size each point from a numeric column (its finite extent → [minR, maxR] px via a linear scale). A point whose radius column is non-finite falls back to the base radius. Omitted ⇒ the style's base radius. The encoding is a column + range, not a per-datum callback — there's no place for a styling bug to hide (the trap the package avoids).