Friday, 29 June 2012

Leaflet vectors

Looking at a new-style speed limit made me realise that I might not have completed the speed limit tagging in Hull. I looked for a map showing speed limits as an overlay, struggled to find what I wanted and decided to put something together for myself. My last blog post about creating a map with overlays using leaflet seemed popular, so I thought I'd write up my experience here too.

I wanted to show a map with an overlay of roads that don't have a speed limit tag (maxspeed=*) so I can survey them and add the correct tag. I decided to extract all highway=* that are roads which could have speed limits, so not service roads or cycleways for example. The maxspeed tag (or absence of it) could drive an overlay to highlight missing ones and show the actual speed limits where there is a tag.

I thought I would extract the OSM data for an area, parse it to extract the relevant highways and store that in a database. Then create a page to display the map using AJAX and GeoJSON to deliver an overlay.

All of the scripts are on github, so you can download it from there. The README file includes some installation stuff to make it work for you. A working version is here, though the data will rapidly get out of date, so don't trust what you see - it is only an example.

First, get some data. I download the data for areas from Geofabrik's download server. Their service is excellent and by providing data that is less than a day old and cut into useful areas it is hard to beat. I downloaded the county data for East_Yorkshire_with_Hull. I usually download the data as .pbf a file. That can go straight into many utilities, but to use the data myself with Python I convert it to a .osm file first with osmosis.

I wrote some Python code to parse an OSM file long ago and I keep going back to it. It is included as python/osm.py. I wanted to find the ways tagged with highway. I wanted to narrow that down to a smaller group of highways: unclassified to motorways ignoring footways for example. I then wanted to load the ways into a database for use later. All of this is in the script called python/readlimits.py. My cheap and cheerful website host provides PHP and MySQL, so my database is MySQL. To draw the overlay on a map I need the list of nodes that make up the way, so I extracted them too and added them to a table too. The table layouts are in github folder database.

The script works through the ways that fit the requirements and extracts from the list of nodes that make up the way. From these it works out the most northerly, southerly, easterly and westerly of the nodes and stores this bounding box of the way. We want to show an overlay for the current part of the map being displayed and this bounding box for a way will allow that.

Loading the data for (38,000 ways and 350,000 nodes to work through) took a few minutes, loading 15,700 ways and 114,000 nodes.

Now to create a PHP script that gets called with a bounding box and returns the ways that fall, at least partially, into that area. This script will get called by an AJAX call so it needs to return data in the correct format for Leaflet to use. I use GeoJSON, which Leaflet handles well. Now we need to make a decision. Do we choose the things that get displayed and how it gets displayed in the PHP script that extracts the data or do we throw everything at the client and select there? I've decided to manage the process in the PHP. My interest is in finding which roads have no maxspeed tag, so I paint the overlay red with no tag and blue with tagged roads. The roads with a maxspeed tag get its text set for a popup, no maxspeed tag gets 'Not set'. The script is called getspeeds.php.

The HTML is simple, I create two columns side by side, managed by CSS. The map is displayed in a div, as always, this time called speedmap. The work is all done in the JavaScript showspeed.js, which has comments to guide you along. I have deliberately limited the minimum zoom to be 14 so not too much data is requested by AJAX.

I hope this will help anyone wondering about vector layers. If you have any questions, leave a comment and I'll try to answer it. If you have a better way of doing this, leave a comment linking to your solution and I'll ask you questions.

5 comments:

Matt Williams said...

In addition to your map, don't forget to also look at these few maps.

Chris Hill said...

Thanks Matt,
I tried to use ITO's maps, though I might not have looked at all of them. They show beautifully the speed limits on roads, but I found it really hard to distinguish the roads that didn't have a maxspeed tag, which was my aim.

It was also an exercise on my part to try to work through extracting and displaying vector data. My previous efforts with vectors have been around displaying them for other people's data as an overlay for their specific web sites.

Tom said...

Very helpful, thanks!

Spokes East Kent Cycle Campaign said...

I've tended to use the ITO maps to get the majority of the maxspeed coverage and then used either some searches in JOSM or some queries against a Postgres database of the data to find the last few. Usually it's just things like bridges or where a route briefly crosses a highway where I manage to miss off including the appropriate maxspeed tagging.

Chris Hill said...

@Spokes,
I like to work from surveys, so having a printed map with an overlay to take out is helpful to me. Getting a list from a database query always seems a hard way to work to me, finding and checking it in a map editor is fiddly and awkward, but each to his own.