Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 data changes. Declare a racechart, paste the data with racedata (a value per period per row; icons ride the bars), and play with race. Bars get rescaling gridlines + a live Total; raceline/racepanel add a companion line or a multi-line history panel below the bars. See the charts guide.

Each block is the whole file — copy it into x.manic and run manic x.manic (live) or --record out (video).

charts-gdp-race

The flagship bar-chart race: the world’s biggest economies, GDP 1990→2026, with country flags riding the bars. Watch China climb from #7 to #2 as the bars reorder, the axis rescales with gridlines, and the year + Total tick — all from one pasted data block.

// charts-gdp-race.manic — an animated BAR-CHART RACE from a pasted data block.
//
// The `charts` kit turns a table into bars that actually REORDER as the numbers
// change — the viral data-viz format, but true to the data and self-contained in
// one script. Paste your data into `racedata` (one row per entity: label, an icon
// shorthand, then a value per period), then `race` plays the whole thing —
// re-ranking, sliding bars to their new slots, rescaling the axis, and ticking the
// year + values. Bars are rounded, gradient-filled; flags are imported SVG.
//
// Nominal GDP, US$ trillion, 1990 → 2026 (approx.) — watch China climb from the
// bottom to #2, Japan slide, and India rise.
//
//   manic examples/charts-gdp-race.manic
canvas("16:9");
template("blank");

racechart(gdp, "bar", "1990 1995 2000 2005 2010 2015 2020 2026",
          "The World's Biggest Economies — GDP 1990 to 2026 ($T)");

// paste your table: label, ICON, then one value per period.
// separators are forgiving — commas here, but tabs / spaces / newlines all work.
//
// the ICON column takes ANY svg, not just flags:
//   us                              a flag shorthand      → asset:svg/flags/us.svg
//   rocket / heart / trophy         an emoji/icon alias   → asset:svg/emoji|lucide/…
//   asset:svg/lucide/lightbulb.svg  an explicit set path
//   logos/acme.svg                  your OWN file (any path ending in .svg)
// omit the icon entirely and the row is just label + values.
//
// NOTE: a few flags whose stars are drawn with SVG <use> (e.g. cn — China) render
// imperfectly for now (tracked); most flags and all icons/emoji render cleanly.
racedata(gdp, "
  USA,     us,  5.96,  7.64, 10.25, 13.04, 15.05, 18.24, 21.06, 30.34
  China,   cn,  0.36,  0.73,  1.21,  2.29,  6.09, 11.06, 14.69, 20.50
  Japan,   jp,  3.13,  5.55,  4.97,  4.83,  5.76,  4.44,  5.06,  4.40
  Germany, de,  1.60,  2.59,  1.95,  2.85,  3.40,  3.36,  3.89,  4.90
  India,   in,  0.32,  0.36,  0.47,  0.82,  1.68,  2.10,  2.67,  4.60
  UK,      gb,  1.09,  1.33,  1.66,  2.54,  2.49,  2.93,  2.70,  3.90
  France,  fr,  1.27,  1.60,  1.36,  2.20,  2.65,  2.44,  2.63,  3.30
  Brazil,  br,  0.46,  0.77,  0.65,  0.89,  2.21,  1.80,  1.48,  2.40
");

race(gdp, 14);

charts-column-race

A COLUMN race (vertical bars), built with the per-series raceseries input: men’s tennis Grand Slam titles 2005→2024, Djokovic climbing to overtake Federer and Nadal, with flags.

// charts-column-race.manic — a COLUMN chart race (vertical bars), built with the
// per-series `raceseries` input (the computed/loop sibling of `racedata`). A sport
// race: the men's tennis Grand Slam count, 2005 → 2024 — watch Djokovic climb from
// nothing to overtake Federer and Nadal. Flags are imported SVG (rs/es/ch/gb).
//
//   manic examples/charts-column-race.manic
canvas("16:9");
template("blank");

racechart(gs, "column", "2005 2009 2013 2017 2021 2024",
          "Men's Tennis — Grand Slam Titles, 2005 to 2024");

// one entity per player: raceseries(chart, "name", "flag", "v0 v1 …")
raceseries(gs, "Federer",  "ch",  "5 15 17 19 20 20");
raceseries(gs, "Nadal",    "es",  "4  6 13 16 20 22");
raceseries(gs, "Djokovic", "rs",  "0  1  6 12 20 24");
raceseries(gs, "Murray",   "gb",  "0  0  2  3  3  3");

race(gs, 10);

charts-line-race

A LINE race: each series draws its line on left-to-right as the years tick, value/label/flag riding the leading tip; the race is which line climbs highest. Fixed axis, decluttered tips.

// charts-line-race.manic — a LINE chart race. Each series draws its line on
// (left → right) as the years tick, with the value, label and flag riding the
// leading tip; the "race" is which line climbs highest. Fixed y-axis (line charts
// don't rescale), L-shaped axes, flags are imported SVG.
//
//   manic examples/charts-line-race.manic
canvas("16:9");
template("blank");

racechart(gdp, "line", "1990 2000 2010 2020 2026",
          "GDP Over Time — a Line Race ($T)");

racedata(gdp, "
  USA,     us,  5.96, 10.25, 15.05, 21.06, 30.34
  China,   cn,  0.36,  1.21,  6.09, 14.69, 20.50
  Japan,   jp,  3.13,  4.97,  5.76,  5.06,  4.40
  Germany, de,  1.60,  1.95,  3.40,  3.89,  4.90
  India,   in,  0.32,  0.47,  1.68,  2.67,  4.60
");

race(gdp, 10);

charts-bar-line

The bar+line combo: a GDP bar race with a companion raceline across the top showing the auto-summed world Total, drawn on with a marker and live readout, synced to the race.

// charts-bar-line.manic — a BAR race with a companion LINE (the classic combo).
//
// The bars race as usual (reordering by value), and `raceline` draws a synced line
// across the top strip — here the running TOTAL, auto-summed from the bars (pass
// your own "v0 v1 …" to track a different metric). The line draws on, a marker
// rides its leading point, and a live readout counts up — all locked to the race.
//
//   manic examples/charts-bar-line.manic
canvas("16:9");
template("blank");

racechart(gdp, "bar", "1990 2000 2010 2020 2026",
          "World GDP — Who's Biggest, and the Total Growing ($T)");

racedata(gdp, "
  USA,     us,  5.96, 10.25, 15.05, 21.06, 30.34
  China,   cn,  0.36,  1.21,  6.09, 14.69, 20.50
  Japan,   jp,  3.13,  4.97,  5.76,  5.06,  4.40
  Germany, de,  1.60,  1.95,  3.40,  3.89,  4.90
  India,   in,  0.32,  0.47,  1.68,  2.67,  4.60
");

// the companion line across the top — a running total of all bars (auto-summed)
raceline(gdp, "World total");

race(gdp, 12);

charts-german-elections

Bar race + a multi-line history racepanel below (the Flourish bar+line layout), from a REAL CSV: German federal election vote share 1949→2021, 7 parties, missing early years as 0, Total 100. Every party is a bar up top and a color-matched line in the history panel.

// charts-german-elections.manic — a BAR race from real CSV data (German federal
// election vote share, %, 1949-2021). Transcribed from Data.1785183258253.csv:
// the empty separator column is dropped and missing early years (parties that
// didn't exist yet) are 0. Watch CDU/CSU and SPD trade the lead while the Greens,
// Left and AfD climb from nothing.
//
//   manic examples/charts-german-elections.manic
canvas("16:9");
template("blank");

racechart(de, "bar", "1949 1953 1957 1961 1965 1969 1972 1976 1980 1983 1987 1990 1994 1998 2002 2005 2009 2013 2017 2021",
          "German Federal Elections — Vote Share %, 1949 to 2021");

racedata(de, "
  CDU/CSU, 31, 45.2, 50.2, 45.3, 47.6, 46.1, 44.9, 48.6, 44.5, 48.8, 44.3, 43.8, 41.4, 35.1, 38.5, 35.2, 33.8, 41.5, 32.9, 24.1
  SPD, 29.2, 28.8, 31.8, 36.2, 39.3, 42.7, 45.8, 42.6, 42.9, 38.2, 37, 33.5, 36.4, 40.9, 38.5, 34.2, 23, 25.7, 20.5, 25.7
  FDP, 11.9, 9.5, 7.7, 12.8, 9.5, 5.8, 8.4, 7.9, 10.6, 7, 9.1, 11, 6.9, 6.2, 7.4, 9.8, 14.6, 4.8, 10.7, 11.5
  Green, 0, 0, 0, 0, 0, 0, 0, 0, 1.5, 5.6, 8.3, 5.1, 7.3, 6.7, 8.6, 8.1, 10.7, 8.4, 8.9, 14.8
  Left, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.4, 4.4, 5.1, 4, 8.7, 11.9, 8.6, 9.2, 4.9
  AfD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.7, 12.6, 10.3
  Other, 27.6, 16.3, 10.2, 5.6, 3.6, 5.4, 0.9, 0.9, 0.5, 0.4, 1.3, 4.2, 3.6, 6, 3, 4, 6, 6.3, 5.2, 8.6
");

// a synced multi-line history panel below the bars: every party as a line, drawn
// up to a moving time-cursor (the Flourish bar+line combo)
racepanel(de);

race(de, 16);