Radar Chart
Several measures for one subject on axes radiating from a centre. Good for recognising a profile’s shape; documented plainly as the wrong chart when the reader needs to compare values.
src/components/ui/radar-chart.tsxAbout
From the component's own source, where it was written.
Several measures for one subject, on axes radiating from a centre.
**What it is genuinely good at** is comparing two or three profiles across the same handful of dimensions — this candidate against the role, this service against its SLO, this model against that one — where the *shape* is the thing you remember and any single axis is secondary.
**What it is bad at, stated plainly, because it is usually the wrong chart.** Area grows with the square of the value, so a profile scoring 20% higher on every axis looks about 44% "bigger" and reads as a much larger gap than there is. The order of the axes is arbitrary but changes the shape completely, so two charts of the same data can look unrelated. And comparing lengths along different radial directions is measurably harder than comparing bars on a shared baseline. **If the reader needs to compare values, use a grouped bar chart.** Use this when they need to recognise a shape.
Every axis is normalised to a common max by default, because axes with different scales on one radar produce a shape that means nothing at all — per-axis maxima are available through axes[].max when the units genuinely differ and you accept that trade.
The viewBox is square with uniform scaling, so the polygon is never sheared by its container's aspect ratio.
Install
npx astralyx-ui add radar-chart
Usage
import { RadarChart } from '@/components/ui/radar-chart'
<RadarChart axes={axes} series={series} max={100} />Composer
Change the props and the source below follows.
- Opus 5
- Haiku 4.5
<RadarChart
axes={axes}
series={series}
rings={4}
max={100}
/>Examples
Two models on six axes
<RadarChart axes={axes} series={[opus, haiku]} />API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
RadarChart
Extends Omit<ComponentProps<'figure'>, 'height'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| axes | RadarAxis[] | required | { key, label, max? } and { name, values: Record<key, number> }. |
| series | RadarSeries[] | required | { key, label, max? } and { name, values: Record<key, number> }. |
| max | number | 100 | Shared ceiling. Axes on different scales produce a shape that means nothing; per-axis max exists for when the units genuinely differ. |
| size | number | 260 | — |
| rings | number | 4 | Rings drawn behind the shapes. |
| legend | boolean | true | — |
| fillOpacity | number | 0.18 | Lower it when shapes overlap heavily. |
| valueFormat | (value: number) => string | DEFAULT_FORMAT | — |
| emptyLabel | string | 'No data.' | — |
| label | string | 'Radar chart' | — |
| to | read the docs | — | Area grows with the square of the value, so a 20% better profile looks 44% bigger. Axis order is arbitrary but changes the shape. For comparing values, a grouped bar chart is measurably better. |
Types
RadarAxis
Several measures for one subject, on axes radiating from a centre.
| Field | Type | Description |
|---|---|---|
| key | string | — |
| label | string | — |
| max? | number | Per-axis maximum. Defaults to the chart's max. |
RadarSeries
| Field | Type | Description |
|---|---|---|
| name | string | — |
| values | Record<string, number> | — |
| color? | string | — |
Behaviour
| Topic | Detail | Description |
|---|---|---|
| uniform scaling | square viewBox | No preserveAspectRatio: none — a sheared radar is unreadable. |