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

About

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.

Radar chart
Opus 5: Latency 62, Accuracy 94, Cost 48, Context 96, Tool use 92, Safety 90Haiku 4.5: Latency 95, Accuracy 78, Cost 92, Context 70, Tool use 74, Safety 86LatencyAccuracyCostContextTool useSafety
  • Opus 5
  • Haiku 4.5
Props
tsx
<RadarChart
  axes={axes}
  series={series}
  rings={4}
  max={100}
/>

Examples

Two models on six axes

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

PropTypeDefaultDescription
axesRadarAxis[]required{ key, label, max? } and { name, values: Record<key, number> }.
seriesRadarSeries[]required{ key, label, max? } and { name, values: Record<key, number> }.
maxnumber100Shared ceiling. Axes on different scales produce a shape that means nothing; per-axis max exists for when the units genuinely differ.
sizenumber260—
ringsnumber4Rings drawn behind the shapes.
legendbooleantrue—
fillOpacitynumber0.18Lower it when shapes overlap heavily.
valueFormat(value: number) => stringDEFAULT_FORMAT—
emptyLabelstring'No data.'—
labelstring'Radar chart'—
toread 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.

FieldTypeDescription
keystring—
labelstring—
max?numberPer-axis maximum. Defaults to the chart's max.

RadarSeries

FieldTypeDescription
namestring—
valuesRecord<string, number>—
color?string—

Behaviour

TopicDetailDescription
uniform scalingsquare viewBoxNo preserveAspectRatio: none — a sheared radar is unreadable.