Framework
How the maps are made, what they are made with, and who actually did the hard parts.
The pipeline
Every map on this site comes from one input: the agency’s published GTFS feed, the same open format that powers transit directions in most journey planners. A feed is a zip of tables describing routes, stops, trips and stop times. Turning that into a diagram takes six stages, and each one makes a decision.
-
gtfs2graphReads the feed and builds a line graph: stations as nodes, track as edges, each edge knowing which routes use it. Geographic, still.
-
topoMerges track that several routes share, and folds an interchange’s separate platforms into a single station.
-
loomDecides the left-to-right order of lines running together, so parallel routes do not cross each other pointlessly at every junction.
-
octiThe Beck step. Snaps the whole network onto a grid of 45° angles, trading geographic truth for legibility.
-
renderDraws the SVG: parallel tracks offset onto their own lines, stations marked, and station names placed by a solver that rotates them off the line and tests real collisions rather than bounding boxes.
-
animateWalks every trip in the timetable across the drawn network and emits the times and distances the browser interpolates between.
The first four stages are LOOM. The last two I wrote, mostly because the animation needs geometry it can address by name: one path per line per segment, so a train can be placed along it by distance.
Each running map also has a second view. The schematic has already thrown away geography, but it is still a map; the linear view throws away the last of it and lays every line out as a row of equally spaced stations. Row length then reads directly as station count, the lines can be compared with each other rather than located in a city, and because the spacing is by stop rather than by distance, a train visibly accelerates wherever it skips one. Lines that branch fork onto a short row of their own, the way the diagram above a carriage door does.
A third view drops the network entirely and plots time. Stations run down each line’s band, hours run across, and every train of the day is one diagonal — the chart Étienne-Jules Marey drew for the Paris to Lyon railway in the 1880s. Where the diagonals crowd, that is frequency; where they steepen, speed; and the shape of the service day shows up whole. New York’s 6 express is the clearest example: it appears at each peak and vanishes between them, which is plain in the chart and invisible on any map. The playhead is the same instant the other two views are showing.
Adding a city is one entry in a registry — a name, a feed URL, and which modes to include. Everything else is the same code. That was the point of building it this way, and the twenty-one networks in the atlas are the test of whether it worked.
Credit
This project is a thin layer over other people’s work. The interesting problems here — schematisation, line ordering, the idea itself — were solved by others, and it would be dishonest to present the result without saying so clearly.
LOOM — Hannah Bast, Patrick Brosi and Sabine Storandt
LOOM, from the Chair of Algorithms and Data Structures at the University of Freiburg, does the genuinely hard computation: it takes a geographic network and produces a schematic one, solving both the line ordering and the octilinear layout. Their paper, Large-scale Generation of Transit Maps from OpenStreetMap Data, describes the approach. LOOM is released under the GPL-3.0. Without it this project would be an essay with no maps in it.
Harry Beck, and Transport for London
The 1933 Underground diagram is the original argument that a transit map should be judged by how well it serves a journey rather than how faithfully it reproduces geography. Every schematic map since, including all of these, is a variation on what Beck established.
Thomas van Dijk — mooey
mooey is where this started. I went looking for a way to generate a schematic map and found it first; reading it is what led me to LOOM, which mooey itself builds on. Its core idea — that a designer fixing the direction of edges by hand, with the layout recomputed instantly, beats full automation — is the most likely next step for this project.
Lance Wyman, Arturo Quiñones and Francisco Gallardo
The Mexico City Metro’s station icon system, designed in 1969 under architect Pedro Ramírez Vázquez. It remains the clearest demonstration that cultural specificity and accessibility can be the same design decision, and it is the standard the maps here fall short of.
Jorge Luis Borges
On Exactitude in Science, one paragraph long, which settled the question of whether more detail means more understanding.
The transit agencies
Twenty-two agencies publish the schedule data these maps are built from, openly and for free: LA Metro, the MTA, Metra, NJ Transit, SFMTA, TriMet, SEPTA, the CTA, the MBTA, BART, RTD Denver, UTA, Valley Metro, DART, Sound Transit, Pittsburgh Regional Transit, Cleveland RTA, Miami-Dade Transit, MARTA, Metro Transit in Minneapolis, and Mexico City’s Sistema de Transporte Colectivo, through the city’s Secretaría de Movilidad. Each map derives from that agency’s feed and remains subject to that agency’s terms; every network in the atlas links back to its source.
The Mobility Database catalogues those feeds, which is how I found the current URL for each one instead of guessing. GTFS itself, originally developed by Portland’s TriMet with Google, is the reason a single pipeline can read all of them.
OpenStreetMap
Not used for the maps here — every one of these feeds ships its own track geometry — but pfaedle, also from the Freiburg group, can generate that geometry from OSM for feeds that lack it. Anything produced that way inherits the ODbL.
This site
Built with Eleventy, set in Iowan Old Style with Palatino and Georgia behind it, and themed to match the rest of my writing. The maps are inlined as SVG rather than linked as images so they take the page’s colours — though only the background, station markers and labels change with the theme. Line colours are the agencies’ own and are never altered.
The pipeline is Python and LOOM runs in Docker. Adding a city takes a name, a feed URL, and the modes to include.