I said when I was working on the bike map that I would get around to publishing the ‘source code’, and now that I’m preparing to leave the city, I feel I ought to finally do that. So! The basic idea of this post will be a step by step instruction for how to make yourself (or your city) an updated Cincinnati Bike Map. Strictly speaking, this will work for other cities too, but please note that the map was designed for Cincinnati in 2014 and other cities in other times, with different (data) structures may simply not work well at all.
Let’s get started!
Step 1: Get the software you’ll need: QGIS, PostGIS(a PostgreSQL extension), osm2pgsql, osm2po, GRASS, PHP(for one of the scripts), and Inkscape and GIMP for the final layout. All are free and open source and run on Linux (but probably other things too).
Step 2:Update the data! A big and important step. The vector data is all from OpenStreetMap and the process of editing OSM is well documented elsewhere, so I needn’t go into it at all here.
Step 3: Go to OpenStreetMap and navigate to the area you want to download. Be generous and include at least ten extra miles on all sides of the map you’ll be making. Click the ‘export’ tab and use the ‘Overpass API’. It will prompt you to download a large .osm XML file to your computer.
Step 4: Import that data into a PostGIS database twice: once with osm2pgsql and once with osm2po. The first will bring in the OSM data as-is, with as many tags as you care to import. To do it the way I did it, you should use this osm2pgsql.style file. The second one, osm2po will slice the linear path data (the streets and stuff) into a table of routable nodes and edges. For that one, you may want to try this configuration file. If that doesn’t work, the real point of it is to include paths that bikes can use (paths, pedestrian streets, stairs, etc), which are not included by default, while leaving out the rest.
Step 5: Process the data from osm2pgsql using this SQL script. It does quite a few things, including setting (short) street labels, calculating speed in mph, setting default speeds and lane-counts for no-data streets, identifying landmark buildings, and pulling a number of features into a consistent format for better/easier rendering.
Step 6: Run this SQL script to merge the two tables you’ve imported into one table that is both routable and has all of the important attributes/tags from OSM.
Step 7: Run tarjan.php on the new/duplicate segments table. This script uses Tarjan’s Algorithm to identify edges that connected at both ends to the main street network, and those that are not, leaving the results in a boolean field on that table.
Step 8: Once the dangling edges are identified, run this SQL script to drop the minor paths that go nowhere. Major dead-ending streets will be kept. Things like driveways will be dropped.
Step 9: Get the elevation data. I used data from the USGS (use their national map tool to download). I found that of the two decent resolutions available, one was too course (I could see pixels) and the other was too fine (I could see buildings). I chose to smooth out the finer data, using a neighborhood average in GRASS. I suppose you could also go at that the other way though too, increasing the resolution and then smoothing. The point is to get an amount of detail that just looks right and doesn’t have any visible pixelation: use your gut!
Step 10: Now you have all the data ready to go in your PostGIS database, and you just need to drop it into QGIS and style it. I wish things were easy enough that I could share a simple stylesheet with you; the way QGIS does it, the style information is all bound up with information about the table. That means that if your table/database/column/everything names are different from the ones I used, you’re going to have trouble making this run smoothly. In the interest of giving something here though instead of nothing, I’ll link to the QGIS map files used to render the main and inset maps (hills, transit, and trails). These may not be directly useful, but you could look at them as XML files, and see precisely how things were styled including line widths, hex colors, etc. It may also be useful to sample colors directly from the digital version of the map using something like GIMP. Once ready, export these maps as 300+DPI rasters using the following templates: main map, 1/3 scale inset maps.
Step 11: Now we have the base maps, we’re finally ready for the layout! I did the layout in Inkscape SVG, linking to the exported raster maps which I placed in an adjacent directory. You’ll have to re-link those, but the frames should still be in the right position.
Step 12: Profit.
Well, that’s about the gist of it. … I don’t actually think that hardly covers it, but there’s not enough time in the world to document everything for an uncertain future that may or may well not contain good bike maps. And anyway, I don’t expect anyone to slavishly duplicate my approach. We’ll call it a limited edition ;-)
If someone does actually want a real update though, I’m always available to answer questions, or if you’re the type to cut right to the chase, for hire. Email me!
Spotted this map while out and about yesterday (…and quickly appropriated it for the geography grad office).
People I don’t know making maps?? WHHAAAAT? How exciting! And screen-printed no less.
As everyone may or may not know, there’s no obvious and standard ontology in the world of cartography and map data, meaning that each dataset has its own way of describing and encoding the objects of the world. Its own familiar quirks. I was able to pick this out as OSM data by the too-thick blotches in the railyard, where I remembered I had failed to properly classify some of the shorter segments.
Something about the holidays lately finds me sitting at the counter at my parent’s house, editing OSM and Wiki(p/m)edia furiously between opening presents, wandering through the woods and drinking white russians. What is that? Probably that it involves short bouts of work that don’t mind my distraction and let me feel productive. Perhaps also that I discovered recently that both SORTA and TANK had very poorly developed Wikipedia pages. Or perhaps I was mostly driven by the frustrating thoroughness of the streetcar page, or the exhaustive description of the vehicles in the agency’s respective fleets, that latter thanks almost certainly to our friends at the Cincinnati Transit Historical Association.
Anyway, I’ve set about making some major changes to both pages. I hope you’ll take a look, expand on my mistakes and correct my contributions. Links above!
I was trying to de-clutter a streetmap I’m making and I found some interesting patterns along the way :-)
Cool colors are areas with more dead-ending street segments and warm colors indicate more connected streets than otherwise. That big top blob is Dayton, the lower Cincinnati sitting on the Ohio River. Disconnected streets simply cancel out connecting streets, so you can sort of consider this corrected for density.
Here is the relative intensity of dead-ending streets by themselves:
Since most streets connect to others at both ends1, the inverse of the above map doesn’t show much that the first one didn’t. It’s interesting to note the distinctly different patterns here. Clusters of connecting streets, many of their more intense appearances in gridded arrangements, form relatively distinct places. You can easily make out Hamilton, Middleton, Richmond or Oxford in the first map if you know where to look. The disconnected streets though seem to really blur recognizable places, totally changing the shape of Cincinnati and smearing it into Dayton, a visible connection not so apparent in the first map.
What’s going on in Kentucky? The rural area south of Cincinnati is a lot hillier than that to the North and there are a lot of long streets that branch out along the tops of hills and then end where the hills themselves do. In flatter places, such streets would pretty naturally just continue straight on until they met the next road.
Since you’re probably wondering if you made it this far just what counts as a connecting street, it’s a segment that connects to another at both ends. In fact, here they are below. You’re gonna want to click the image for the full resolution. Red is connecting, blue unconnected.
Create a routable topology from OSM data using osm2po.
Identify dead-ends recursively:
Identify nodes(‘source’ & ‘target’ fields) that are connected to only one edge
Identify the edges that are connected to those nodes
Isolate those edges from the rest of the network and recurse until everything you have left is connected at both ends. This took me about 20 iterations for this dataset and identified ~81,000 segments out of ~300,000
Create a centroid geometry from the linear geometry of the edges
Calculate a weight for each edge as it’s distance in miles, signed negatively for the dead-ending segments identified in #2
Compute a kernel density surface using the centroids and weight values. I used an 8KM radius, and tri-weight kernels with the QGIS raster plugin which I think is simply a GUI for GDAL.
And then I made it kind of pretty :-)
Some very long dead-ending segments appeared around the edges as a result of clipping the original dataset out of it’s global context. Concentrating their weight in a centroid resulted in strongly negative spots which simply shouldn’t exist.
Lines that turned back on themselves, or sub-networks of streets which where ultimately connected to the main network by only one edge, and which may thus reasonably be considered entirely dead ends were not identified at all.
OSM data in the US is mainly derived from low-quality TIGER data that was imported several years ago. Many rural areas seem to have an enormous number of driveway type paths identified, many of them mislabelled as residential streets. There are also some places where actual suburban driveways have been identified as dead-ends, which may or may not be misleading to some degree. Most of these however are very short and so their weight shouldn’t be overwhelming. Though that huge negative area West of Dayton is Brookville, where someone seems to have added driveways for every house in town.
Just because I think the PDF schedule maps can be terribly confusing at times, here are some route maps with more context. Click an image for a full interactive map!
And don’t forget the ‘layers’ tab over on the right of the maps. That will show you even more detail. Unlike the m+ I did last week, you can safely ignore the stops in these maps. All the stops shown are accurate, but they’re simply incomplete.
OpenStreetMap, the wiki map of the world, continues to delight me.
I’ve been slowly entering transit information over the last few months and while the effort is far from finished I’ve got most of the important lines and many of the major stops entered now. One result is the first and only web-map1 of transit services in Cincinnati.
Such a thing is useful because it allows users to dig deep into information-dense places like downtown(or their own neighborhoods) while allowing them to skim over sparse or irrelevant areas. The need for that ability is the reason most good printed transit maps exaggerate dense areas like downtowns and condense suburban service dramatically. A web map however is able to preserve topographic accuracy while filling the same need for differential detail. It’s more able to let individual users focus on what information is important to them without the designer needing to make as many assumptions.
Move around in the above map and if you see anything wrong let me know or have a go at correcting it yourself!