Skip to main content
Gremorie

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 table

The 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 series

Preview

Scatter chart of Height (cm) against weight
weightHeight (cm)
60165
72178
55160
90185
68172
80180
'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>).

PropTypeDefaultDescription
dataChartDatum[]-Tabular data. Each row carries the numeric xKey value plus one numeric value per config key.
configChartConfig-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.
xKeystring-Name of the numeric field on each row used as the X axis. Linear, not categorical.
yAxisbooleantrueRender the numeric Y axis. Set to false for a minimal, axis-free scatter.
tooltipbooleantrueToggles the hover tooltip.
classNamestring-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.

ExportRole
ChartContainerResponsive frame; injects per-series --color-<key> vars from config.
ChartTooltiprecharts Tooltip re-export; pair with ChartTooltipContent.
ChartTooltipContentStyled tooltip body.
ChartLegendrecharts Legend re-export; pair with ChartLegendContent.
ChartLegendContentStyled legend body.
useChartHook to read the active config inside a custom child.

Types

TypeShape
ChartDatumRecord<string, string | number> & { fill?: string } - one row of chart data; the optional fill sets a per-point color.
ChartConfigRecord<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

  1. xKey must be numeric. Both axes use recharts' type="number", so the X scale is linear, not a band scale.
  2. Each config entry becomes one <Scatter> set of dots, colored by its var(--color-<key>) variable. The shared Y domain auto-includes every series.
  3. Per-point color is possible by setting a fill field on individual rows of ChartDatum; recharts reads it over the series color.
  4. 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

Scatter chart of Height (cm) against weight
weightHeight (cm)
60165
72178
55160
90185
68172
80180
<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

Scatter chart of Height (cm), Target (cm) against weight
weightHeight (cm)Target (cm)
60165170
72178176
55160168
90185184
68172174
80180181
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' accessibilityLayer adds keyboard navigation and screen-reader announcements for the plotted series.
  • --chart-1 through --chart-5 ship 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 fillOpacity on a custom <Scatter> or jitter slightly to keep individual points legible.
  • LineChart - reach for LineChart when the X axis is ordered categories, not numeric.
  • BarChart - discrete category comparison.
  • AreaChart - filled magnitude over an ordered domain.

On this page