ScatterPlot
Correlation plot of two measures per entity (latency vs. throughput, spend vs. conversions), with optional bubble size and group color encodings.
Component behavior
ScatterPlot shows whether two numbers move together. Each mark is one entity measured twice, and position on both axes carries the meaning.
- Relationships between two continuous measures per record.
- Outlier inspection across a moderate number of records.
- Additional measures encoded by bubble size and group color.
Props
A ScatterPoint is x and y in your own units, plus an optional size (bubble radius input), label, and group (color and legend membership). Both axes default to the data's own extent padded 6% at each end, which normally puts the origin off-screen; pass xDomain/yDomain if zero has to be visible or if two charts must share a scale. Points are drawn in array order, so later entries sit on top.
| Prop | Type | Default | Description |
|---|---|---|---|
points | ScatterPoint[] | — | One entry per entity. Markers are HTML circles with a 2px surface ring so overlapping points stay countable, and point.label becomes the marker's native title attribute. |
groups | { name: string; color: string }[] | — | Colors by group name. Unmatched or omitted groups use the first group color. |
height | number | 200 | Plot area height in pixels. The x-axis, axis labels, and legend add to the total. |
xLabel | ReactNode | — | Caption under the x-axis, rendered small and uppercase. Put the units here. |
yLabel | ReactNode | — | Caption beside the y-axis, rotated vertically. Put the units here. |
xDomain | [number, number] | — | X-axis domain. Defaults to the data's extent padded ~6%; if every x is identical it becomes [x − 1, x + 1]. Values outside the domain still render, outside the plot. |
yDomain | [number, number] | — | Y-axis domain, with the same defaulting rules as xDomain. |
formatX | (value: number) => string | — | Formats x-axis tick labels. Defaults to Math.round, which collapses ticks on a domain narrower than a few units. |
formatY | (value: number) => string | — | Formats y-axis tick labels. Same default and same caveat. |
ticks | number | 4 | Tick count per axis, including both ends. Horizontal gridlines are drawn for every y tick; vertical ones only for interior x ticks. |
pointRadius | number | 4 | Marker radius in pixels for points with no size. Points that do have a size ignore it entirely. |
trendLine | boolean | — | Dashed ordinary-least-squares fit across the full x domain, computed over every point regardless of group. Not drawn for fewer than two points or when every x is identical. |
renderTooltip | (point: ScatterPoint) => ReactNode | — | Tooltip renderer receiving the hovered point. Changes sides past 60% of plot width. |
Examples
Groups and tooltips
groups assigns a color per series name and draws the legend, which only appears when there are two or more groups. Hovering a marker dims the rest to 28% and hands the point to renderTooltip. Even without one, every point's label is set as the marker's title, so the browser's own tooltip still names it.
Trend line
trendLine fits an ordinary least-squares line across all points, including every group. The line spans the x domain and represents the pooled relationship. Outliers can substantially affect the fit.
Bubble size as a third measure
Bubble radius is proportional to the square root of size, so area represents the value. Radii have a 3px minimum and an approximate 12px maximum.
Pinning the domains
The default domain is the data's extent plus 6% padding. This fills the plot area but hides how far the cluster sits from zero, so the same data can look steep or modest depending on the domain. Pin xDomain and yDomain when the origin is part of the argument, or when two charts must be compared.
import { ScatterPlot } from "@solarius/onset";
import type { ScatterPoint } from "@solarius/onset";
<ScatterPlot
points={[
{ x: 10, y: 45, size: 30, group: "A" },
{ x: 40, y: 48, size: 40, group: "B" },
]}
groups={[
{ name: "A", color: "var(--m-color-primary)" },
{ name: "B", color: "var(--m-color-warn)" },
]}
xLabel="Throughput"
yLabel="Latency"
xDomain={[0, 100]}
trendLine
/>;