ComponentAdded in v15.1

Scatter Chart

Points on two numeric axes. An optional size per point makes it a bubble chart.

Installation

Import the class, and @use the entry point in your global styles: without it the component renders unstyled.

import { Component } from '@angular/core';
import { WrScatterChart } from 'ngwr/charts/scatter-chart';

@Component({ imports: [WrScatterChart] })
export class MyComponent {}

Basic

Neither axis is forced to include zero. Each fits its data and snaps to round numbers.

<wr-scatter-chart
  xLabel="Price"
  yLabel="Rating"
  [series]="[{ label: 'Headphones', data: [{ x: 49, y: 3.6 }, { x: 129, y: 4.2 }] }]"
/>
  • Headphones
Rating
Price

Several series

Each series takes the next palette colour and the next marker shape, so the shape tells them apart too.

<wr-scatter-chart xLabel="Weight, kg" yLabel="Battery, h" [series]="devices" />
  • Laptops
  • Tablets
  • Phones
Battery, h
Weight, kg

Bubbles

size is drawn as the marker's area: the largest at maxRadius, none under 4px. Bubbles are see-through, since they overlap. label names a point.

<wr-scatter-chart
  xLabel="Visitors a day"
  yLabel="Revenue, k$"
  sizeLabel="Floor area, m²"
  [series]="stores"
/>
stores: WrScatterSeries[] = [
  {
    label: 'City centre',
    data: [
      { x: 1450, y: 62, size: 320, label: 'Harbour' },
      { x: 1720, y: 71, size: 410, label: 'Old Town' },
    ],
  },
];
  • City centre
  • Suburbs
Revenue, k$
Visitors a day

Number format

Numbers follow LOCALE_ID. valueFormat replaces it, and its second argument says which number it writes: 'x', 'y' or 'size'.

<wr-scatter-chart xLabel="Price" yLabel="Rating" [series]="products" [valueFormat]="format" />
const usd = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 });

format = (value: number, axis: WrScatterAxis): string =>
  axis === 'x' ? usd.format(value) : value.toFixed(1) + ' ★';
  • Headphones
Rating
Price

Toggle series

toggleableLegend makes each legend row a button. A hidden series leaves the points, both axes, the tooltip and the data table.

<wr-scatter-chart [series]="devices" toggleableLegend [(hiddenSeries)]="hidden" />
hidden = signal<readonly number[]>([]);
Battery, h
Weight, kg

Data table

dataTable renders every value as a table only screen readers reach: a group per series, a row per point. Nothing changes on screen.

<wr-scatter-chart ariaLabel="Weight against battery life" dataTable [series]="devices" />
  • Laptops
  • Tablets
  • Phones
Battery, h
Weight, kg
Weight against battery life
Weight, kgBattery, h
Laptops11.214
21.412
31.610
42.17
52.46
Tablets10.4511
20.510
30.612
40.689
Phones10.1720
20.1923
30.2118
40.2326

Accessibility

PartBehaviour
PlotOne role="img", named by ariaLabel. No tab stop.
ValuesOnly in the tooltip, unless dataTable is on.
SeriesTold apart by marker shape as well as colour.
TooltipPointer only. Escape closes it.
Forced coloursPoints keep their colours. Their ring takes the page colour.

Many points

Hover measures every point. Keep a chart to a few thousand points, or bin them first.

API

NameDescriptionTypeDefault
seriesOne entry per series. A series with no color takes the next entry from the chart's palette, and every series takes the next marker shape, so several series are told apart unconfigured.readonly WrScatterSeries[][]
ariaLabelAccessible name of the chart. The legend carries the series NAMES only — the values are nowhere in text unless dataTable puts them there — so say what the chart shows. Falls back to scatterChart.label ("Scatter chart").string | nullnull
xLabelThe x axis' name. Drawn under the axis only when given; either way it names the x row of the tooltip and the x column of the data table, which fall back to scatterChart.x ("X").string | nullnull
yLabelThe y axis' name. Drawn above the axis only when given; either way it names the y row of the tooltip and the y column of the data table, which fall back to scatterChart.y ("Y").string | nullnull
sizeLabelWhat a point's size measures. It names the size row of the tooltip and the size column of the data table, which appear only when a point has a size, and falls back to scatterChart.size ("Size").string | nullnull
valueFormatWrites every number the chart shows — the axis ticks, the tooltip and the data table — and is told which number it is writing: 'x', 'y' or 'size', so the two axes can carry different units. A (value) => string written for another chart fits too. null uses Intl.NumberFormat in LOCALE_ID, with compact ticks (1.2K, 3.4M) unless the full numbers are shorter.((value: number, axis: WrScatterAxis) => string) | nullnull
heightThe plot's height in px, at least 80.number240
showGridShow the gridlines and the tick labels of both axes.booleantrue
showLegendShow the legend above the chart.booleantrue
toggleableLegendMake each legend row a toggle button that shows and hides its series, through hiddenSeries. A row is a <button aria-pressed>, pressed while its series is shown, so the legend becomes one tab stop per series.booleanfalse
hiddenSeriesThe positions in series of the series that are hidden. Positions rather than labels, since two series may share a label. A toggleable legend writes it, and a host may bind it with or without one: [(hiddenSeries)]. A hidden series is left out of everything that reads its values: it draws no points, the tooltip cannot land on them, the data table drops its rows, and both axes and the bubble scale are fitted to the series still shown, so hiding an outlier lets the rest fill the plot. Its legend row stays, struck through, so it can be shown again. With every series hidden the plot is the empty 0 to 1 frame. A position past the end of series is kept and ignored.readonly number[][]
tooltipShow a tooltip with the series, x, y and size of the point under the pointer. Pointer only.booleantrue
dataTableRender every point's values as a table only assistive technology reaches, beside the drawing: one group of rows per series shown, headed by the series' name, a row per point, and a column for x, for y and, when a point has one, for size. The drawing is one named image, so without it the values are nowhere a screen reader can walk.booleanfalse
maxRadiusThe radius, in px, the largest size shown is drawn at. Every other sized point is scaled by AREA against it — a point of half the size has half the area, not half the radius — and none is drawn under 4px. At least 4.number20

Types

interface WrScatterSeries {
  label: string;
  data: readonly WrScatterPoint[];
  color?: string;
}

interface WrScatterPoint {
  x: number;
  y: number;
  size?: number;
  label?: string;
}

type WrScatterAxis = 'x' | 'y' | 'size';
NameDescriptionTypeDefault
WrScatterSeriesOne series of points.interface—
labelrequiredThe series name: legend, tooltip, data table.string—
datarequiredThe points, in any order.readonly WrScatterPoint[]—
colorAny CSS colour.stringpalette
WrScatterPointOne point.interface—
xrequiredPosition on the x axis. A non-finite point is not drawn.number—
yrequiredPosition on the y axis.number—
sizeDrawn as the marker's area. The largest is drawn at maxRadius.numberundefined
labelThe point's name, in the tooltip and as its data table row.stringundefined
WrScatterAxisWhich number valueFormat writes.'x' | 'y' | 'size'—

CSS variables

Set these on the component's selector or a wrapper, not on :root: the defaults are declared on ngwr/charts/scatter-chart's own element.

VariableDefaultDeclared on
--wr-scatter-chart-bubble-opacity0.7.wr-scatter-chart
--wr-scatter-chart-colorvar(--wr-color-on-surface).wr-scatter-chart
--wr-scatter-chart-font-familyvar(--wr-font-family-base).wr-scatter-chart
--wr-scatter-chart-grid-colorcolor-mix(in srgb, var(--wr-border-base) 70%, transparent).wr-scatter-chart +1 variant override
--wr-scatter-chart-halo-width2px.wr-scatter-chart
--wr-scatter-chart-legend-margin-bottomvar(--wr-space-md).wr-scatter-chart
--wr-scatter-chart-plot-inset-xvar(--wr-space-md).wr-scatter-chart
--wr-scatter-chart-plot-inset-yvar(--wr-space-sm).wr-scatter-chart
--wr-scatter-chart-point-opacity1.wr-scatter-chart +1 variant override
--wr-scatter-chart-point-ringvar(--wr-color-surface).wr-scatter-chart +1 variant override
--wr-scatter-chart-point-ring-width1px.wr-scatter-chart
--wr-scatter-chart-tick-colorvar(--wr-color-on-surface-muted).wr-scatter-chart
--wr-scatter-chart-tick-font-sizevar(--wr-text-xs).wr-scatter-chart
--wr-scatter-chart-tick-gapvar(--wr-space-xs).wr-scatter-chart
--wr-scatter-chart-tick-line-heightvar(--wr-text-xs-leading).wr-scatter-chart
--wr-scatter-chart-title-colorvar(--wr-color-on-surface-muted).wr-scatter-chart
--wr-scatter-chart-title-font-sizevar(--wr-text-xs).wr-scatter-chart
--wr-scatter-chart-title-font-weightvar(--wr-font-weight-medium).wr-scatter-chart
--wr-scatter-chart-title-gapvar(--wr-space-xs).wr-scatter-chart

Dependencies

See also