Race charts — paste a table, get a race
The charts kit turns a table into an animated race chart — ranked bars, columns, or lines that reorder over time as the numbers change. It’s the viral data-viz format (GDP, population, brands, sports…), but true to the data and self-contained in one script: no timeline scrubbing, no keyframes.
Three ideas:
- Declare a chart —
racechart(id, layout, periods) - Paste the data —
racedata(id, "…") - Play it —
race(id, seconds)
canvas("16:9"); template("blank");
racechart(gdp, "bar", "2000 2010 2020 2024", "GDP by Country ($T)");
racedata(gdp, "
USA, us, 10.3, 15.0, 21.4, 27.4
China, cn, 1.2, 6.1, 14.7, 20.5
Japan, jp, 4.9, 5.8, 5.0, 4.2
India, in, 0.5, 1.7, 2.7, 3.9
");
race(gdp, 8);
The bars grow, reorder as ranks change (the reorder is the race), the axis rescales with the running max, and the year + values tick — all from that block.
The data block
racedata(parent, "block") is the heart of it. One row per entity:
label [icon] v0 v1 v2 … ← one value per period
The parser is forgiving so real data pastes straight in:
- Rows split on a newline or a
;. - Cells split on comma, tab, or whitespace — so a CSV, a TSV, or a spreadsheet copy all work.
- Missing cells count as 0 (e.g. a company/party that didn’t exist yet).
- Multi-word labels are fine when the data is comma- or tab-delimited.
Prefer to build rows in code? raceseries adds one entity at a time — the
computed/loop path:
for i in 0..n {
raceseries(g, name{i}, "rocket", vals{i}); // label, icon, values
}
Icons — any SVG on the bar
The optional icon column puts a flag, logo, or emoji on each bar. It takes any SVG, not just flags:
| You write | Resolves to |
|---|---|
us | a flag shorthand → asset:svg/flags/us.svg |
rocket, heart, trophy | an emoji / icon alias |
asset:svg/lucide/lightbulb.svg | an explicit set path |
logos/acme.svg | your own file (any path ending .svg) |
| (omit it) | the row is just label + values |
Icons are imported as real geometry via svg(), so they recolour
and scale cleanly. Browse every bundled asset in the SVG catalogue.
A handful of flags whose stars use SVG
<use>/<marker>(e.g. China) render imperfectly for now — most flags and all icons/emoji are clean.
Layouts
racechart(id, layout, …) takes one of three:
"bar"— horizontal bars, ranked top-to-bottom. The classic; gets value gridlines + a live Total readout."column"— vertical bars, ranked left-to-right."line"— each series a line that draws on over time; the race is which line climbs highest (fixed axis, tip labels auto-declutter).
Bar + line, together
On a bar race you can overlay a companion line:
raceline(parent)— a line across the top showing a running total (auto-summed from the bars), orraceline(parent, "label", "v0 v1 …")for an explicit metric.racepanel(parent)— a multi-line history panel below the bars: every series as a line revealed up to a moving time-cursor (the Flourish bar+line combo).
racechart(de, "bar", "1949 … 2021", "German Elections %");
racedata(de, " CDU/CSU, , 31, … ; SPD, , 29, … ; … ");
racepanel(de); // history panel below the bars
race(de, 16);
Composing with the rest of manic
A race chart is just tagged entities, so it drops into any scene — a voiced
Creator Short, a quiz reveal, a caption sequence. In
creator-race-quiz a quiz poses a question and
the race chart proves the answer, narrated with speak, closed with a CTA
card — the chart running inside a par while the voice-over plays over it.
Examples
- GDP bar race — flags racing, gridlines, total
- Column race — tennis Grand Slams
- Line race — GDP trajectories
- Bar + total line
- Bar + history panel — from a real CSV
- Race-chart quiz Short — voiced, problem→proof→CTA