Skip to content

Scatter Chart

ChartsSince 0.4.0
import { ScatterChart } from '@absoluteui/components/scatter-chart';
import '@absoluteui/components/scatter-chart/style.css';

Using Angular? See Scatter Chart for Angular.

An accessible SVG scatter plot of one or more series of (x, y) points on linear axes; a size on points makes it a bubble chart (bubble area proportional to size). It provides:

  • keyboard-reachable points (one tab stop) ordered by x within each series, Up/Down between series, with a tooltip on focus and hover;
  • a legend of toggle buttons that show and hide series;
  • an optional crosshair (vertical and horizontal lines) through the hovered or focused point;
  • optional zoom and pan along x (zoom: 'x') or both axes (zoom: 'xy');
  • a generated accessible summary (per-series point counts and x/y ranges) and a data table fallback with the exact values;
  • series that differ by color and marker shape, never by color alone (WCAG 1.4.1).
  • Relationships or correlation between two numeric variables.
  • Clusters and outliers across a few groups (up to about 8 series).
  • A third numeric dimension as bubble size (sizes set on points).
  • Trends over an ordered x shared by all series: use Line Chart.
  • Comparing categories: use Bar Chart or Combo Chart.
  • Distribution of one variable: use Histogram (or Box Plot).
  • Very large point clouds (tens of thousands of points): not a target of this component.

Two groups with named axes, crosshair, and xy zoom

Section titled “Two groups with named axes, crosshair, and xy zoom”
import { ScatterChart, type ScatterChartZoomDetail } from '@absoluteui/components/scatter-chart';
const host = document.createElement('div');
document.body.append(host);
const chart = ScatterChart.create(host, {
label: 'Height and weight',
series: [
{ id: 'a', label: 'Group A', points: [{ x: 160, y: 55 }, { x: 175, y: 72 }, { x: 182, y: 80 }] },
{ id: 'b', label: 'Group B', points: [{ x: 150, y: 48 }, { x: 170, y: 65 }] },
],
xAxis: { label: 'Height (cm)' },
yAxis: { label: 'Weight (kg)' },
crosshair: true,
zoom: 'xy',
});
host.addEventListener('aui-zoom', (event) => {
const { x, y } = (event as CustomEvent<ScatterChartZoomDetail>).detail;
host.dataset.zoomed = String(x !== null || y !== null);
});
chart.update({ zoomRange: { from: 155, to: 180 } });

Bubble chart with labelled points and a size dimension

Section titled “Bubble chart with labelled points and a size dimension”
import { ScatterChart } from '@absoluteui/components/scatter-chart';
const host = document.querySelector<HTMLElement>('#markets');
if (host) {
ScatterChart.create(host, {
label: 'Markets',
series: [{
id: 'm',
label: 'Markets',
color: 4,
points: [
{ x: 2.1, y: 18, size: 120, label: 'North' },
{ x: 3.4, y: 11, size: 60, label: 'South' },
{ x: 1.2, y: 25, size: 300, label: 'West' },
],
}],
xAxis: { label: 'Growth (%)', includeZero: true },
yAxis: { label: 'Margin (%)' },
sizeLabel: 'Revenue (M)',
sizeRange: [6, 30],
dataTable: 'visible',
});
}
import { ScatterChart } from '@absoluteui/components/scatter-chart';
import '@absoluteui/components/scatter-chart/style.css';
const host = document.querySelector<HTMLElement>('#markets');
if (host) {
ScatterChart.create(host, {
label: 'Markets',
series: [{ id: 'm', label: 'Markets', points: [{ x: 2.1, y: 18, size: 120, label: 'North' }, { x: 3.4, y: 11, size: 60, label: 'South' }] }],
xAxis: { label: 'Growth (%)' },
yAxis: { label: 'Margin (%)' },
sizeLabel: 'Revenue (M)',
zoom: 'xy',
});
}
import { ScatterChart } from '@absoluteui/components/scatter-chart';
const host = document.createElement('div');
document.body.append(host);
ScatterChart.create(host, {
label: 'Height and weight',
series: [{ id: 'a', label: 'Group A', points: [{ x: 160, y: 55 }, { x: 175, y: 72 }] }],
xAxis: { label: 'Height (cm)' },
yAxis: { label: 'Weight (kg)' },
});

Export: @absoluteui/components/chart-export (chartToSvg, chartToPng, downloadChart) exports any chart instance to SVG or PNG.

<div class="aui-chart aui-scatter-chart [aui-scatter-chart--bubble] [aui-chart--patterns] [aui-chart--zoomable] [aui-chart--zoomed]">
<div class="aui-chart__header">
<div class="aui-chart__title" id="T">title</div>
<p class="aui-chart__description" id="D">description</p>
<div class="aui-chart__toolbar"> (zoom enabled; hidden otherwise)
<div class="aui-chart__zoom" role="group" aria-label="Zoom">
<button class="aui-chart__tool" aria-label="Zoom in"/> <button class="aui-chart__tool" aria-label="Zoom out" aria-disabled="true"/> <button class="aui-chart__tool" aria-label="Reset zoom" aria-disabled="true"/>
</div>
</div>
</div>
<ul class="aui-chart__legend" aria-label="Legend">
<li class="aui-chart__legend-entry"><button class="aui-chart__legend-item" aria-pressed="true"><svg class="aui-chart__swatch" aria-hidden="true"/>Group A</button></li>
</ul>
<div class="aui-chart__body"> (height: --aui-chart-height)
<svg class="aui-chart__svg" role="group" aria-roledescription="scatter chart" aria-labelledby="T" aria-describedby="D S">
<g class="aui-chart__crosshair" aria-hidden="true"><line class="aui-chart__crosshair-line"/><line class="aui-chart__crosshair-line"/></g> (crosshair: true)
<g class="aui-chart__grid" aria-hidden="true"/> <g class="aui-chart__axis …" aria-hidden="true"/>
<g class="aui-scatter-chart__points"> (clipped to the plot while zoomed)
<g class="aui-scatter-chart__series aui-chart__series--c1">
<path class="aui-chart__mark aui-scatter-chart__point [aui-scatter-chart__bubble]" role="img" aria-label="Group A: Height (cm) 160, Weight (kg) 55" tabindex="0"/>...
</g>
</g>
</svg>
<div class="aui-chart__empty" hidden/> <div class="aui-chart__tooltip" aria-hidden="true" hidden/>
</div>
<p class="aui-chart__summary" id="S" hidden>generated summary</p>
<div class="aui-chart__data"><button class="aui-chart__table-toggle" aria-expanded="false" aria-controls="R">Show data table</button><div class="aui-chart__table-scroll" id="R" role="region"><table class="aui-chart__table">...</table></div></div>
</div>
ScatterChart.create(host: HTMLElement, options: ScatterChartOptions): ScatterChart

Global configuration key: scatterChart (see Configuration).

Option Type Default Description
label string Chart title: visible text and the accessible name of the plot (aria-labelledby). Required.
hideLabel boolean false Visually hide the title; it stays the accessible name.
description string Visible description below the title, also referenced by aria-describedby (text only).
summary string Replaces the generated accessible summary (aria-describedby).
valueFormat Intl.NumberFormatOptions Number format for values in tooltips, labels, the data table, the summary, and axis ticks (ticks use fixed fraction digits).
formatValue (value: number) => string Custom value text; overrides valueFormat everywhere except axis ticks.
hiddenSeries readonly string[] Ids of series hidden initially; update() replaces the hidden set.
series readonly ScatterChartSeries[] Series: { id, label, points: { x: number; y: number; size?: number; label?: string }[], color?: 1-8 }. Ids are unique and non-empty. Points with a non-finite x or y are skipped. Any point with a size makes the chart a bubble chart. Required.
xAxis { label?: string; min?: number; max?: number; tickCount?: number; includeZero?: boolean } X axis title, fixed domain (min < max), approximate tick count (2-20), and zero inclusion (default false). The title also names x in point labels, tooltips, and the table (default “X axis”).
yAxis { label?: string; min?: number; max?: number; tickCount?: number; includeZero?: boolean } Y axis title, fixed domain, tick count, and zero inclusion (default false). The title also names y (default “Y axis”).
sizeLabel string "Size" Name of the size dimension in bubble labels, tooltips, and the table.
sizeRange readonly [number, number] [4,24] Bubble radius in CSS px for the smallest and largest size (each 1-100, min <= max). Area is proportional to size.
xFormat Intl.NumberFormatOptions Number format of x values (ticks, labels, tooltips, table, summary). Default: valueFormat.
zoom 'none' | 'x' | 'xy' "none" Zoom and pan along x or both axes: a Zoom toolbar (Zoom in, Zoom out, Reset zoom), +/= and - and 0 keys on a focused point, Ctrl/Cmd + wheel, drag to pan a zoomed chart, Shift + drag to select a range. Turning it off resets the window.
zoomRange ChartZoomRange | null Visible x window { from, to } in data units; null shows everything. Clamped to the data (minimum span 1/50 of the extent). Applied without an aui-zoom event; use with zoom enabled.
zoomRangeY ChartZoomRange | null Visible y window with zoom: “xy” (ignored otherwise); null shows everything.
legend 'auto' | 'show' | 'hide' "auto" auto: legend when there is more than one series. Entries are toggle buttons. Globally configurable.
dataTable 'toggle' | 'visible' | 'hidden' | 'none' "toggle" Data table fallback with the exact data: behind a Show data table button (built on first open), always visible, visually hidden (screen readers only), or none. Globally configurable.
tooltip boolean true Tooltip on pointer hover and keyboard focus. Globally configurable.
patterns boolean false Texture fills (and dash patterns for lines) so marks never differ by color alone (always on in forced colors). Globally configurable.
height number 300 Plot height in CSS px (integer 120-2000); the width follows the container. Globally configurable.
crosshair boolean false Crosshair lines (vertical and horizontal, aria-hidden) through the hovered or focused point. Globally configurable.
locale string "en-US" Number and message locale. Globally configurable. Inherited from common configuration.
direction 'ltr' | 'rtl' "ltr" rtl mirrors the x axis, puts the value axis on the right, and swaps ArrowLeft/ArrowRight. Globally configurable. Inherited from common configuration.
Property Type Description
host HTMLElement The host element.
element SVGSVGElement The plot (svg role=“group”), named by the title and described by the summary.
summary string The generated (or custom) accessible summary.
hiddenSeries string[] Ids of hidden series, in data order.
zoomRange ChartZoomRange | null Current visible x window, or null.
zoomRangeY ChartZoomRange | null Current visible y window (zoom: “xy”), or null.
Method Description
update(options: Partial<ScatterChartOptions>): void Merge, validate, and re-render. Invalid options throw and keep the previous state. Keyboard focus stays on the same mark when it still exists.
setSeriesVisible(id: string, visible: boolean): void Show or hide a series programmatically; emits no event.
destroy(): void Remove rendering, host classes, listeners, the resize observer, and the configuration subscription.
Event Detail Bubbles Cancelable Description
aui-series-toggle { id: string; visible: boolean; hidden: string[] } Yes No The user toggled a legend entry (pointer or keyboard). Not emitted for update() or setSeriesVisible().
aui-zoom ScatterChartZoomDetail = ChartZoomDetail: { x: ChartZoomRange | null; y: ChartZoomRange | null; reason: 'button' | 'keyboard' | 'wheel' | 'pan' | 'select' | 'reset' } Yes No The user changed the visible window (toolbar, keys, Ctrl/Cmd + wheel, drag pan, Shift + drag selection). x and y are null when that axis shows everything (y is always null with zoom: “x”). Not emitted for the zoom range options or when the window does not change.

All rules live in the aui.components cascade layer, so application styles override them without specificity battles.

Class Purpose
aui-chart Host (shared chart chrome).
aui-scatter-chart Host modifier for this chart type.
aui-chart--patterns patterns option on: textures (and dash patterns) shown.
aui-chart__header / __title / __title--hidden / __description Title and description.
aui-chart__legend / __legend-entry / __legend-item / __legend-item--hidden / __legend-label Legend list and its entries.
aui-chart__swatch aria-hidden legend and tooltip key (marker, dash, texture).
aui-chart__body / __svg / __layer Plot container (height from –aui-chart-height), SVG, and drawing layer.
aui-chart__grid / __gridline / __zero-line / __axis / __axis-line / __tick-label / __axis-title Axes (aria-hidden).
aui-chart__series--c1 ... --c8 Palette slot classes; set –aui-chart-color from color-chart-<n>.
aui-chart__mark / __mark--active / __mark--hover Focusable data mark and its states.
aui-chart__tooltip / __tooltip-title / __tooltip-rows / __tooltip-row / __tooltip-label / __tooltip-value Tooltip (aria-hidden; the focused mark carries the same text).
aui-chart__empty Empty state text (No data, All series are hidden).
aui-chart__summary Hidden summary referenced by aria-describedby.
aui-chart__data / __data--hidden / __table-toggle / __table-scroll / __table / __cell--numeric Data table fallback.
aui-chart--zoomable / aui-chart--zoomed Host modifiers: zoom enabled (touch-action pan-y on the body); a window is applied (grab cursor).
aui-chart__toolbar / __zoom / __tool Header toolbar (hidden while empty), the Zoom button group, and its icon buttons (aria-disabled when unavailable).
aui-chart__crosshair / __crosshair-line aria-hidden crosshair lines drawn under the marks (crosshair option).
aui-chart__brush Range-selection rectangle while Shift + dragging.
aui-scatter-chart--bubble Host modifier while any point has a size (bubble chart).
aui-scatter-chart__points / __series / __point / __bubble / __cursor Points layer (clipped while zoomed), series group, point marker, translucent bubble, and the proxy mark of dense data.

Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.

--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-chart-1 | --aui-color-chart-2 | --aui-color-chart-3 | --aui-color-chart-4 | --aui-color-chart-5 | --aui-color-chart-6 | --aui-color-chart-7 | --aui-color-chart-8 | --aui-color-chart-axis | --aui-color-chart-grid | --aui-color-focus-ring | --aui-color-hover | --aui-color-link | --aui-color-surface | --aui-color-surface-sunken | --aui-color-text | --aui-color-text-muted | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-size-xs | --aui-font-weight-medium | --aui-font-weight-regular | --aui-font-weight-semibold | --aui-line-height-normal | --aui-line-height-tight | --aui-radius-md | --aui-radius-sm | --aui-shadow-md | --aui-space-1 | --aui-space-2 | --aui-space-3 | --aui-tooltip-max-width | --aui-touch-target-min

interface ScatterChartPoint { x: number; y: number; size?: number; label?: string }
interface ScatterChartSeries { id: string; label: string; points: readonly ScatterChartPoint[]; color?: ChartColor }
interface ScatterChartAxis { readonly label?: string; readonly min?: number; readonly max?: number; readonly tickCount?: number; readonly includeZero?: boolean }
interface ScatterChartConfig { legend: ChartLegendMode; dataTable: ChartTableMode; tooltip: boolean; patterns: boolean; height: number; crosshair: boolean }
type ChartZoomMode = 'none' | 'x' | 'xy';
interface ChartZoomRange { readonly from: number; readonly to: number }
interface ScatterChartOptions extends ChartCommonOptions, Partial<ScatterChartConfig> {
series: readonly ScatterChartSeries[];
xAxis?: ScatterChartAxis;
yAxis?: ScatterChartAxis;
sizeLabel?: string;
sizeRange?: readonly [number, number];
xFormat?: Intl.NumberFormatOptions;
zoom?: ChartZoomMode;
zoomRange?: ChartZoomRange | null;
zoomRangeY?: ChartZoomRange | null;
}
type ScatterChartSeriesToggleDetail = { id: string; visible: boolean; hidden: string[] };
type ScatterChartZoomDetail = { x: ChartZoomRange | null; y: ChartZoomRange | null; reason: 'button' | 'keyboard' | 'wheel' | 'pan' | 'select' | 'reset' };

Pattern: SVG chart as a named, described group (role=“group” with aria-roledescription) of role=“img” data marks with roving focus; data table fallback (native table). Follows the WAI Complex Images tutorial (short name plus long description) and the roving tabindex technique of WAI-ARIA APG.

Key Context Action
ArrowLeft / ArrowRight Point focused Previous / next point of the same series in x order (then y); mirrored in RTL.
ArrowUp / ArrowDown Point focused, more than one visible series Point at the nearest x-order position in the previous / next visible series. With one series: previous / next point.
Home / End Point focused First / last point of the series (x order).
PageUp / PageDown Point focused Ten points back / forward.
Escape Tooltip visible Hides the tooltip without moving focus (WCAG 1.4.13); it returns on the next move.
Tab / Shift+Tab Any Zoom buttons (zoom enabled), legend buttons, then one tab stop for the plot (the active point), then the Show data table button and table region.
Enter / Space Legend button Shows or hides the series (native button).
+ / = Mark focused, zoom enabled Zoom in around the focused mark.
- Mark focused, zoom enabled Zoom out around the focused mark.
0 Mark focused, zoom enabled Reset zoom (show all data).
Enter / Space Zoom button Zoom in, zoom out, or reset (native button; ignored while aria-disabled).
Element Role
svg.aui-chart__svg group with aria-roledescription (localized chart type), named by the title
data marks img with an aria-label: point name or series, x and y with their axis names (and size for bubbles)
legend list (ul) named “Legend”; entries are toggle buttons (aria-pressed)
zoom toolbar (zoom enabled) group named “Zoom” of native buttons “Zoom in”, “Zoom out”, “Reset zoom”
axes, decorative dense-point paths, tooltip, crosshair, selection brush aria-hidden (decorative duplicates of the accessible data)
data table table (native) with caption, column headers, and row headers; wide tables scroll in a focusable region
Attribute Element Value
aria-labelledby svg id of the visible (or visually hidden) title
aria-describedby svg description id (when provided) and the generated summary id
aria-roledescription svg Localized “scatter chart” or “bubble chart”
aria-label each mark Localized “{name}: {xAxis} {x}, {yAxis} {y}” (bubbles add “, {sizeAxis} {size}”); name is “{label}, {series}” for labelled points, else the series label. Example: “Group A: Height (cm) 160, Weight (kg) 55”
tabindex active mark 0 on exactly one mark (roving); other marks have none
aria-pressed legend button true while the series is visible
aria-expanded / aria-controls Show data table button Table open state and the table region id
aria-disabled zoom buttons true while the action is unavailable (Zoom in at the minimum span, Zoom out and Reset zoom when not zoomed); the button stays focusable

Roving focus: one point is in the tab sequence and remembers the last visited point across re-renders (resize, update, zoom) while it stays in view. Points outside the zoom window are not focusable. Toggling a legend entry keeps focus on its button; toggling the table keeps focus on the table button; zoom buttons stay focusable while aria-disabled.

Criterion Level Note
1.1.1 Non-text Content A
1.3.1 Info and Relationships A
1.4.1 Use of Color A
1.4.3 Contrast (Minimum) AA
1.4.10 Reflow AA
1.4.11 Non-text Contrast AA
1.4.13 Content on Hover or Focus AA
2.1.1 Keyboard A
2.4.3 Focus Order A
2.4.7 Focus Visible AA
4.1.2 Name, Role, Value A
2.5.1 Pointer Gestures A

Automated test results: Accessibility and compliance.

  • The generated summary names the chart type, series and point counts, and per series its point count and x and y ranges, plus hidden series.
  • Meaning never depends on color alone: each series has its own marker shape, repeated in the legend key.
  • Forced colors: marks use CanvasText (bubbles and outlines Canvas/CanvasText) and keep shapes and textures; focus uses Highlight.
  • No animation: nothing moves on render; hover and focus emphasis transitions are removed under prefers-reduced-motion and animation: none.
  • Above 600 visible points, points are virtual: two proxy marks alternate focus so every move is announced. Browse-mode users read the exact values from the data table.
  • Zoom changes are announced politely (“Showing {from} to {to}.” or “Showing all data.”) and emitted as aui-zoom. Pointer gestures (Ctrl/Cmd + wheel, drag pan, Shift + drag selection) have keyboard and toolbar equivalents.
  • The crosshair (crosshair option) is aria-hidden and follows both hover and keyboard focus; it hides when focus and the pointer leave.
  • Manual screen-reader verification (NVDA, JAWS, VoiceOver, TalkBack) is pending.
  • aria-roledescription support varies; screen readers without it announce “group”.

default, bubble (any point has a size), empty (“No data”), all series hidden (“All series are hidden”), series hidden, point focused (tooltip), hovered (nearest point within 12 px), crosshair shown, zoomed, panning or selecting (pointer drag), table open, dense (virtual points above 600 visible points).

From Trigger To
any legend button (click, Enter, Space) series hidden or shown; aui-series-toggle emitted; domains rescale to visible series
plot not focused Tab active point focused, tooltip (and crosshair) shown
point focused arrow keys, Home, End, PageUp, PageDown another point focused
tooltip visible Escape tooltip hidden, focus unchanged
not zoomed Zoom in, +/=, Ctrl/Cmd + wheel up, Shift + drag zoomed; “Showing {from} to {to}.” announced; aui-zoom emitted
zoomed Zoom out, -, drag window widened or moved; announced; aui-zoom emitted
zoomed Reset zoom, 0 all data shown (“Showing all data.”); aui-zoom with x: null, y: null
table closed Show data table table built and shown
any container resize re-render at the new width; focus kept on the same point
  • The summary names the type, series and point counts, and per series its point count and x and y ranges, plus hidden series.
  • With more than 600 visible points, points are virtual: two proxy marks alternate focus so each move is announced; browse-mode users read values from the data table.
  • Series differ by marker shape (repeated in the legend key); forced colors keep shapes and use CanvasText/Canvas, focus uses Highlight.
  • Zoom changes are announced politely; every pointer gesture has a keyboard and toolbar equivalent (WCAG 2.1.1, 2.5.1). The crosshair follows hover and keyboard focus and is aria-hidden.
  • The tooltip meets WCAG 1.4.13: shown on focus and hover, dismissible with Escape, hoverable, persistent. Nothing animates.
  • Manual screen-reader verification is pending.

The width follows the container (ResizeObserver); the height is height. Tick counts follow the plot size; the scales are inset by the largest mark radius so marks never cover the axes. Reflows at 320 CSS px; wide data tables scroll in a focusable region.

direction: 'rtl' mirrors the x axis (smallest x at the right), puts the y axis on the right, and swaps ArrowLeft/ArrowRight; drag panning follows the mirrored axis. The legend, tooltip, and table follow the document direction.

Series colors come from color-chart-1..8 by palette slot (series position, or color). Bubbles are translucent with a solid outline in the series color so overlapping bubbles stay visible. Gridlines use color-chart-grid, axes and the crosshair color-chart-axis.

configureAbsoluteUI({ components: { scatterChart: { crosshair: true, dataTable: 'hidden', height: 360 } } });

Changes apply to existing instances immediately.

Instance options override global and theme defaults. All options are dynamic. zoom, zoomRange, and zoomRangeY are instance-only.

Not applicable: numeric axes only; no dates are formatted.

No icons option. Markers are drawn shapes. The zoom buttons render the icons plus, minus, and refresh through @absoluteui/icons; a global icon provider or registry entry for those names replaces them in every component that uses them.

All text uses textContent; SVG is built with createElementNS. Colors are classes; the plot height and tooltip position are written through the CSSOM. No innerHTML, style attributes, or inline handlers: compatible with style-src 'self' and require-trusted-types-for 'script'.

Renders the given data only; no persistence, network access, or telemetry. Validation errors name the option, never its value.

Budget: ScatterChart.create with 2,000 points under 60 ms in headless Chromium, including the first render (e2e performance test, tests/e2e/perf-r3.spec.ts). Above 600 visible points, points are virtual (two proxy marks plus one decorative path per series); hover uses a spatial hash; the data table is built only when opened in toggle mode.

Tested with 2,000 points. DOM size is independent of the point count above 600 visible points.

  • No series, or no points at all: “No data”. Visible series without any finite point: “No data”.
  • Every series hidden: “All series are hidden”.
  • All sizes equal: every bubble uses the middle of sizeRange.
  • Points without size in a bubble chart are drawn as regular markers.
  • The data table lists every series (including hidden ones); unlabelled points are named “Point {n}”.
Code Category Cause
SCATTER_CHART_OPTIONS configuration Missing label; series ids not unique or empty; points without numeric x/y; negative size; invalid axis options; sizeRange outside 1-100 or reversed; invalid zoom or zoom ranges.
CFG_INVALID_VALUE / CFG_UNKNOWN_OPTION configuration Invalid or unknown configuration (for example height outside 120-2000).

A failed construction leaves the host untouched; a failed update() keeps the previous state.

  • Linear axes only.
  • Keyboard order within a series is by x (then y), not data order.
  • Axis label widths are estimated (about 0.6 em per character).
  • Manual screen-reader verification is pending.
  • Logarithmic or time axes.
  • Trend lines, regression, density contours.
  • Lasso selection; linked brushing across charts.
  • HTML in labels or tooltips.