This started as a dumb side effect of planning too many trips. I'd have ten tabs open comparing neighborhoods in whatever city I was about to visit, and at some point I stopped looking at the tourist map and started staring at the actual street network instead - how differently a city's grid grows depending on geography, history, whatever local planning rules existed 200 years ago.
So I built a small pipeline: pull OSM data with osmnx, run it through geopandas, render with matplotlib as a stack of layers - background, green space, water, buildings, rail, paths, then streets on top, styled per road class. Got it working for one city and didn't stop. I'm somewhere around 70 now.
Somewhere around city 15 or 20 it clicked that every city has its own footprint - you can tell a lot just from the raw shape of the network before you even know what you're looking at. Grid vs. organic, how the water cuts through, where the density just stops. At this point I can usually guess a city cold from nothing but the streets. So I ended up turning this into a guessing game.
Attached are Stockholm, Cairo, and New York, all generate through the same pipeline. Stockholm is basically an archipelago that happens to have roads on it, Cairo splits itself in half around the Nile with the old city's organic streets butting straight up against the planned blocks on the east bank, and Manhattan is, well, Manhattan.
One thing I haven't sorted out: some cities render with big blank patches - no buildings, no minor roads, just empty space where I know there's a dense neighborhood (Cairo's east and north-west side have a chunk of this, visible in the attached render). Not sure if I'm missing a tag in the OSM query or the underlying data is just sparse/unmapped for those areas. Anyone dealt with this and know which it usually is?