ScatterPlot
PreviewSVG · Canvas · WebGLPublishes selection
Plots two quantitative fields against each other to show correlation, clusters and outliers. Add size for a bubble chart.
Playground
Campaigns: sessions against conversion
36 campaigns · Preparing renderer
Conversion against Sessions, 36 points in 4 groups, sized by Revenue. Sessions from 811 to 13,994; Conversion from 1.5% to 5.75%. Moderate positive correlation (r = 0.33).
| Campaign | Channel | Sessions | Conversion | Revenue |
|---|---|---|---|---|
| Campaign 20 | Direct | 811 | 2.51% | $2,931.00 |
| Campaign 13 | Organic search | 820 | 2.44% | $4,676.00 |
| Campaign 30 | Paid social | 1,188 | 4.72% | $6,783.00 |
| Campaign 23 | 1,234 | 2.38% | $5,439.00 | |
| Campaign 1 | Organic search | 1,620 | 2.51% | $5,729.00 |
| Campaign 16 | Direct | 1,710 | 2.71% | $6,486.00 |
| Campaign 6 | Paid social | 1,988 | 1.58% | $7,484.00 |
| Campaign 21 | Organic search | 2,829 | 2.63% | $14,560.00 |
| Campaign 22 | Paid social | 3,394 | 3.47% | $5,439.00 |
| Campaign 8 | Direct | 3,532 | 1.5% | $7,522.00 |
| Campaign 15 | 3,563 | 2.37% | $18,947.00 | |
| Campaign 18 | Paid social | 3,941 | 1.61% | $18,177.00 |
| Campaign 26 | Paid social | 4,452 | 1.66% | $6,941.00 |
| Campaign 12 | Direct | 4,492 | 4.87% | $24,231.00 |
| Campaign 32 | Direct | 4,864 | 4.66% | $7,901.00 |
| Campaign 31 | 6,956 | 3.3% | $30,099.00 | |
| Campaign 17 | Organic search | 8,104 | 4.92% | $30,469.00 |
| Campaign 34 | Paid social | 8,425 | 4.34% | $37,935.00 |
| Campaign 29 | Organic search | 8,519 | 2.93% | $16,288.00 |
| Campaign 5 | Organic search | 8,875 | 2.79% | $36,341.00 |
| Campaign 33 | Organic search | 8,941 | 3.05% | $38,157.00 |
| Campaign 19 | 9,290 | 4.87% | $51,077.00 | |
| Campaign 9 | Organic search | 9,314 | 2.95% | $20,866.00 |
| Campaign 25 | Organic search | 9,898 | 3.52% | $41,025.00 |
| Campaign 3 | 9,950 | 3.93% | $38,642.00 | |
| Campaign 7 | 10,795 | 5.14% | $38,878.00 | |
| Campaign 2 | Paid social | 11,397 | 5.75% | $33,637.00 |
| Campaign 24 | Direct | 12,214 | 2.26% | $51,692.00 |
| Campaign 36 | Direct | 12,241 | 4.96% | $51,210.00 |
| Campaign 4 | Direct | 12,312 | 2.26% | $45,470.00 |
| Campaign 27 | 12,501 | 5.53% | $43,741.00 | |
| Campaign 35 | 12,695 | 2.3% | $67,203.00 | |
| Campaign 10 | Paid social | 13,141 | 2.88% | $76,591.00 |
| Campaign 28 | Direct | 13,646 | 2.42% | $44,396.00 |
| Campaign 14 | Paid social | 13,936 | 3.77% | $45,471.00 |
| Campaign 11 | 13,994 | 3.7% | $30,708.00 |
renderer
<ScatterPlot
data={campaigns}
renderer="svg"
x="sessions"
y="conversion_rate"
size="revenue"
color="channel"
label="campaign"
select
/>Installation
ScatterPlot is exported from @quartile/react, alongside every other chart and component.
git clone https://github.com/zinnoberHaus/quartileNot on npm yet: build the package from the clone as described in Installation. The preview API may change before publication.
Usage
Pass rows and name quantitative x/y fields. SVG remains the default; set renderer="canvas" or renderer="webgl" explicitly. Read Canvas and WebGL scatter for fallback, limits and measurements.
import { ScatterPlot } from '@quartile/react';
// campaigns: { campaign: 'Campaign 4', channel: 'Email', sessions: 8210, conversion_rate: 0.034, revenue: 31800 }, …
type Campaign = { campaign: string; channel: string; sessions: number; conversion_rate: number; revenue: number };
export function Campaigns({ campaigns }: { campaigns: Campaign[] }) {
return (
<ScatterPlot
data={campaigns}
x="sessions"
y="conversion_rate"
size="revenue"
color="channel"
label="campaign"
select
/>
);
}select toggles a value on click or Enter: true uses the color field (or label), and a field name selects by that field, such as an id. Shift adds.typedSelection preserves physical identities for prepared query results. See Linked selections.Props
PropTypeDefaultDescription
renderer'svg' | 'canvas' | 'webgl'ScatterRenderer'svg'SVG is the default. WebGL falls back to Canvas, then SVG, when unavailable or lost.
onRendererChange(state: ScatterRendererState) => void—Reports the active renderer after drawing, including any fallback reason.
datarequiredDataInput<R>—Rows to plot, or a dataset with a schema attached.
xrequiredkeyof R & string—Quantitative field for the horizontal axis.
yrequiredkeyof R & string—Quantitative field for the vertical axis.
sizekeyof R & string—Sizes each point by this field (area-proportional), making a bubble chart.
colorkeyof R & string—Colors points by a categorical field.
labelkeyof R & string—Field naming each point, used as the tooltip title.
formatFormatter—Formats
y. Defaults to the field's schema format.xFormatFormatter—Formats
x. Defaults to the field's schema format.selectboolean | (keyof R & string)—Click (or Enter) toggles a value in the selection:
true uses the color field (or label), a field name uses that field, e.g. a point id. Shift adds to the selection.typedSelectionbooleanfalsePreserve physical field identities for prepared query results, including nominal ISO strings.
legendboolean—Shows a legend above the plot. Defaults to true when
color is set.xTitlestring | false—Axis titles under the plot. Default "<x> →" and "↑ <y>"; false hides them.
yTitlestring | false——
idstring—Publisher id for the selection. Defaults to a generated id.
selectionstring | false—Selection to read from and publish to. Defaults to the nearest; false opts out.
onSelect(predicate: Predicate | null) => void—Called after a click selection changes.
Frame and state props shared with the charts (11) · ChartBaseProps, ChartStateProps
PropTypeDefaultDescription
heightnumber240Plot height in px. Width always fills the container.
classNamestring——
styleCSSProperties——
aria-labelstring—Accessible name. A summary of the data is generated and rendered as hidden text inside the figure.
view'chart' | 'table'—
table renders the same data as a table, with the same formats, at the chart's size. Large lazy tables expose a data-view control rather than mounting every hidden row.tooltipNotestring—Plain-text context shown with tooltips and included in the accessible chart description.
loadingboolean | string—Shows the loading state at the chart's size, so the layout never jumps.
errorboolean | string | Error | null—Shows the error state. A string or Error becomes the message.
errorCodestring—Shown in the error state; copyable for support.
onRetry() => void——
empty{ title?: string; description?: string; action?: ReactNode }—Title and description for the empty state. Shown when there are no rows.
Accessibility
Keyboard
Tab into the plot, arrow keys between points, Home and End to jump. With
select, Enter or Space toggles the focused point and Shift adds it.Screen readers
A summary gives the point count, both ranges and the strength of the correlation. The focused point is announced with its values.
Exact paged data
Above 200 visible points, a data-view button opens 50-row pages instead of constructing a full hidden table. Every exact plotted value remains reachable.
view="table" opens it directly; smaller plots keep the hidden table.Report an issueBuilt Oct 21, 2026