The classification of cycle paths in OSM

There are many tags and relations that define whether or not a “way” is a bicycl path or not. Here we will use the example of Chapeltown, taken from a tutorial on loading OSM data. The advantage of using a small subset of the data is that it can be reproduced by anyone using data that can easily be downloaded on one's home computer. So we start by loading the data:

library(osmar)
src <- osmsource_api()
bb <- center_bbox(-1.53492, 53.81934, 1000, 1200)  # set location of download
# ctown <- get_osm(bb, source = src) # uncomment if no data saved
load("data/ctown.RData")
plot(ctown)
points(-1.53492, 53.81934, col = "red", lwd = 5)

plot of chunk Preliminary plot of Chapletown with osmar

The basic plot function of osmar objects is very sparse. For insight into the cycle paths that are present in this area, we can look at the OpenCycleMap's visualisation:

Cycle paths in the study area from OpenCycleMap

This map, which can be viewed from here, illustrates bicycle paths with a blue line that is continuous if it's part of the local cycle network and dashed if it's tagged as a cyclepath. Further details are described in the key.

Another option to visualise relevant cycle infrastructure on the internet is via CycleStreets.net. Their editor shows relevant cycle path data:

Cycle paths in the study area from Cyclestreets.net editor

As illustrated in the color maps above, both roads marked with the “highway=cycleway” tag and “bicycle=yes” tag are included. Let us extract and plot these features:

# identify and extract the 'bicycle=yes' paths
byes <- find(ctown, way(tags(k == "bicycle" & v == "yes")))
byes <- find_down(ctown, way(byes))
byes <- subset(ctown, ids = byes)

# extract the 'highway=cycleway' paths
hway <- find(ctown, way(tags(k == "highway" & v == "cycleway")))
hway <- find_down(ctown, way(hway))
hway <- subset(ctown, ids = hway)

plot(ctown)
plot_ways(byes, add = T, col = "red")
plot_ways(hway, add = T, col = "green")

plot of chunk unnamed-chunk-2

The above code extracts all of the tagged cycleways in the study area but, as we will see below, there is another way to mark cycle paths: relations. In fact, it is recommended “to tag the cycle routes using relations instead of tagging the ways.”

To find out the importance of these relational tags, we will move the analysis to Cambridge, which has a much more complete cycle network than Leeds or Nottingham, visualised here.

The example of Cambridge

To test whether our method works in another context, let us try to visualise the data for cambridge on our map.

library(ggmap)
camb <- get_map(location = "Cambridge, UK", zoom = 18)
## Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=Cambridge,+UK&zoom=18&size=%20640x640&scale=%202&maptype=terrain&sensor=false
## Google Maps API Terms of Service : http://developers.google.com/maps/terms
## Information from URL : http://maps.googleapis.com/maps/api/geocode/json?address=Cambridge,+UK&sensor=false
## Google Maps API Terms of Service : http://developers.google.com/maps/terms
ggmap(camb)

plot of chunk Plot of the cambridge cycleways

bbc <- attr(camb, "bb")
(bbn <- as.numeric(attr(camb, "bb")))
## [1] 52.2043  0.1201 52.2064  0.1235
bb <- center_bbox(center_lon = bbn[2], center_lat = bbn[1], 500, 500)  # set location of download
# cam <- get_osm(bb, source = src) # uncomment if no data saved
load("data/cam.RData")
byes <- find(cam, way(tags(k == "bicycle" & v == "yes")))
byes <- find_down(cam, way(byes))
byes <- subset(cam, ids = byes)

# extract the 'highway=cycleway' paths
hway <- find(cam, way(tags(k == "highway" & v == "cycleway")))
hway <- find_down(cam, way(hway))
hway <- subset(cam, ids = hway)

# extract the 'cycleway=*' ways
cway <- find(cam, way(tags(k == "cycleway")))
cway <- find_down(cam, way(cway))
cway <- subset(cam, ids = cway)

# plot
plot_nodes(cam, xlim = c(0.114, 0.13))
plot_ways(cam, add = T)
plot_ways(byes, add = T, col = "red", lwd = 3)
plot_ways(hway, add = T, col = "green", lwd = 4)
plot_ways(cway, add = T, col = "yellow", lwd = 4)

plot of chunk Plot of the cambridge cycleways

As the above plot shows, the cycle network is sparser than one would expect, based on the “cycleway” and “bicycle” tags alone. We must also extract the relations related to bicycles.

summary(cam$relations$tag$v[grepl("cycle|ncn", cam$relations$tags$v)], 4)
##      bicycle bicycle;foot          ncn      (Other) 
##            4            1            1            1
crels <- find(cam, relation(tags(v %grep% "cycle|ncn")))
crels <- find_down(cam, relation(crels))
cw <- subset(cam, way_ids = crels$way_ids, node_ids = crels$node_ids)

plot_nodes(cam, xlim = c(0.114, 0.13))
plot_ways(cam, add = T)
plot_ways(byes, add = T, col = "red", lwd = 3)
plot_ways(hway, add = T, col = "green", lwd = 4)
plot_ways(cway, add = T, col = "yellow", lwd = 4)
plot_ways(cw, add = T, col = "blue", lwd = 3)

plot of chunk unnamed-chunk-4

Convert to shp (and then ggplot2) objects.

byesSp <- as_sp(byes, "lines")
hwaySp <- as_sp(hway, "lines")
cwaySp <- as_sp(cway, "lines")
cwSp <- as_sp(cw, "lines")
# qplot(data = fortify(cwaySp), x=long, y=lat, geom = 'line', group=group)

Now that we have converted these objects into the commonly used Sp data format (try plot(byesSp) to test this has worked), we can save them into whatever format we want. In this case we will save them as Shapefiles, to plot in QGIS. We can use a small for loop to do this:

library(rgdal)
for (i in ls()[grepl("Sp", ls())]) {
    writeOGR(get(i), dsn = "dataexclude/", layer = print(i), driver = "ESRI Shapefile")
}

This allows us to plot the data over a basemap of our choosing in QGIS. For the purposes of checking the bicycle routes, the OpenCycleMap basemap from the OpenLayers QGIS plugin is ideal. As illustrated in the resulting map, the routes we have extracted correspond to the cycle paths in the basemap.

Bicycle paths in Cambridge

Conclusion

The above examples from Leeds and Cambridge show that there are many ways of classifying bicycle paths in OSM: with 3 types of tags (bicycle=yes, highway=cycleway and cycleway=yes) and an unspecified number of relations (most of which seem to be collected via a fuzzy search for “cycle”, “ncn” and “rcn”). Because of this diversity, CycleStreets.net have developed custom filters to help identify the paths thought to be most suitable for cycling.