Ask a coding agent to map a spreadsheet and it'll give you something that looks fine. The trouble is what the picture says. I kept seeing the same four mistakes, so I wrote Graticule to stop them.
The four mistakes
Raw counts. Coloring countries by COVID deaths mostly shows where people live. The fix is a rate. Graticule asks you to declare what the numbers are. If you don't, it checks whether the values rank like population. On 33 World Bank indicators, that check flagged 0 of 25 rates and caught 8 of 8 counts.
Mercator for the world. Greenland looks as big as Africa. Shaded maps are compared by area, so Graticule defaults to an equal-area projection and refuses Mercator above 20 degrees of latitude.
Rows that vanish. "Korea, Rep." doesn't match "South Korea" and nothing tells you. Every row that fails to join is listed with its closest names. If a name fits two places, Graticule won't guess. On 235 ISO country names, the join found 232 with no wrong match. Exact matching against Natural Earth found 202.
Rainbow palettes. Lightness that goes up and down draws borders that aren't in the data. The palette has to get steadily lighter or darker, and its colors have to stay apart under simulated color vision deficiency.
How it works
A map is a small JSON spec. graticule check runs 25 rules and prints every finding with a one-sentence reason. --fix applies the smallest repair for each error and records it. Only then does it draw SVG, PNG, PDF or an interactive page.
graticule render map.json --fix -f svg,png
There are no native dependencies. PNG goes through resvg compiled to WebAssembly. Fonts are subset per map with the HarfBuzz subsetter, so Chinese, Japanese and Korean labels survive on any machine. Geography is bundled, so it works offline. The same modules run in the browser playground, which has nine interface languages.
What I checked
Eleven of twelve projections match PROJ to 0.00001 m on 3,000 points each. Robinson agrees to 10.2 km after fitting one scale. Class breaks match mapclassify on 45 cases, before the legend rounds the edges.
Rough edges
Boundaries are drawn for maps rather than surveying. Small countries become dots. Labels use a greedy placer, so dense maps drop some and the report counts them. The counts detector is a heuristic with a limit of 0.6. If you have a table that joins wrongly or a map that gets past the checker, I want to see it.
Install it as an agent skill with npx skills add Arthur031221/Graticule, or open the playground and drop a CSV.

Top comments (0)