DataPressr · charting spike · issue #11

Hand-rolled SVG, or Observable Plot?

Both story #2 charts, rendered the way they were (a hand-written SVG generator) and the way the line-charts bake-off recommends (Observable Plot). Same data, same palette, same deployment: a committed .svg file embedded as a Markdown image. Plot is rendered to that SVG in Node at build time — no JavaScript runs on the published page.

Outcome: Plot wins. It is now the near-term standard for story and enrich charts — see docs/charting.md. This page is kept as the record of the comparison.

Same
data, computed values, palette, sort order, the 16.6× clip, the "beyond" row, the deploy model
New cost
@observablehq/plot + jsdom, build-only, scoped to site/stories/package.json
Code
scoreboard generator: ~120 lines hand-rolled → ~45 with Plot
Rough edge
Plot's Node render estimates text width (no browser layout) — tick margins can be a few px off a real browser

01The scoreboard

Twelve indicators, framework-normalised so the pre-industrial state is 0 and the boundary is 1×. Six of nine boundaries crossed; genetic diversity runs off the axis at 16.6×.

planetary-boundaries-scoreboard — horizontal bars, reference rule at 1×, tinted safe zone, rows sorted by overshoot
was — hand-rolled~120 loc
Novel entities beyond — boundary is zero, extent not quantified Biosphere: genetic diversity → 16.6× Freshwater: green water 4.7× Freshwater: blue water 3.8× Biosphere: functional diversity 3.5× Biogeochemical: phosphorus 2.9× Biogeochemical: nitrogen 2.7× Climate change 2.1× Land-system change 1.6× Ocean acidification 0.9× Atmospheric aerosols 0.5× Stratospheric ozone -0.1× planetary boundary (1×) ← safe operating space
now — Observable Plot~45 loc
Novel entitiesBiosphere: genetic diversityFreshwater: green waterFreshwater: blue waterBiosphere: functional diversityBiogeochemical: phosphorusBiogeochemical: nitrogenClimate changeLand-system changeOcean acidificationAtmospheric aerosolsStratospheric ozonedistance from the pre-industrial state, in boundary units (1× = the boundary)safe operating space→ 16.6×4.7×3.8×3.5×2.9×2.7×2.1×1.6×0.9×0.5×-0.1×beyond — boundary is zero, extent not quantifiedplanetary boundary
What Plot changed

02Ozone

Seven benchmark years from the source compilation. The line dips toward the 276 DU boundary around 1990, then recovers after the Montreal Protocol.

planetary-boundaries-ozone — line + points, boundary rule, shaded exceedance band, event marker
was — hand-rolled~50 loc
270 276 282 288 294 300 1900 1930 1960 1990 2020 Year Stratospheric ozone (Dobson units) Montreal Protocol boundary — 276 DU
now — Observable Plot~30 loc
270276282288294300Stratospheric ozone (Dobson units)19001930196019902020Yearboundary — 276 DUMontreal Protocol
What Plot changed

03The trade

 Hand-rolled SVGObservable Plot
Scoreboard generator~120 lines~45 lines
Axis / ticks / grid / sortwritten by hand each timedeclarative, free
Pixel-level controltotalPlot's defaults, then override
Axis-label placementfully yoursPlot's, unless overridden
New dependencynone@observablehq/plot + jsdom, build-only
Published pagestatic SVG, no JSstatic SVG, no JS
Chart types ahead (ranged bars, small multiples, dot plots for enrich)each one hand-builtone mark call

Chosen — Observable Plot

Near-term standard for story and enrich charts, rendered to static SVG at build time. planetary-boundaries-make-charts.mjs is the reference. Closes the near-term half of #11.

Still hand-rolled

A genuinely bespoke one-off visual, where fighting Plot's grammar costs more than writing the SVG. And the Keeling Curve charts, until they're next touched (#12).