Scatter Chart
Correlation between a numeric X field and one or more Y series, plotted as colored dots.
Overview
ScatterChart is the styled wrapper over recharts' ScatterChart, composed on the shadcn chart primitive (ChartContainer). xKey is a numeric field (linear X axis); each entry in config is a numeric Y series. The chart wires up the cartesian grid, the numeric X and Y axes, an optional tooltip, and one set of dots per series.
Reach for ScatterChart when you need to surface correlation, density, or outliers - response time vs payload size, conversion rate vs traffic, runtime vs input. For ordered category trends use LineChart or AreaChart; for discrete category comparison use BarChart.
The React edition (@gremorie/rx-data) renders with recharts inside the shadcn chart primitive; the Angular edition (@gremorie/ng-data) renders headless d3 geometry inside a styled SVG. The rendering engine differs; the public surface is identical input-for-input.
Anatomy
<scatter-chart>
└─ figure (role="img") card surface, aspect-video
├─ svg (chart frame)
│ ├─ cartesian grid
│ ├─ x axis (numeric from xKey)
│ ├─ y axis (numeric, optional via yAxis)
│ └─ points, one set per config key
├─ tooltip overlay (optional via tooltip)
├─ legend (when config has >1 series)
└─ sr-only data tableThe React edition composes this surface through the shadcn chart primitive:
ChartContainer responsive frame + injects --color-<key>
└─ ScatterChart recharts scatter plot area
├─ CartesianGrid full grid
├─ XAxis numeric X (linear)
├─ YAxis numeric Y (linear)
├─ ChartTooltip hover card
│ └─ ChartTooltipContent styled tooltip body
└─ Scatter one set of dots per seriesPreview
| weight | Height (cm) |
|---|---|
| 60 | 165 |
| 72 | 178 |
| 55 | 160 |
| 90 | 185 |
| 68 | 172 |
| 80 | 180 |
'use client';import { ScatterChart, type ChartConfig, type ChartDatum,} from '@gremorie/rx-data';const scatterData: ChartDatum[] = [ { weight: 60, height: 165 }, { weight: 72, height: 178 }, { weight: 55, height: 160 }, { weight: 90, height: 185 }, { weight: 68, height: 172 }, { weight: 80, height: 180 },];const scatterConfig: ChartConfig = { height: { label: 'Height (cm)', color: 'var(--chart-1)' },};export function ScatterChartPreview() { return ( <ScatterChart data={scatterData} config={scatterConfig} xKey="weight" /> );}Installation
bash npx gremorie@latest add rx-scatter-chart bash pnpm dlx gremorie@latest add rx-scatter-chart
bash yarn dlx gremorie@latest add rx-scatter-chart
bash bunx --bun gremorie@latest add rx-scatter-chart
Usage
import { ScatterChart } from "@gremorie/rx-data";
import type { ChartConfig, ChartDatum } from "@gremorie/rx-data";
const data: ChartDatum[] = [
{ x: 30, y: 100 },
{ x: 50, y: 200 },
{ x: 70, y: 150 },
{ x: 90, y: 250 },
{ x: 110, y: 175 },
{ x: 130, y: 300 },
];
const config: ChartConfig = {
y: { label: "Value", color: "var(--chart-1)" },
};
export function CorrelationChart() {
return <ScatterChart data={data} config={config} xKey="x" />;
}import { Component } from '@angular/core';
import { ScatterChart } from '@gremorie/ng-data';
import type { ChartConfig, ChartDatum } from '@gremorie/ng-data';
@Component({
selector: 'app-correlation-chart',
imports: [ScatterChart],
template: `<scatter-chart [data]="data" [config]="config" xKey="x" />`,
})
export class CorrelationChartComponent {
readonly data: ChartDatum[] = [
{ x: 30, y: 100 },
{ x: 50, y: 200 },
{ x: 70, y: 150 },
{ x: 90, y: 250 },
{ x: 110, y: 175 },
{ x: 130, y: 300 },
];
readonly config: ChartConfig = {
y: { label: 'Value', color: 'var(--chart-1)' },
};
}
API
<ScatterChart>
The styled wrapper over recharts' ScatterChart, composed on ChartContainer. Renders the responsive frame, a cartesian grid, the numeric X and Y axes, an optional tooltip, and one <Scatter> per config key colored var(--color-<key>).
| Prop | Type | Default | Description |
|---|---|---|---|
data | ChartDatum[] | - | Tabular data. Each row carries the numeric xKey value plus one numeric value per config key. |
config | ChartConfig | - | Maps each Y series key to { label, color }. The color is any CSS color or token, typically "var(--chart-1)" through "var(--chart-5)". ChartContainer injects each as a var(--color-<key>) CSS variable. |
xKey | string | - | Name of the numeric field on each row used as the X axis. Linear, not categorical. |
yAxis | boolean | true | Render the numeric Y axis. Set to false for a minimal, axis-free scatter. |
tooltip | boolean | true | Toggles the hover tooltip. |
className | string | - | Merged onto the ChartContainer. |
Composing with the chart primitive
For full control, compose recharts directly inside ChartContainer using the exported primitives. shadcn ships no scatter block, but the composition follows the same pattern as the other shadcn chart blocks.
| Export | Role |
|---|---|
ChartContainer | Responsive frame; injects per-series --color-<key> vars from config. |
ChartTooltip | recharts Tooltip re-export; pair with ChartTooltipContent. |
ChartTooltipContent | Styled tooltip body. |
ChartLegend | recharts Legend re-export; pair with ChartLegendContent. |
ChartLegendContent | Styled legend body. |
useChart | Hook to read the active config inside a custom child. |
Types
| Type | Shape |
|---|---|
ChartDatum | Record<string, string | number> & { fill?: string } - one row of chart data; the optional fill sets a per-point color. |
ChartConfig | Record<string, { label?: ReactNode; color?: string }> - per-series label and color map. |
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
type ChartConfig,
type ChartDatum,
} from '@gremorie/rx-data';
import { CartesianGrid, Scatter, ScatterChart, XAxis, YAxis } from 'recharts';
const config = {
y: { label: 'Value', color: 'var(--chart-1)' },
} satisfies ChartConfig;
export function Example({ data }: { data: ChartDatum[] }) {
return (
<ChartContainer config={config}>
<ScatterChart
accessibilityLayer
margin={{ left: 12, right: 12, top: 8, bottom: 8 }}
>
<CartesianGrid />
<XAxis
dataKey="x"
type="number"
name="x"
tickLine={false}
axisLine={false}
tickMargin={8}
/>
<YAxis
type="number"
tickLine={false}
axisLine={false}
tickMargin={8}
width={40}
/>
<ChartTooltip
cursor={{ strokeDasharray: '3 3' }}
content={<ChartTooltipContent />}
/>
<Scatter name="y" dataKey="y" fill="var(--color-y)" />
</ScatterChart>
</ChartContainer>
);
}Drop down to this level for bubble charts (size encoded by a third field), per-point coloring via the row's fill, jitter overlays, or a custom legend via ChartLegend + ChartLegendContent.
Composition
xKeymust be numeric. Both axes use recharts'type="number", so the X scale is linear, not a band scale.- Each
configentry becomes one<Scatter>set of dots, colored by itsvar(--color-<key>)variable. The shared Y domain auto-includes every series. - Per-point color is possible by setting a
fillfield on individual rows ofChartDatum; recharts reads it over the series color. - Keep the series count low - two or three before the dots get too dense to read against each other.
The chart auto-sizes to its parent through ChartContainer's responsive frame.
Variations
Single series
| weight | Height (cm) |
|---|---|
| 60 | 165 |
| 72 | 178 |
| 55 | 160 |
| 90 | 185 |
| 68 | 172 |
| 80 | 180 |
<ScatterChart
data={data}
config={{ y: { label: 'Value', color: 'var(--chart-1)' } }}
xKey="x"
/><scatter-chart [data]="data" [config]="config" xKey="x" />The default shape. Reach for a single series when surfacing correlation or density across one numeric axis pair.
Multi-series
| weight | Height (cm) | Target (cm) |
|---|---|---|
| 60 | 165 | 170 |
| 72 | 178 | 176 |
| 55 | 160 | 168 |
| 90 | 185 | 184 |
| 68 | 172 | 174 |
| 80 | 180 | 181 |
const config: ChartConfig = {
height: { label: 'Median', color: 'var(--chart-1)' },
max: { label: 'Max', color: 'var(--chart-2)' },
};
<ScatterChart data={data} config={config} xKey="weight" />;<scatter-chart [data]="data" [config]="config" xKey="weight" />For comparing two distributions against the same X axis. Color tokens carry the series distinction; keep the count at two or three before the dots get too dense to read.
No axis
Set yAxis to false to drop the numeric Y axis for a minimal, axis-free scatter that leans on the tooltip for exact values.
<ScatterChart data={data} config={config} xKey="x" yAxis={false} /><scatter-chart [data]="data" [config]="config" xKey="x" [yAxis]="false" />Accessibility
- recharts'
accessibilityLayeradds keyboard navigation and screen-reader announcements for the plotted series. --chart-1through--chart-5ship with WCAG AA contrast against the card background in both light and dark themes.- Density caveat: dense scatter plots can hide outliers behind clusters. Set a lower
fillOpacityon a custom<Scatter>or jitter slightly to keep individual points legible.