Components / Charts
Ridgeline
Overlapping distributions, one ridge per group: hover to lift a ridge and read its quartiles, switch datasets and every curve morphs.
Install
npx shadcn@latest add https://irisui.dev/r/ridgeline.jsonimport { Ridgeline } from "@/components/iris/ridgeline/ridgeline";Preview
Ridgeline
Overlapping density curves, one ridge per group, that compare the shape of many distributions; hover to lift a ridge and read its quartiles.
When to use
- Comparing spread, skew and bimodality across several groups at once: response times by region, session length by plan, daily highs by month.
- Raw observations are available (at least about 20 per group); the component smooths them into a density.
- Not when one summary number per group is enough; use
BarChart. Not for more than about 20 groups.
Usage
import { Ridgeline } from "@/components/iris/ridgeline/ridgeline";
h(Ridgeline, {
label: "FairRent scores by country",
domain: [0, 100],
series: [
{ id: "gr", label: "GR", values: [62, 71, 55, 64 /* … raw scores */] },
{ id: "ie", label: "IE", values: [35, 28, 41, 33 /* … */] },
],
});
Props
| Prop | Type | Default | Description |
|---|---|---|---|
series |
{ id: string; label: string; values: number[] }[] |
required | One ridge per series, drawn top to bottom. values are raw observations. |
label |
string |
required | What is measured; names the chart for assistive technology. |
unit |
string |
— | Appended to every value and tick, such as " ms" or "°C". |
formatValue |
(value: number) => string |
— | Overrides unit formatting. |
domain |
[number, number] |
data with a little room | Fixed axis range; keeps the axis still across datasets. |
overlap |
number |
2.4 |
How far the tallest ridge rises into the rows above, in row heights. |
rowHeight |
number |
30 |
Height of one row in px. |
bandwidth |
number |
Silverman's rule | Smoothing in value units. |
tint |
boolean |
true |
Shades each ridge by its median and shows a stepped scale under the axis. |
active / defaultActive / onActiveChange |
string | null / callback |
— / null |
The lifted ridge. |
emptyLabel |
string |
"No data yet" |
Shown when there are no values. |
className |
string |
— | Class on the root figure. |
ref |
Ref<HTMLElement> |
— | Forwarded to the root figure. |
Notes
- Keyboard: Up/Down lift the previous or next ridge, Left/Right move the reading cursor one axis step, Home/End lift the first or last ridge, Escape lowers it.
- Accessibility: the plot is a focusable group; a polite live region announces the lifted ridge's median, middle half, range and count; a hidden table lists the statistics for every series.
- Gotcha: row labels sit in a fixed 52px gutter (36px on narrow widths), so keep them short (codes or abbreviations) or they truncate. Tick spacing can drop toward 40px on wide plots, so long units (
" ms") crowd the axis beyond about 600px of width; use a narrower container, a widerdomainstep, or a terseformatValue. - Colours come from
--series-1…4; override them on an ancestor to rebrand. Comfortable up to a few thousand observations per series.