ComponentAdded in v15.1

Radar Chart

Several series compared across the same axes, as polygons on a polar grid or as polar-area wedges.

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 { WrRadarChart } from 'ngwr/charts/radar-chart';

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

Basic

One value per axis per series. The first axis points up and the rest follow clockwise.

<wr-radar-chart
  [axes]="['Speed', 'Power', 'Range', 'Comfort', 'Price']"
  [series]="[
    { label: 'Model A', data: [80, 65, 70, 90, 55] },
    { label: 'Model B', data: [60, 85, 75, 60, 80] }
  ]"
  [max]="100"
/>
SpeedPowerRangeComfortPrice
  • Model A
  • Model B

Scale

With no max the scale runs from zero to a readable step above the data. A fixed max gets rings on a readable step that divides it: a rating out of 5 has one per point.

<!-- Fitted: 0 to a readable step above the data -->
<wr-radar-chart [axes]="axes" [series]="models" />

<!-- Fixed: a rating out of 5, one ring per point -->
<wr-radar-chart [axes]="skills" [series]="ratings" [max]="5" />
SpeedPowerRangeComfortPrice
  • Model A
  • Model B
DesignFrontendBackendTestingWritingOps
  • Ana
  • Ben

Polar area

With variant set to polar-area, each axis gets a wedge per series. The area of a wedge is its value. A missing value is a missing wedge.

<wr-radar-chart variant="polar-area" [axes]="directions" [series]="wind" toggleableLegend />
directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];

// Hours of wind from each direction. A wedge's area, not its radius, is the value.
wind: WrRadarSeries[] = [
  { label: 'Winter', data: [42, 30, 12, 8, 10, 18, 36, 48] },
  { label: 'Summer', data: [12, 16, 28, 34, 30, 22, 14, 10] },
];
NNEESESSWWNW

Missing values

A missing value, null or a non-finite number, breaks the outline at its axis. The series is drawn open and not filled, so no reading is invented.

<wr-radar-chart [axes]="axes" [series]="survey" [max]="100" />
survey: WrRadarSeries[] = [
  { label: '2025', data: [62, 71, 58, 66, 74] },
  // No Range figure for 2026: the outline breaks there and is not filled.
  { label: '2026', data: [70, 76, null, 72, 79] },
];
SpeedPowerRangeComfortPrice
  • 2025
  • 2026

Toggle series

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

<wr-radar-chart [axes]="axes" [series]="teams" [max]="100" toggleableLegend [(hiddenSeries)]="hidden" />
hidden = signal<readonly number[]>([]);
SpeedPowerRangeComfortPrice

Data table

dataTable adds a table only screen readers reach: a row per axis, a column per series shown. Nothing changes on screen.

<wr-radar-chart [axes]="axes" [series]="models" [max]="100" ariaLabel="Two models compared" dataTable />
SpeedPowerRangeComfortPrice
Two models compared
Model AModel B
Speed8060
Power6585
Range7075
Comfort9060
Price5580
  • Model A
  • Model B

Accessibility

PartBehaviour
Drawing One role="img", named by ariaLabel. The polygons and wedges announce nothing.
NumbersIn the tooltip, which is pointer only, and in the table dataTable adds.
SeriesEach has its own dash as well as its colour, so outlines differ without hue.
Axis namesReal text. A long name is cut with an ellipsis; the tooltip and the table carry it whole.
KeyboardNo tab stop, unless toggleableLegend makes the legend rows buttons.

API

NameDescriptionTypeDefault
axesThe axes' names, clockwise from twelve o'clock. A series takes one value per axis, in this order. Three at least: with fewer the chart draws the grid and no series.readonly string[][]
seriesOne polygon per series. A series with no color takes the next entry from the chart's palette, and each takes the next dash, the first one solid.readonly WrRadarSeries[][]
variantHow the series are drawn. 'polygon' joins each series' values into a polygon, one vertex per axis. 'polar-area' gives each axis an equal-angle wedge per series whose AREA is the value — the radius grows with the square root of the value, so the ink a wedge paints is proportional to what it stands for — with the series overlaid. The legend, the toggle, the tooltip and the data table are the same in both.WrRadarVariant'polygon'
ariaLabelAccessible name of the drawing. The shapes carry no text and the legend has the series names only, so this is where to say what the chart shows — or turn on dataTable. Falls back to radarChart.label, or to radarChart.polarAreaLabel in the polar-area variant, which is also the data table's caption.string | nullnull
maxThe value of the outer ring. 0 fits the scale to the series shown, on a readable step and including zero; a value above 0 fixes it, from zero at the centre — a score out of 100, a rating out of 5 — with its rings on a readable step that divides it (see rings). A value outside a fixed scale is drawn on its edge, and the tooltip and the data table still give its own figure.number0
ringsAbout how many rings the grid draws between the centre and the outer ring, each on a readable step — 1, 2, 2.5 or 5 times a power of ten. A fitted scale aims for this many and rounds its step up onto that ladder. A fixed max takes the step that divides it into the count nearest this one, the fewer on a tie, so a rating out of 5 gets a ring per point and a score out of 100 a ring per 25; only a max that no such step divides, such as 37, is cut into exactly this many equal rings. Whole numbers from 1 to 10.number4
sizeThe drawing's diameter in CSS pixels, at least 120. The axis names sit in a gutter round it, so the chart is wider than this by the gutter on either side; in a narrower container the drawing shrinks to fit.number280
showGridShow the rings, the spokes and the ring values. The axis names stay.booleantrue
showLegendShow the legend under 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 polygon and no dots, it has no row in the tooltip and no column in the data table, and a fitted scale is fitted to the series still shown. The axes do not change, since they belong to the chart rather than to one series. The legend keeps the hidden series' row, struck through, so it can be shown again; the row says "hidden" to a screen reader as well. A position past the end of series is kept and ignored.readonly number[][]
showDotsShow a dot at every value: on the polygon's vertex, or in the polar-area variant on the middle of the wedge's arc, where the value reads against the rings.booleantrue
showAreaFill each closed polygon with its colour, faintly (--wr-radar-chart-area-opacity), under every outline — the name the line chart and the sparkline give the same fill. A series with a missing value is never filled, whatever this says: its outline is open. In the polar-area variant every wedge is filled, since the outline round them always closes, and a missing value is a missing wedge.booleantrue
tooltipShow a tooltip for the axis nearest the pointer: its name, and every series' value on it; an axis no series shown has a value on opens none. Pointer only — the data table is where the same numbers are for a keyboard or a screen reader.booleantrue
valueFormatWrites every number the chart shows: the ring values, the tooltip and the data table. null uses Intl.NumberFormat in LOCALE_ID, with compact ring values (1.2K) unless the full numbers are shorter.((value: number) => string) | nullnull
dataTableRender the chart's figures as a table that only assistive technology reaches: a row per axis, headed by its name, and a column per series shown, every value written the way the tooltip writes it. A missing value is an empty cell. The drawing is one named role="img", which hides everything inside it, so without the table the numbers are nowhere a screen reader can walk. It is rendered beside the drawing, clipped to nothing: it takes no room, draws nothing and holds no tab stop. A hidden series leaves it.booleanfalse

Types

interface WrRadarSeries {
  label: string;
  data: readonly (number | null)[];
  color?: string;
}

type WrRadarVariant = 'polygon' | 'polar-area';
NameDescriptionTypeDefault
WrRadarSeriesOne polygon.interface—
labelrequiredLegend, tooltip and table name.string—
datarequiredOne value per axis, in the order of axes. null, a non-finite or an absent value is missing.readonly (number | null)[]—
colorCSS colour for the outline and fill.stringpalette
WrRadarVariantHow the series are drawn: polygons, or wedges whose area is the value.'polygon' | 'polar-area'—

CSS variables

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

VariableDefaultDeclared on
--wr-radar-chart-area-opacity0.15.wr-radar-chart
--wr-radar-chart-colorvar(--wr-color-on-surface).wr-radar-chart
--wr-radar-chart-crosshair-colorvar(--wr-color-on-surface-muted).wr-radar-chart
--wr-radar-chart-dot-size6px.wr-radar-chart
--wr-radar-chart-font-familyvar(--wr-font-family-base).wr-radar-chart
--wr-radar-chart-gapvar(--wr-space-lg).wr-radar-chart
--wr-radar-chart-grid-colorcolor-mix(in srgb, var(--wr-border-base) 70%, transparent).wr-radar-chart
--wr-radar-chart-grid-width1px.wr-radar-chart
--wr-radar-chart-gutter-x5rem.wr-radar-chart
--wr-radar-chart-gutter-ycalc(var(--wr-radar-chart-label-line-height) + var(--wr-radar-chart-label-gap)).wr-radar-chart
--wr-radar-chart-hover-centervar(--wr-color-surface).wr-radar-chart
--wr-radar-chart-label-colorvar(--wr-color-on-surface).wr-radar-chart
--wr-radar-chart-label-font-sizevar(--wr-text-xs).wr-radar-chart
--wr-radar-chart-label-gapvar(--wr-space-sm).wr-radar-chart
--wr-radar-chart-label-line-heightvar(--wr-text-xs-leading).wr-radar-chart
--wr-radar-chart-label-max-width10rem.wr-radar-chart
--wr-radar-chart-line-width2px.wr-radar-chart
--wr-radar-chart-ring-label-colorvar(--wr-color-on-surface-muted).wr-radar-chart
--wr-radar-chart-ring-label-halovar(--wr-color-surface).wr-radar-chart
--wr-radar-chart-ring-label-offsetvar(--wr-space-sm).wr-radar-chart

Dependencies

See also