Metrocyclopaedia 🚇 Interactive map of all metro systems of the world

I have been playing around quite a bit with CesiumJS recently. It is likely the best tool out there to visualize global datasets on an interactive 3D Earth in the browser.

As you might know from the title of his blog, 😁 I am fascinated by complex systems. A particular kind of complex systems are infrastructures, and 🇫🇷 metro 🇺🇸 subway 🇬🇧 underground 🇩🇪 U-bahn lines are one of the most mesmerizing pieces of infrastructure – as they give us an insight into how society organizes itself around patterns. But, unlike the road network, the metro system also gives us a sense of population density at a glance – provided that the city planners made the sensible decision to position the stations at the most frequented locations, which apparently does not always happen.

Recently, I have also been experimenting with 3D globes, with various oddball datasets.. For example, I’ve visualized all Antarctic research stations, Global Warming Stripes and more recently Traffic congestion. So my next project was to visualize the metro systems of the world, ideally all of them at once, if possible, on an interactive Earth.


Initially, naturally I thought that likely many have fared down this route before me. But, as I have later found out , not so. Clearly, the one project we cannot do without mentioning is OpenRailwayMap. This is just an incredible asset for visualizing all railways of the world – metros included. However, it is a bit overwhelming, it’s not possible to filter for metros only and – I wanted something a bit more fun 😅.

So my goal was to create an interactive transit map of all metro systems of the world and this is what I ended up with. The process included several steps 👇 (click for 🕹 interactive)

Metrocyclopaedia 🚇 Interactive map of all metro systems of the world
Metrocyclopaedia 🚇 Interactive map of all metro systems of the world
👆 Budapest Metro on the 🚇 Metrocyclopaedia
Looking at the London Underground system from Heathrow Airport on the 🚇 Metrocyclopaedia
👆 Looking at the London Underground system from Heathrow Airport on the 🚇 Metrocyclopaedia
Boston's T and the extensive Green Line branches on the 🚇 Metrocyclopaedia
👆 Boston’s T and the extensive Green Line branches on the 🚇 Metrocyclopaedia
The Paris Métropolitain on the 🚇 Metrocyclopaedia
👆 The Paris Métropolitain on the 🚇 Metrocyclopaedia
Aerial view of Manhattan and the New York City Subway System on the 🚇 Metrocyclopaedia
👆 Aerial view of Manhattan and the New York City Subway system on the 🚇 Metrocyclopaedia
The Tokyo Metro and Toei Subway networks on the 🚇 Metrocyclopaedia
👆 The Tokyo Metro and Toei Subway networks on the 🚇 Metrocyclopaedia

Data

The first problem is getting the data. There is hardly any unified and normalized database of all subways systems. One could always turn to Wikipedia, of course, but then this requires extensive work as manual normalization and validation would be needed for most entries.

OpenStreetMap

The next logical choice would be OpenStreetMap. Here one can look for all railways, for example, then filter for only subways. OSM even has an extensive guide on how to properly record metro line and station data, so it ends up in the standardized format that the community would desire. However, practically speaking, the data is quite messy and the connection between lines, itineraries, stations, and transfers between stations is hard to clean up (it would eventually have, however, the advantage of being scalable and sustainable, and it would likely stand the test of time). Nonetheless, the most popular free offline mapping app, maps.me does use OSM data and they have even created a quality control system for validating subway systems up on OSM. So I started out by looking more closely at this dataset as they list all metro systems, as well as all light-rail systems of the world. They automatically produce daily dump-files of the OSM data, resulting in a yaml and a geojson file of each network. I did write a parser for processing these datasets, but I discovered two major setbacks:

  • Firstly, the station names are stored only in the respective country’s native language and script – which is fine and fair, but can be a difficulty for tourists who are not familiar with one script or another (e.g. Arabic and English labels, or Japanese and Romaji)
  • Second, while all lines and stations are listed both in the yaml files and the geojson files, I couldn’t find a consistent way of linking them together. It complicates things further, that the geosjons include the actual railway tracks, rather than the informative trajectory of the metro lines, therefore always at least two parallel line geometries exist next to each other, as well as multiple entrances and exits (representing the the actual escalators and platform accesses) for stations. This is great for millimeter-accurate mapping – but hardly useful for a high-level transit map.

These are not insurmountable challenges, of course, as one can always go back to the actual OSM data and re-query everything to see if there are more tags not captured in the maps.me validation site. In fact, they even provide a GitHub repo for reproducing the validation datasets from the raw OSM data, complete with a spreadsheet for the bounding boxes of all metro and light-rail systems. As delving into this would be quite a bit more effort than a weekend project, I’ve decided to carry on by other means. My thought was to re-query only the bits I considered missing from the raw OSM data and then merge the two..

In order to work with OSM data, one needs to use the Overpass API. There are several tools to ease the interaction with this API, including Osmosis which also works from python, my go-to data language. However, there is even a web tool, overpass-turbo. This is very handy and after a bit of experimentation, I’ve discovered that there are, indeed, a number of tags (such as name:en for English station names) that would help with extending the maps.me dataset the way I would like. However, connecting the shapes with the lines and selecting between the track line segments would still be a major project on its own..

Metrolinemap

Then I found metrolinemap.com. This had the caveat of including only the actual metro systems and no light rails (suburban networks, RERs or S-Bahns), and the last update was a few months ago, but it was was much better in terms or normalization – and included trivia bits about each system, too! So, after some parsing and cleaning in python with Jupyter, lxml and BeatifulSoup, I got my formatted json data, ready to load into Cesium. It ended up being a 6MB file, so I used JSZip to shrink it to around 1MB and load it in JavaScript with D3.js.

Metro line map logo

All the kudos and recognition to “two ordinary guys from Finland” for creating and maintaining this resource!


Visualization

🕹 Metrocylopaedia

Once loaded as a JavaScript object, I needed to create the entities to be visualized in Cesium. Because of my previous experience with using it and its similarity to the generic JSON structure, I’ve decided to go for CZML. This meant that I would basically just create a giant a CZML object and then load it as an entities array into Cesium. However, later I discovered that eventually there were about 1 million individual entities when fully loaded, even with coarse shape geometries (octagons instead of cylinders, for example, for stations) , so I had to slice the data up a bit.

I store the data as a JavaScript array, with each item being an Object like:

{
    "name": "Budapest Metro",
    "url": "https://www.metrolinemap.com/metro/budapest/",
    "desc": "The Budapest Metro is the oldest electrified 
            rapid transit system in the Europe. It serves 
            the Hungarian capital of Budapest. It began operation 
            in 1896. System consists of four lines and 48 stations.",
    "lines": [
        {
            "path": [
                {
                    "lat": 47.49667985962044,
                    "lng": 19.05032381415367
                },...
            ],
            "color": "#4EA237",
            "name": "M4",
            "branch": "Kelenföld vasútállomás - Keleti Pályaudvar",
            "id": "151"
        }
    ],
    "stations": [
        {
            "name": "Arany János utca",
            "lat": 47.504085752636,
            "lon": 19.054628759623,
            "url": "https://www.metrolinemap.com/...",
            "lines": [
                "M3"
            ],
            "branches": [
                "150"
            ]
        },...
    ],
    "geo": {
        "continent": "Europe",
        "country": "Hungary"
    },
    "year": 1896
}

Each metro system has four different elements loaded into Cesium:

  • A main label for the entire system – configured to be visible from far away only
  • Station labels – visible from close by only
  • Station octagons
  • Line corridors

Furthermore, there is metadata associated with the each of the stations and lines, containing the naming and branch information. This info is shown in the Ceium infoBox upon clicking/tapping on a station or line.

I also distinguish between transfer stations between two or more separate lines (displayed in white, larger octagon), transfer stations on the same line’s different branches (displayed in the line’s color, but larger) and regular stations (line’s color, regular sized octagon). In order to position the main system label, I use a small function to identify the central station of a system – i.e. the location where the highest number of lines intersect. At the coordinates of the central station, I place the system label.

function central(stations, already) {
    maxStations = 0
    coords = []
    name = ''
    stations.forEach(function (station) {
        if (station.lines.length > maxStations) {
            if (already.indexOf(station.name) < 0) {
                name = station.name
                maxStations = station.lines.length
                coords = [station.lat, station.lon
                ]
            }
        }
    })
    return [coords, name
    ]
}

After much experimentation, I concluded that the highest toll on the processor were the station labels – containing the highest number of individual glyphs, so everything except these is rendered on page load. This still takes 3-4 seconds, but it has the advantage of the user being able to roam the world map, and see the metro system maps laid out over their respective cities. If there is a click or tap event, on any element of a yet unvisited system, then the labels and station metadata are loaded for that system. Likewise, each station label also includes information about the transfers and branches pertaining to that particular station.

{
    "id": metro.name + ' | ' + station.name,
    "name": station.name,
    "position": {
        "cartographicDegrees": [station.lon, station.lat, 40]
    },
    "cylinder": {
        "length": height * (0.95 + Math.random() / 10),
        "topRadius": radius,
        "bottomRadius": radius,
        "slices": 8,
        "material": {
            "solidColor": {
                "color": {
                    'rgba': station.color
                }
            }
        }
    }
}

On a mobile device, the processing power is even more limited, so here the systems are only loaded one-by-one, by a menu selection or navigation event. Furthermore, the labels cause clutter – and sometimes have rendering issues – on the phone, so these are removed altogether for a cleaner look. Station info is still displayed in the standard Cesium infoBox on tap.

👆 The Vienna U-Bahn network viewed on a mobile device on the 🚇 Metrocyclopaedia
👆 The Vienna U-Bahn network viewed on a mobile device on the 🚇 Metrocyclopaedia

🕹 OSM version – alpha

After tweaking the look and feel of my Cesium metro systems app, I’ve revisited the idea of displaying all urban transit systems listed in the OSM directory. Using js-yaml, I managed to create a connector that loads and processes all the metro and light rail systems listed in the maps.me database, live. However, this is very early stage (with the issues listed at the beginning of this article), and I did not go through the substantial cleaning it would require to become fully usable. Nonetheless, it’s nice to see the metro systems with their suburban extensions side-by side (Caveat: not all systems load because of the dual tracks..).

The Budapest Metro with the basic layout, using data from metrolinemap.com
The Budapest Metro with the basic layout, using data from metrolinemap.com
The Budapest Metro and the HÉV suburban rail network, using live OSM data curated by maps.me
The Budapest Metro and the HÉV suburban rail network, using live OSM data curated by maps.me

Since the second method uses possibly the most up to date layout, it is interesting to see that because of the ongoing construction on the Blue Line of the Budapest Metro (M3), this shows up only for its currently available length (until Nagyvárad tér). Note the slight difference in color shades as well.

The Paris Metro + RER spaghetti on the OSM version of the 🚇 Metrocyclopaedia
The Paris Metro + RER spaghetti on the OSM version of the 🚇 Metrocyclopaedia
Tokyo Bay extensive network on the OSM version of the 🚇 Metrocyclopaedia
Tokyo Bay extensive network on the OSM version of the 🚇 Metrocyclopaedia
New York City and New Jersey transport systems on the OSM version of the 🚇 Metrocyclopaedia
New York City and New Jersey transit systems on the OSM version of the 🚇 Metrocyclopaedia
The massive Shanghai Metro network on the OSM version of the 🚇 Metrocyclopaedia
The massive Shanghai Metro network on the OSM version of the 🚇 Metrocyclopaedia
Seoul's rapid transit system, the world's longest, on the OSM version of the 🚇 Metrocyclopaedia
Seoul’s rapid transit system, the world’s longest, on the OSM version of the 🚇 Metrocyclopaedia

Finally, here are some simple data visualizations made in Flourish about the core metro systems (🕹 interactive).

👆 Metro systems of the world by number of systems per country 🚇 Metrocyclopaedia
👆 Metro systems of the world by number of systems per country 🚇 Metrocyclopaedia
👆 Metro systems of the world by total system length 🚇 Metrocyclopaedia
👆 Metro systems of the world by total system length 🚇 Metrocyclopaedia
👆 Metro systems of the world by number of stations 🚇 Metrocyclopaedia
👆 Metro systems of the world by number of stations 🚇 Metrocyclopaedia
👆 Metro systems of the world by number of lines 🚇 Metrocyclopaedia
👆 Metro systems of the world by number of lines 🚇 Metrocyclopaedia
👆 Metro systems of the world by number of lines 🚇 Metrocyclopaedia
Total system length vs. Population on a log-log scale
Bubble size represents number of stations

Mapping the metros systems of the world has been a great experience – and I have even discovered that there is a Transit Mapping Symposium organized each year – next one’s in Korea in Apil. So long metros, I have the feeling that we meet again!..


If you like this stuff follow my GitHubTwitter and Website. Check out more data visualizations over at my Hungarian blog. Or if it helps you a lot, consider a small donation on PayPal or in crypto.

Till next time! 😉🚇

Advertisement

Published by Dénes Csala

AI | DATA | ENERGY | SYSTEMS researcher | thinker | modeler | blogger | traveller https://csaladen.es

One thought on “Metrocyclopaedia 🚇 Interactive map of all metro systems of the world

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: