Isochrones from Routing Engines (OSRM)

Introduction

In other posts, I have shown how to use external servers (google, craigslist etc.) to access information. You can also query a local (on your computer) server and your R session acts like a client (e.g. browser).

We can demonstrate this using (Open Source Routing Machine) OSRM server and constructing Isocrhrones. Isochrones are area you can reach from a point within a specified time. Often isochrones are used to identify gaps in the service area boundaries (e.g. 15 min distance from fire stations).

We can plot isochornes of every 2 min biking, around some random points in Orange County, NC. While we use OSRM, though any other API works as well (e.g. Google, Mapbox etc. see this blog for example.) . If you want to set other types of local routing engine, Valhalla and associated R packages might be a good option. Use whichever one suits your needs.

I am using a OSRM server. T

Setting up a OSRM server

We are going to set up a OSRM server on your computer.

  • Different OS require different instructions, so please follow the website to construct the backend for your OS.

  • Download North Carolina road network from Openstreetmap from Geofabrik for example (use the pbf file).

  • Construct a graph that can be used for finding shortest routes. Use suitably modified versions of (mind the file locations)

    - osrm-extract nc.osm.pbf -p ./profiles/bicycle.lua
    - osrm-partition nc.osrm
    - osrm-customize nc.osrm
    - osrm-routed --algorithm mld nc.osrm 

in the command window/terminal (outside R). If all goes well, this sequence of steps will create local server ready to accept your requests. The server will be ready to be queried at http://localhost:5000/ or http://127.0.0.1:5000

To get other modes, simply change the lua profile.

The following code is here for the sake of completeness and is not evaluated. it can only be evaluated with the server is runnign in the background at localhost:5000

library(osrm)
library(tidyverse)
library(sf)
library(leaflet)
library(widgetframe)

# Ideally set these options up
 options(osrm.server = "http://localhost:5000/")
options(osrm.profile = 'bike') 

randompoints <- matrix(c( -79.065443, 35.924787, -79.087353, 35.914525, -79.066203, 35.881521), 
                       ncol=2, byrow =TRUE) %>%
                      data.frame()
names(randompoints) <- c('lng', 'lat')
randompoints$name <- c('pt1', 'pt2', 'pt3')

rt <- osrmRoute(src = randompoints[1,c('name', 'lng','lat')], 
                dst = randompoints[2,c('name','lng','lat')], 
                returnclass = "sf")

m1 <- 
rt %>% leaflet() %>%
    addProviderTiles(providers$Stamen.TonerLines, group = "Basemap") %>%
  addProviderTiles(providers$Stamen.TonerLite, group = "Basemap") %>%
  addMarkers(data=randompoints[1:2,], ~lng, ~lat) %>%
  addPolylines(weight =5, smoothFactor = .5, color='red')


frameWidget(m1)

OSRM is a convenience package that is wrapping the calls to the server and parsing the output into sf classes. For example, the curl query in the backend looks like

http://localhost:5000/route/v1/biking/-78.901330,36.002806,-78.909020,36.040266

and should result in the following image

You can always shut the server down by closing the terminal/command window, after you are done with your analysis.

To get a matrix of distances and durations between multiple points,

ttmatrix <- osrmTable(loc=randompoints[, c('name', 'lng', 'lat')], measure = c('duration', 'distance'))

ttmatrix$durations should return a table similar to

pt1 pt2 pt3
pt1 0.0 22.8 32.5
pt2 22.8 0.0 25.1
pt3 32.9 25.8 0.0

Querying a OSRM server

iso <- list()
for (i in 1:nrow(randompoints)){
iso[[i]] <- osrmIsochrone(loc = randompoints[i,c('lng','lat')], breaks = seq(from = 0,to = 15, by = 2)) %>% st_as_sf()
}

iso <- do.call('rbind', iso)

 Npal <- colorNumeric(
   palette = "Reds", n = 5,
   domain = iso$center
 )
 
iso %>% leaflet() %>%
  addProviderTiles(providers$Stamen.TonerLines, group = "Basemap") %>%
  addProviderTiles(providers$Stamen.TonerLite, group = "Basemap") %>%
  addMarkers(data=randompoints, ~lng, ~lat) %>%
  addPolygons(color = "#444444", weight = 1, smoothFactor = 0.5,
    opacity = 1.0, fillOpacity = 0.5, fillColor = ~Npal(iso$center),
    group = "Isochrone") %>%
  addLegend("topleft", pal = Npal, values = ~iso$center,
            title = "Biking Time (min)",opacity = 1
            )

The result should looks similar to the following.


Exercise

  • Change the profile of the OSRM server to car and notice the differences in the Isochrones (shapes and extents).
  • Repeat the entire exercise for all the major shopping areas in the Triangle.

Conclusions

It should be obvious that having a local server might reduce latency and allow for quicker turnaround. However, there are some distinct disadvantages compared to commercial option, including but not limited to incorporating real time information, setup costs and maintenance costs. Nonetheless, it is useful to think about how these might be beneficial within an organisation.

Nikhil Kaza
Nikhil Kaza
Professor

My research interests include urbanization patterns, local energy policy and equity

Related