Skip to content
Folio

Charts

ScatterChart

Two measures against each other, one mark per observation.

Usage

When to reach for it

Correlation, clustering, outliers — the questions that do not survive being bucketed into a bar. The only chart here whose x axis is a number rather than a category.

Ships from@misoto22/design/charts

TSX
import { ScatterChart } from '@misoto22/design/charts'

Notes

Two measures against each other, one mark per observation — the shape for "is there a relationship here".

The only chart in the set whose x axis is a NUMBER rather than a category, which is the whole point: a scatter answers correlation, clustering and outliers, and none of those questions survive being bucketed into a bar.

Past three series, shape stops separating them and the answer is small multiples — one chart per series, same axes — rather than a fourth mark.

Anatomy

ScatterChart anatomy
ElementDescription
Figure framerequiredChartFigure’s <figure>, with isLoading and an empty state. Emptiness is read from the declared table rows, for the same reason the table is declared at all: the observations live on each <Scatter>, and the root cannot see them.
Numeric axesrequired<ScatterChart.XAxis> and <ScatterChart.YAxis>, both type="number" by default. The only chart in the group whose horizontal axis is a measurement rather than a category.
Cloudsrequired<ScatterChart.Scatter>, one per series, each carrying its OWN data array rather than reading the root’s. Six mark shapes, and a solid mark takes a 1px --chart-surface ring so two coincident observations stay countable.
Size channel<ScatterChart.ZAxis>, range [40, 400] by default. That range is in AREA, not radius: doubling a radius quadruples the ink, which is how a bubble chart usually lies.
CrosshairThe tooltip’s cursor, a pair of rules rather than one band. A scatter point is located by two coordinates and a single vertical cursor answers half of that.
Declared tabletable is a PROP here, not inferred. Scatter data lives on each series, so there are no rows on the root to read off — and passing nothing ships a figure with no table at all.

Best practices

Do

  • Declare table. It is the one chart in the group whose hidden table cannot be derived, so omitting it fails silently: the figure renders, is named, and has no numbers behind it.
  • Separate series by shape before anything else. Circle against cross stays legible where two steps of grey do not, and shape survives overprinting and forced colours — where every --series-* token becomes CanvasText and a lightness step is gone.
  • Reach for variant="outline" or shape="ring" on a dense cloud. A hollow mark shows what is under it; a solid one at two thousand points is a silhouette of the densest region and nothing else.

Don’t

  • Do not vary size between series to mean something. size is a flat radius in pixels, so it encodes nothing while looking exactly as if it does; <ScatterChart.ZAxis> is the only path that maps a value to a mark’s area.
  • Past three series shape stops separating them — circle, cross and triangle are distinct, and a fourth glyph is a diamond most readers see as a rotated square. Small multiples on shared axes is the answer, not a fourth mark.

Examples

default

Two measures against each other, one mark per observation — the only chart here whose x axis is a NUMBER rather than a category, which is what lets it answer correlation, clustering and outliers. Seven points rising together is a pattern and not a coefficient: nothing here fits a line, and the chart claims no share of ms explained by kB. Each solid mark carries a surface-coloured ring, the hairline that keeps two overlapping observations countable — past a few hundred points that stops working and density has to be shown some other way. The table prop is not bookkeeping: a scatter's rows live on each Scatter rather than on the root, so unlike every other chart in the package the hidden table cannot be inferred and has to be declared.

Load time against bundle size
Load time against bundle size
kbLoad (ms)
120340
180412
240505
310618
360660
420790
470812

shape and variant

Two clouds that overlap, and the props that keep them apart. The package's ramp is monochrome, so shape is doing the work hue does elsewhere: circle against cross separates two overlapping clouds far better than two steps of grey, and a shape survives overprinting where a lightness step does not. outline hollows the mark out, which is the version to reach for where the clouds sit on top of each other, since a hollow mark shows the one underneath it. Past three series shape stops separating them, and the answer is a grid of small multiples — one plot per series, same axes — not a fourth glyph.

Load time against bundle size
Load time against bundle size
kbLoad (ms)
120340
180412
240505
310618
420790
130520
190610
250704
320861
430990

bubbles

A third measure on the same two axes, carried by ZAxis. Recharts scales the z range in AREA units, which is what makes it safe: map a value to a RADIUS instead and doubling it quadruples the ink, so a release with twice the downloads would read as four times as popular. The 60 to 900 range here is a fifteenfold span of area and roughly a fourfold span of diameter. outline is deliberate too — bubbles overlap by construction, and a solid mark hides whatever smaller one it lands on.

Load time, bundle size and downloads
Load time, bundle size and downloads
kbLoad (ms)Downloads
120340400
1804121,200
240505260
3106182,400
420790900

Types

TSX
export type ScatterShape = 'circle' | 'square' | 'triangle' | 'diamond' | 'cross' | 'ring'
export type ScatterVariant = 'solid' | 'outline' | 'gradient'

Accessibility

  • title is required. The table view is declared rather than inferred: scatter data lives on each series, so there is no single set of rows to read off the root.
  • Shape does the work hue does elsewhere. Two overlapping clouds separate far better by circle-versus-cross than by two steps of grey — and shape survives overprinting, which a lightness step does not.
  • A solid mark carries a surface-coloured ring, so two observations that land on top of each other stay countable.
  • ZAxis maps its measure to a mark’s AREA, not its radius: doubling a radius quadruples the ink, which is the most common way a bubble chart lies.