# Scatter Chart

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

Source: https://ngwr.dev/charts/scatter-chart  
Added in v15.1

## Installation

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

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

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

```scss
@use 'ngwr/charts/scatter-chart';
```

## Basic

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

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

## Several series

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

```angular-html
<wr-scatter-chart xLabel="Weight, kg" yLabel="Battery, h" [series]="devices" />
```

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

```angular-html
<wr-scatter-chart
  xLabel="Visitors a day"
  yLabel="Revenue, k$"
  sizeLabel="Floor area, m²"
  [series]="stores"
/>
```

```angular-ts
stores: WrScatterSeries[] = [
  {
    label: 'City centre',
    data: [
      { x: 1450, y: 62, size: 320, label: 'Harbour' },
      { x: 1720, y: 71, size: 410, label: 'Old Town' },
    ],
  },
];
```

## Number format

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

```angular-html
<wr-scatter-chart xLabel="Price" yLabel="Rating" [series]="products" [valueFormat]="format" />
```

```angular-ts
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) + ' ★';
```

## Toggle series

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

```angular-html
<wr-scatter-chart [series]="devices" toggleableLegend [(hiddenSeries)]="hidden" />
```

```angular-ts
hidden = signal<readonly number[]>([]);
```

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

```angular-html
<wr-scatter-chart ariaLabel="Weight against battery life" dataTable [series]="devices" />
```

## Accessibility

| Part | Behaviour |
| --- | --- |
| Plot | One `role="img"`, named by `ariaLabel`. No tab stop. |
| Values | Only in the tooltip, unless `dataTable` is on. |
| Series | Told apart by marker shape as well as colour. |
| Tooltip | Pointer only. `Escape` closes it. |
| Forced colours | Points 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

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `series` | One 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[]` | `[]` |
| `ariaLabel` | Accessible 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 \| null` | `null` |
| `xLabel` | The 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 \| null` | `null` |
| `yLabel` | The 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 \| null` | `null` |
| `sizeLabel` | What 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 \| null` | `null` |
| `valueFormat` | Writes 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) \| null` | `null` |
| `height` | The plot's height in px, at least 80. | `number` | `240` |
| `showGrid` | Show the gridlines and the tick labels of both axes. | `boolean` | `true` |
| `showLegend` | Show the legend above the chart. | `boolean` | `true` |
| `toggleableLegend` | Make 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. | `boolean` | `false` |
| `hiddenSeries` | The 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[]` | `[]` |
| `tooltip` | Show a tooltip with the series, x, y and size of the point under the pointer. Pointer only. | `boolean` | `true` |
| `dataTable` | Render 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. | `boolean` | `false` |
| `maxRadius` | The 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. | `number` | `20` |

## Types

```angular-ts
interface WrScatterSeries {
  label: string;
  data: readonly WrScatterPoint[];
  color?: string;
}

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

type WrScatterAxis = 'x' | 'y' | 'size';
```

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `WrScatterSeries` | One series of points. | `interface` | — |
| `label`required | The series name: legend, tooltip, data table. | `string` | — |
| `data`required | The points, in any order. | `readonly WrScatterPoint[]` | — |
| `color` | Any CSS colour. | `string` | `palette` |
| `WrScatterPoint` | One point. | `interface` | — |
| `x`required | Position on the x axis. A non-finite point is not drawn. | `number` | — |
| `y`required | Position on the y axis. | `number` | — |
| `size` | Drawn as the marker's area. The largest is drawn at `maxRadius`. | `number` | `undefined` |
| `label` | The point's name, in the tooltip and as its data table row. | `string` | `undefined` |
| `WrScatterAxis` | Which 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.

| Variable | Default | Declared on |
| --- | --- | --- |
| `--wr-scatter-chart-bubble-opacity` | `0.7` | `.wr-scatter-chart` |
| `--wr-scatter-chart-color` | `var(--wr-color-on-surface)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-font-family` | `var(--wr-font-family-base)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-grid-color` | `color-mix(in srgb, var(--wr-border-base) 70%, transparent)` | `.wr-scatter-chart` +1 variant override |
| `--wr-scatter-chart-halo-width` | `2px` | `.wr-scatter-chart` |
| `--wr-scatter-chart-legend-margin-bottom` | `var(--wr-space-md)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-plot-inset-x` | `var(--wr-space-md)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-plot-inset-y` | `var(--wr-space-sm)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-point-opacity` | `1` | `.wr-scatter-chart` +1 variant override |
| `--wr-scatter-chart-point-ring` | `var(--wr-color-surface)` | `.wr-scatter-chart` +1 variant override |
| `--wr-scatter-chart-point-ring-width` | `1px` | `.wr-scatter-chart` |
| `--wr-scatter-chart-tick-color` | `var(--wr-color-on-surface-muted)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-tick-font-size` | `var(--wr-text-xs)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-tick-gap` | `var(--wr-space-xs)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-tick-line-height` | `var(--wr-text-xs-leading)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-title-color` | `var(--wr-color-on-surface-muted)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-title-font-size` | `var(--wr-text-xs)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-title-font-weight` | `var(--wr-font-weight-medium)` | `.wr-scatter-chart` |
| `--wr-scatter-chart-title-gap` | `var(--wr-space-xs)` | `.wr-scatter-chart` |

## Dependencies

| Built on | [Chart Legend](https://ngwr.dev/charts/chart-legend), [Popover](https://ngwr.dev/reference/components/popover) |
| --- | --- |

## See also

- [Line Chart](https://ngwr.dev/charts/line-chart) — One or more series of values as lines or as an area chart, overlaid or stacked.
- [Bar Chart](https://ngwr.dev/charts/bar-chart) — Bars for one or several series, grouped or stacked, standing up or lying along a row, with lines over them.
- [Box Plot](https://ngwr.dev/charts/boxplot-chart) — How the values of several groups are spread: the median, the middle half, the range and the outliers of each, side by side.
- [Radar Chart](https://ngwr.dev/charts/radar-chart) — Several series compared across the same axes, as polygons on a polar grid or as polar-area wedges.
- [Colors](https://ngwr.dev/guides/tokens/colors) — The --wr-color-* tokens, and which one to use for fills, text and borders.
- [Chart Legend](https://ngwr.dev/charts/chart-legend) — A chart's key: a swatch, a name and a value per series.
- [Popover](https://ngwr.dev/reference/components/popover) — Show a template, or a text tooltip, next to its trigger.
