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.

Preview

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" />;
}

Angular edition planned for a follow-up release; it mirrors this component's anatomy.

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.
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

<ScatterChart
  data={data}
  config={{ y: { label: 'Value', color: 'var(--chart-1)' } }}
  xKey="x"
/>

The default shape. Reach for a single series when surfacing correlation or density across one numeric axis pair.

Multi-series

const config: ChartConfig = {
  height: { label: 'Median', color: 'var(--chart-1)' },
  max: { label: 'Max', color: 'var(--chart-2)' },
};

<ScatterChart 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.

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