Charts
ScatterChart
Two measures against each other, one mark per observation.
Usage
When to reach for it
Ships from@misoto22/design/charts
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
| Element | Description |
|---|---|
| Figure framerequired | ChartFigure’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. |
| Crosshair | The 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 table | table 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.
| kb | Load (ms) |
|---|---|
| 120 | 340 |
| 180 | 412 |
| 240 | 505 |
| 310 | 618 |
| 360 | 660 |
| 420 | 790 |
| 470 | 812 |
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.
| kb | Load (ms) |
|---|---|
| 120 | 340 |
| 180 | 412 |
| 240 | 505 |
| 310 | 618 |
| 420 | 790 |
| 130 | 520 |
| 190 | 610 |
| 250 | 704 |
| 320 | 861 |
| 430 | 990 |
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.
| kb | Load (ms) | Downloads |
|---|---|---|
| 120 | 340 | 400 |
| 180 | 412 | 1,200 |
| 240 | 505 | 260 |
| 310 | 618 | 2,400 |
| 420 | 790 | 900 |
Types
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.