Scatter Chart
The Scatter Chart plots each datum at its own x and y, so the reading is the relationship between two continuous measures — correlation, clustering, outliers — rather than a trend along an ordered axis. Add sizeBy and it becomes a bubble chart, encoding a third measure as marker area between minRadius and maxRadius. Each series binds its own xBy, yBy, marker and yAxis, and dual-axis crosshair tracking, a legend, grid lines and axis titles are built in. Dense scatters take panning and zooming via navigator, and points animate on entry, update and exit. The target can be a Canvas, an SVG context or a terminal.
NOTE
For the full API, see the Charts API Reference.
Example
TIP
This chart has the navigator enabled. Scroll to zoom toward the cursor and click-and-hold to pan (⌘/Ctrl-drag works too). Use Reset View to return to the default framing.
Usage
import {
createScatterChart,
} from '@ripl/charts';
const chart = createScatterChart('#container', {
data,
key: 'id',
series: [
{
id: 'sales',
label: 'Sales',
xBy: 'sales',
yBy: 'profit',
},
],
});Data Format
Each item needs a unique key and numeric fields for x/y position (and optionally size):
const data = [
{
id: 'a',
sales: 42,
profit: 78,
volume: 15,
},
{
id: 'b',
sales: 68,
profit: 35,
volume: 30,
},
{
id: 'c',
sales: 91,
profit: 52,
volume: 8,
},
];Each series maps xBy and yBy to numeric fields, and optionally sizeBy for bubble sizing.
Variants
Bubble chart
Add sizeBy, minRadius, and maxRadius to enable bubble sizing:
createScatterChart('#container', {
data,
key: 'id',
series: [
{
id: 'sales',
label: 'Sales',
xBy: 'sales',
yBy: 'profit',
sizeBy: 'volume',
minRadius: 5,
maxRadius: 15,
},
],
});Multi-series
Plot multiple series on the same axes for comparison:
createScatterChart('#container', {
data,
key: 'id',
series: [
{
id: 'sales',
label: 'Sales',
xBy: 'sales',
yBy: 'profit',
},
{
id: 'marketing',
label: 'Marketing',
xBy: 'marketing',
yBy: 'engagement',
},
],
});Multiple y-axes
Supply an array of axis.y entries to plot series with different y units on their own independently-scaled axes. Bind each series to an axis with its yAxis option, naming the axis's id; position: 'right' axes sit on the right and same-side axes stack outward in array order:
createScatterChart('#container', {
data,
key: 'id',
series: [
{
id: 'sales',
label: 'Sales',
xBy: 'spend',
yBy: 'revenue',
yAxis: 'revenue',
},
{
id: 'efficiency',
label: 'Efficiency',
xBy: 'spend',
yBy: 'roas',
yAxis: 'roas',
},
],
axis: {
y: [
{
id: 'revenue',
title: 'Revenue ($)',
},
{
id: 'roas',
position: 'right',
title: 'ROAS (×)',
},
],
},
});Pan & zoom (navigator)
Set navigator: true to make the plot explorable: wheel-zoom toward the cursor and click-and-hold to pan, with the axis domains rescaling as the view changes (no data rebuild). Pass an object to tune which interactions are active:
const chart = createScatterChart('#container', {
data,
key: 'id',
series: [/* ... */],
navigator: {
zoom: true,
pan: true,
brush: true,
},
});
// The controller is available for imperative framing and brush-and-link:
chart.navigator?.fitBounds({ x0: 0, y0: 0, x1: 200, y1: 200 });
chart.navigator?.on('brushend', ({ data: extent }) => console.log(extent));
chart.navigator?.reset();Options
A full configuration for this chart. The options every chart shares — padding, title, animation, theme and the rest — behave the same everywhere and are documented on Shared Options.
createScatterChart('#container', {
data,
key: 'id',
labels: true,
format: 'number',
series: [
{
id: 'sales',
label: 'Sales',
color: '#7cacf8',
xBy: 'spend',
yBy: 'revenue',
// Scales each bubble between `minRadius` and `maxRadius`.
sizeBy: 'volume',
minRadius: 4,
maxRadius: 20,
marker: 'circle',
yAxis: 'revenue',
},
{
id: 'reach',
label: 'Reach',
color: '#6dd5b1',
xBy: 'spend',
yBy: 'impressions',
yAxis: 'impressions',
},
],
axis: {
y: [
{
id: 'revenue',
title: 'Revenue ($)',
},
{
id: 'impressions',
position: 'right',
title: 'Impressions',
},
],
},
});Events
Subscribe with chart.on(...). A handler receives an Event object, not the payload directly — the payload is on event.data, and carries the interacted datum plus its { x, y } anchor in chart pixels. event.target and event.stopPropagation() are also available.
// Emitted when a bubble is clicked.
chart.on('markerclick', event => console.log(event.data)); // event.data: ScatterChartMarkerEvent
// Emitted when the pointer enters a bubble.
chart.on('markerenter', event => console.log(event.data)); // event.data: ScatterChartMarkerEvent
// Emitted when the pointer leaves a bubble.
chart.on('markerleave', event => console.log(event.data)); // event.data: ScatterChartMarkerEvent