A landscape spread of up to eleven small illustrations of one subject, each a different graphic form, in three bands of unequal panels: a statement in large type, spokes round an icon and a network of circles; a smooth trend with its peak labelled, nested squares and a slope chart; a pill ranking, a treemap, a tile map and sized circles; and a closing row of icon statements.
Radial spokes
Draws one spoke per row radiating from a centre disc, each as long as its value, with the name and value set on an outer ring.
- Use when
- A poster of 4 to 12 effects, causes or attributes of one subject, which sits in the centre as an icon or a short label: what a household's energy goes on, the side effects of one drug, the scores of one product.
- Avoid when
- Precise comparison or a ranking (use bar chart or pill rank); a dimension that is a cycle, such as hours or months (use radial bar chart); more than 12 rows (use bar chart); several subjects compared on the same attributes (use small multiples or heatmap).
Preview
import { RadialSpokes } from "insightcharts";
const data = [
{ use: "Space heating", share: 42 },
{ use: "Hot water", share: 17 },
{ use: "Cooking", share: 6 },
{ use: "Fridge and freezer", share: 8 },
{ use: "Laundry", share: 7 },
{ use: "Lighting", share: 5 },
{ use: "Screens and computers", share: 9 },
{ use: "Everything else", share: 6 },
];
export function Example() {
return (
<RadialSpokes
data={data}
name="use"
value="share"
format={"{value}%"}
icon="house"
highlight="Space heating"
title="Space heating uses 42% of a home's energy"
subtitle="Share of household energy by end use, a typical home in a cool climate"
note="Illustrative figures"
/>
);
}{
"type": "radial-spokes",
"data": [
{ "use": "Space heating", "share": 42 },
{ "use": "Hot water", "share": 17 },
{ "use": "Cooking", "share": 6 },
{ "use": "Fridge and freezer", "share": 8 },
{ "use": "Laundry", "share": 7 },
{ "use": "Lighting", "share": 5 },
{ "use": "Screens and computers", "share": 9 },
{ "use": "Everything else", "share": 6 }
],
"name": "use",
"value": "share",
"format": "{value}%",
"icon": "house",
"highlight": "Space heating",
"title": "Space heating uses 42% of a home's energy",
"subtitle": "Share of household energy by end use, a typical home in a cool climate",
"note": "Illustrative figures"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Composition
Used in
2 infographics use radial spokes.
Infographics
2A poster with one subject in the middle of the sheet: a wheel of spokes round an icon (radial-spokes), two to four large figures standing either side of it, and a bottom row with the same subject's surroundings on concentric rings (orbit-chart) and a ranking as centred pills (pill-rank).
Installation
$ pnpm dlx shadcn@latest add @insightcharts/radial-spokesThe CLI copies the source into your project and needs the @insightcharts registry in components.json; see installation. With the package, import it by name:
import { RadialSpokes } from "insightcharts";Examples
Thin lines, centre label, click to select
import { RadialSpokes } from "insightcharts";
const data = [
{ aspect: "Battery life", score: 8.6 },
{ aspect: "Camera", score: 7.1 },
{ aspect: "Screen", score: 9 },
{ aspect: "Speed", score: 6.4 },
{ aspect: "Build", score: 7.8 },
{ aspect: "Value", score: 5.2 },
];
export function Example() {
return (
<RadialSpokes
data={data}
name="aspect"
value="score"
shape="line"
max={10}
format={{ minimumFractionDigits: 1 }}
centerLabel="Model K phone"
select
title="Reviewers scored the Model K's screen 9.0 out of 10"
subtitle="Average review score by aspect, out of 10. The ring marks 10."
note="Illustrative scores for an invented phone"
/>
);
}{
"type": "radial-spokes",
"data": [
{ "aspect": "Battery life", "score": 8.6 },
{ "aspect": "Camera", "score": 7.1 },
{ "aspect": "Screen", "score": 9 },
{ "aspect": "Speed", "score": 6.4 },
{ "aspect": "Build", "score": 7.8 },
{ "aspect": "Value", "score": 5.2 }
],
"name": "aspect",
"value": "score",
"shape": "line",
"max": 10,
"format": { "minimumFractionDigits": 1 },
"centerLabel": "Model K phone",
"select": true,
"title": "Reviewers scored the Model K's screen 9.0 out of 10",
"subtitle": "Average review score by aspect, out of 10. The ring marks 10.",
"note": "Illustrative scores for an invented phone"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Fan over 180 degrees, shaded by value
import { RadialSpokes } from "insightcharts";
const data = [
{ effect: "Drowsiness", pct: 31 },
{ effect: "Dry mouth", pct: 22 },
{ effect: "Headache", pct: 14 },
{ effect: "Nausea", pct: 9 },
{ effect: "Dizziness", pct: 6 },
{ effect: "Rash", pct: 2 },
];
export function Example() {
return (
<RadialSpokes
data={data}
name="effect"
value="pct"
format={"{value}%"}
sweep={180}
colorBy="value"
icon="drop"
title="31% of trial patients reported drowsiness"
subtitle="Share of 840 patients reporting each side effect in a 12-week trial"
note="Illustrative figures for an invented medicine"
/>
);
}{
"type": "radial-spokes",
"data": [
{ "effect": "Drowsiness", "pct": 31 },
{ "effect": "Dry mouth", "pct": 22 },
{ "effect": "Headache", "pct": 14 },
{ "effect": "Nausea", "pct": 9 },
{ "effect": "Dizziness", "pct": 6 },
{ "effect": "Rash", "pct": 2 }
],
"name": "effect",
"value": "pct",
"format": "{value}%",
"sweep": 180,
"colorBy": "value",
"icon": "drop",
"title": "31% of trial patients reported drowsiness",
"subtitle": "Share of 840 patients reporting each side effect in a 12-week trial",
"note": "Illustrative figures for an invented medicine"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Stress: 12 spokes, long labels, values from 0 to 96
import { RadialSpokes } from "insightcharts";
const data = [
{ cost: "Unplanned maintenance and emergency call-outs", k: 96 },
{ cost: "Fuel", k: 71 },
{ cost: "Crew wages and overtime", k: 88 },
{ cost: "Port fees", k: 34 },
{ cost: "Insurance", k: 27 },
{ cost: "Training", k: 0 },
{ cost: "Catering", k: 12 },
{ cost: "Navigation and satellite communications", k: 19 },
{ cost: "Cleaning", k: 5 },
{ cost: "Dry-dock inspection", k: 41 },
{ cost: "Waste disposal", k: 3 },
{ cost: "Ticketing", k: 8 },
];
export function Example() {
return (
<RadialSpokes
data={data}
name="cost"
value="k"
format={"£{value}k"}
centerLabel="One ferry"
highlight={["Unplanned maintenance and emergency call-outs"]}
height={560}
title="Unplanned maintenance cost £96,000 per ferry in 2024"
subtitle="Annual running cost of one ferry by item, £ thousand, 2024"
note="Illustrative figures for an invented operator"
/>
);
}{
"type": "radial-spokes",
"data": [
{ "cost": "Unplanned maintenance and emergency call-outs", "k": 96 },
{ "cost": "Fuel", "k": 71 },
{ "cost": "Crew wages and overtime", "k": 88 },
{ "cost": "Port fees", "k": 34 },
{ "cost": "Insurance", "k": 27 },
{ "cost": "Training", "k": 0 },
{ "cost": "Catering", "k": 12 },
{ "cost": "Navigation and satellite communications", "k": 19 },
{ "cost": "Cleaning", "k": 5 },
{ "cost": "Dry-dock inspection", "k": 41 },
{ "cost": "Waste disposal", "k": 3 },
{ "cost": "Ticketing", "k": 8 }
],
"name": "cost",
"value": "k",
"format": "£{value}k",
"centerLabel": "One ferry",
"highlight": ["Unplanned maintenance and emergency call-outs"],
"height": 560,
"title": "Unplanned maintenance cost £96,000 per ferry in 2024",
"subtitle": "Annual running cost of one ferry by item, £ thousand, 2024",
"note": "Illustrative figures for an invented operator"
}Render with import { Insight } from "insightcharts" and <Insight spec={spec} />. Nested specs resolve by name; nothing else to import.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| namerequired | string | Name field: one spoke per row, in data order, clockwise. | |
| valuerequired | string | Value field: spoke length from the centre disc. | |
| shape | "bar" | "line" | "bar" | A thick tapered bar with a round head, or a thin line ending in a dot. |
| icon | string | Icon in the centre disc: a built-in name or path://. | |
| centerLabel | string | Short text in the centre disc, used when there is no icon. | |
| ring | boolean | true | Dotted outer ring at the scale maximum, where the labels sit. |
| max | number | Value that reaches the outer ring. Default: the largest value. | |
| startAngle | number | 0 | Angle of the first spoke in degrees clockwise from 12 o'clock. |
| sweep | number | 360 | Arc the spokes are spread over, in degrees. 180 makes a fan. |
| colorBy | "single" | "value" | "single" | The accent for every spoke, or a shade by value along the sequential ramp. |
Common chart props 29
Every chart built with defineChart accepts these on top of its own props.
| Prop | Type | Description |
|---|---|---|
| data | DataInput | Rows, CSV text, a URL, { url, path }, an async function, or an Arrow-style table. Omit inside <InsightData>. |
| transform | Transform | Transform[] | A pipeline of transforms applied before drawing. |
| title | string | The title. One plain statement of what the data shows, with the number and the period ("Monthly churn fell from 4.2% to 2.1% in 2024"), or a plain label ("Monthly churn, 2024"). One clause, no figures of speech. |
| subtitle | string | Measure, unit, population, period. |
| source | string | Data source, shown as "Source: ...". |
| note | string | Method notes or caveats. |
| height | number | string | CSS height of the plot. Default 360. |
| aspect | number | Width / height. Overrides height. |
| highlight | string | string[] | The entity (or entities) the title is about. Every other series is drawn in grey. |
| annotations | Annotation[] | Reference lines, shaded bands and callouts, in data coordinates. |
| format | FormatSpec | How to print values: "compact", "percent", "currency:USD", "{value} kg", Intl options, or a function. |
| legend | boolean | Show the legend. Default: shown when there are two or more series. |
| select | boolean | string | Make marks clickable to filter. Inside <InsightData> the selection filters every other chart. Pass a field name, or true to use the chart's category field. |
| onSelect | (values: string[], field: string) => void | Called with the selected values whenever the selection changes. |
| option | EChartsOption | ((option: EChartsOption, ctx: BuildContext) => EChartsOption) | Deep-merged over the generated ECharts option, or a function that receives and returns it. Use it for ECharts settings no prop covers. |
| theme | ThemeInput | A theme, or a partial set of tokens merged over the surrounding theme, for this chart only. |
| mode | ModeInput | "auto" (default) follows the page, "system" follows the OS, or force "light" / "dark". |
| renderer | RendererInput | "auto" (default) uses SVG for light charts and canvas for heavy ones. |
| animate | boolean | Set false to disable animation. Reduced-motion preferences are always respected. |
| lazy | boolean | Mount the chart only when it scrolls near the viewport. Default true. |
| group | string | Link tooltips with other charts sharing this group id. |
| exportable | boolean | ExportFormat[] | Show an export menu: true or a list of formats from png, jpeg, svg, pdf, csv, json. |
| table | boolean | Show a collapsible "View data" table under the chart. |
| alt | string | Accessible description: the chart type and measures, then the main pattern and the notable values. |
| id | string | Stable id for this chart's selection in the shared store. |
| onEvents | Record<string, ChartEventHandler> | ECharts event handlers, e.g. { click: (params, chart) => {} }. Prefix a name with zr: to bind to the canvas itself. |
| onReady | (chart: EChartsInstance) => void | Called with the ECharts instance once it is created. |
| className | string | Class name for the outer <figure>. |
| style | CSSProperties | Inline style for the outer <figure>. |