Tools for transport planning with an emphasis on spatial transport
data and non-motorized modes. Enables common transport planning tasks including:
downloading and cleaning transport datasets; creating geographic "desire lines"
from origin-destination (OD) data; route assignment, locally and via
interfaces to routing services such as < https://cyclestreets.net/> and
calculation of route segment attributes such as bearing.
The package implements the 'travel flow aggregration' method
described in Morgan and Lovelace (2020)
stplanr is a package for sustainable transport planning with R.
It provides functions for solving common problems in transport planning and modelling, such as how to best get from point A to point B. The overall aim is to provide a reproducible, transparent and accessible toolkit to help people better understand transport systems and inform policy.
The initial work on the project was funded by the Department of
Transport
(DfT)
as part of the development of the Propensity to Cycle Tool
(PCT). The PCT uses origin-destination data as the
basis of spatial analysis and modelling work to identify where bicycle
paths are most needed. See the package vignette (e.g. via
vignette("introducing-stplanr")
) or an academic paper on the
Propensity to Cycle Tool (PCT)
for more information on how it can be used. This README gives some
basics.
stplanr should be useful to researchers everywhere. The function
route_graphhopper()
, for example, works anywhere in the world using
the graphhopper routing API and
read_table_builder()
reads-in Australian data. We welcome
contributions that make transport research easier worldwide.
Data frames representing flows between origins and destinations must be
combined with geo-referenced zones or points to generate meaningful
analyses and visualisations of ‘flows’ or origin-destination (OD) data.
stplanr facilitates this with od2line()
, which takes flow and
geographical data as inputs and outputs spatial data. Some example data
is provided in the package:
library(stplanr)data(cents, flow)
Let’s take a look at this data:
flow[1:3, 1:3] # typical form of flow data#> Area.of.residence Area.of.workplace All#> 920573 E02002361 E02002361 109#> 920575 E02002361 E02002363 38#> 920578 E02002361 E02002367 10cents[1:3,] # points representing origins and destinations#> class : SpatialPointsDataFrame#> features : 3#> extent : -1.546463, -1.511861, 53.8041, 53.81161 (xmin, xmax, ymin, ymax)#> coord. ref. : +init=epsg:4326 +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0#> variables : 4#> names : geo_code, MSOA11NM, percent_fem, avslope#> min values : E02002382, Leeds 053, 0.408759, 2.284782#> max values : E02002393, Leeds 064, 0.458721, 2.856563
These datasets can be combined as follows:
travel_network <- od2line(flow = flow, zones = cents)w <- flow$All / max(flow$All) *10plot(travel_network, lwd = w)
The package can also allocate flows to the road network, e.g. with
CycleStreets.net and the
OpenStreetMap Routing Machine
(OSRM) API interfaces.
These are supported in route_*()
functions such as
route_cyclestreets
and route_osrm()
:
Route functions take lat/lon inputs:
trip <-route_osrm(from = c(-1, 53), to = c(-1.1, 53))
and place names, found using the Google Map API:
We can replicate this call multiple times using
line2route
.
intrazone <- travel_network$Area.of.residence == travel_network$Area.of.workplacetravel_network <- travel_network[!intrazone,]t_routes <- line2route(travel_network, route_fun = route_osrm)#> Warning in summarise_impl(.data, dots): hybrid evaluation forced for#> `first`. Please use dplyr::first() or library(dplyr) to remove this#> warning.#> Warning in summarise_impl(.data, dots): hybrid evaluation forced for#> `first`. Please use dplyr::first() or library(dplyr) to remove this#> warning.#> Warning in summarise_impl(.data, dots): hybrid evaluation forced for#> `last`. Please use dplyr::last() or library(dplyr) to remove this warning.#> Warning in summarise_impl(.data, dots): hybrid evaluation forced for#> `last`. Please use dplyr::last() or library(dplyr) to remove this warning.plot(t_routes)
Another way to visualise this is with the leaflet package:
library(leaflet)leaflet() %>% addTiles() %>% addPolylines(data = t_routes)
For more examples, example("line2route")
.
overline
is a function which takes a series of route-allocated lines,
splits them into unique segments and aggregates the values of
overlapping lines. This can represent where there will be most traffic
on the transport system, as illustrated below.
t_routes$All <- travel_network$Allrnet <- overline(t_routes, attrib = "All", fun = sum)lwd <- rnet$All / mean(rnet$All)plot(rnet, lwd = lwd)points(cents)
To install the stable version, use:
install.packages("stplanr")
The development version can be installed using devtools:
# install.packages("devtools") # if not already installeddevtools::install_github("ropensci/stplanr")library(stplanr)
stplanr depends on rgdal, which can be tricky to install.
splanr depends on rgdal which can be installed on Ubuntu, for example, with:
sudo apt install r-cran-rgdal
To install gdal
binaries on other distributions please see here:
http://trac.osgeo.org/gdal/wiki/DownloadingGdalBinaries
stplanr also depends on sf. Installation instructions for Mac, Ubuntu and other Linux distros can be found here: https://github.com/r-spatial/sf#installing
Instructions to install gdal
and Quartz
are provided at
https://github.com/ropensci/geojsonio#install and
https://www.xquartz.org/ respectively (Quartz is required for R - as
described here).
The current list of available functions can be seen with:
lsf.str("package:stplanr", all = TRUE)
To get internal help on a specific function, use the standard way.
?od2line
stplanr imports many great packages that it depends on. Many thanks to the developers of these tools:
desc = read.dcf("DESCRIPTION")headings = dimnames(desc)[[2]]fields = which(headings %in% c("Depends", "Imports", "Suggests"))pkgs = paste(desc[fields], collapse = ", ")pkgs = gsub("\n", " ", pkgs)strsplit(pkgs, ",")[[1]]#> [1] "R (>= 3.0.2)" " sp (>= 1.3.1)"#> [3] " curl (>= 3.2)" " readr (>= 1.1.1)"#> [5] " dplyr (>= 0.7.6)" " httr (>= 1.3.1)"#> [7] " jsonlite (>= 1.5)" " stringi (>= 1.2.4)"#> [9] " stringr (>= 1.3.1)" " lubridate (>= 1.7.4)"#> [11] " maptools (>= 0.9.3)" " raster (>= 2.6.7)"#> [13] " rgdal (>= 1.3.4)" " rgeos (>= 0.3.28)"#> [15] " openxlsx (>= 4.1.0)" " methods"#> [17] " R.utils (>= 2.7.0)" " geosphere (>= 1.5.7)"#> [19] " Rcpp (>= 0.12.1)" " igraph (>= 1.2.2)"#> [21] " nabor (>= 0.5.0)" " rlang (>= 0.2.2)"#> [23] " lwgeom (>= 0.1.4)" " sf (>= 0.6.3)"#> [25] " testthat (>= 2.0.0)" " knitr (>= 1.20)"#> [27] " rmarkdown (>= 1.10)" " dodgr (>= 0.0.3)"
stplanr
in R doing citation(package = 'stplanr')
od_aggregate_from()
and od_aggregate_to()
provide easy ways to aggregate origin-destination pairs. See #303.overline2()
is now faster and better documented, thanks to #307route_dodgr()
function, which provides an interface to the dodgr package, accepts wider range of inputssf
method for overline()
has been updated so it calls the much faster overline2()
functionroute_local()
sum_network_routes()
fixed. See #267dl_stats19()
are depreciated. They have been split-out into the new package stats19
route_dodgr()
has now been implementedoverline2()
has been added, thanks to Malcolm Morgan. This is faster than overline()
.od
functions, a new stplanr::od_coords2line()
function, and more support of sf
route_dodgr()
has been addedosm_net_example
, has been added for local routing purposes.citation("stplanr")
@maelle
: https://ropensci.github.io/stplanr/route_graphhopper()
has been fixed, see https://github.com/ropensci/stplanr/pull/297dplyr
0.8.0: https://github.com/ropensci/stplanr/pull/275install.packages()
installs suggested packages by defaultroute_local()
line2route()
: time_sleep
waits a period between each route requestdl_stats19()
, see #270line_via()
for identifying intermediary points on a transport networkSpatialLinesNetwork()
fixed (see #249)geo_length()
returns numeric vector of line lengths from sp or sf objects.?route_graphhopper
no longer mentions the depreciated 'bike2' profile - see #246?route_osrm
mentions that the public API only routes for cars - see #246introducing-stplanr
vignette to show new function and make more robustsf::st_length()
, used in SpatialLinesNetwork()
.sfNetwork
objects: now only plots the geometry by default.SpatialLinesNetwork()
and plot()
for spatial networks.sum_network_routes()
fixed (see #240).library(stplanr)
, making it less tied to sp. This is a continuation of the work to support sf and will make it easier for the package to work with alternative representations of geographic data.geo_select_aeq.sf()
was fixed by Jakub Nowosad in pull #238od_aggregate.sf()
was fixed making it much fastergeo_bb()
supercedes bb2poly()
. The new function can return polygons, points and matrix objects determined by the output
argument. It also allows bounding boxes to be extended in metres, and scaled in x and y dimensions.geo_code()
now uses nominatim by default to find locations on the maps.od_coords()
takes a wide range of input data types to return a consistent output representing OD data as a data frame of origin and destination coordinates. This is used behind the scenes to make other functions more modular.Plans for the next release
route()
function for routing. This is more flexible and user-friendly than the existing line2route()
and route_*()
functions it enhances.route_cyclestreet()
now also called (correctly) route_cyclestreets()
geo_code()
function replaces dependency on RGoogleMapsgoogle_dist()
fixedcombinations
added to sum_network_routes()
so it runs quicker - see pull/177.sum_network_routes()
, weightfield()
and find_network_nodes()
- see e.g. example(sum_network_routes)
for details.l_poly
added.SpatialLinesNetwork()
fixed._each()
dplyr functions replaced with equivalent _at
or _all
functions. See here for more.vignette("stplanr-paper")
for details.introducing-stplanr
vignette has been updated. It now provides a more basic introduction for people new to R for spatial and transport data.line2route()
has been refactored to improve error detection and allow n_processes
arguments. Thanks @nikolai-b. See pull/151 for details.line_match()
function added, a wrapper around rgeos::gDistance()
, to find similar routes.od_aggregate()
and sp_aggregate()
have been added, to enable OD data to be aggregated to new geographic levels.#141
fixed: viaroute()
works again.bidirectional = TRUE
returns a different result in line_bearing()
now.onewayid()
is now a generic function, meaning it can handle spatial and non-spatial dataline2route()
allow you to specify variables to join-by - also has updated and more sensible defaultsod_id_order()
to put origin-destination ids in order, to identify 2 way duplicates (split out from onewayid()
)route_cyclestreet()
leading change_elev
and av_incline
being wrong now fixedNEW FEATURES
od2line()
. See example(od2line)
for an example.destinations
for showing how OD matrix with destinations can be converted to spatial datalist_output
allows the route information to be saved as a list, allowing save_raw = TRUE
(which does not return a Spatial
object) to be passed to the route_
function.BUG FIXES
line2route()
(#124) fixedNEW FEATURES
New function reproject()
is a simple wrapper around spTransform()
that uses
crs_select_aeq()
to convert a spatial object in geographic (lat/lon) coordinates
into on with projected coordinates, with units of 1 m. This is useful for various
spatial operations, such as finding the length and area of an object.
Implement gprojected()
, a function for performing GIS operations on a temporary, projected, version
of spatial objects.
Addition of line_bearing()
to return the bearing of lines based on start and end points.
Addition of angle_diff()
for finding the angular difference between lines: are they roughly parallel or perpendicular?
BUG FIXES
line2df()
now works on lines with multiple vertices and is faster.
Fixes in the examples used to illustrate how od_dist()
works.
NEW FEATURES
Update to OSRM functions to support API v5.
New parameter byvars
in the overline()
function, to allow disaggregation of results by a grouping variable (see example(overline)
).
Faster implementation of od2line()
: od2line2()
. Plan is to replace the original if no issues are found with new implementation.
New function od2odf()
which converts OD data into a dataframe of origins and destinations (feeds od2line2()
but also useful as self-standing function).
New argument new_proj
in buff_geo()
allows the results to be exported to any coordinate reference system (CRS).
New function gprojected()
generalises concept of buff_geo()
, building on crs_select_aeq()
to allow any GIS query to be conducted on a temporary projected version of spatial objects with geographical CRSs.
New function od_dist()
can quickly calculate Euclidean distances of OD pairs without converting to spatial objects.
BUG FIXES
Bug fix in onewayid()
so it captures all lines.
Various improvements to documentation and code.
NEW FEATURES
Interface to the Google Distance Matrix API with dist_google
.
New transport planning API added, with route_transportapi_public
(for testing).
Update to line2route
, allowing it to accept different routing funtions via the new argument route_fun
(for testing - tested with route_fun = route_cyclestreet
).
New functions for creating origin-destination data frames (point2odf
) and SpatialLinesDataFrames (points2flow
).
Addition of n_vertices
and is_linepoint
for identifying the number of vertices in spatial objects and whether the 'line' is really a point.
BUG FIXES
line2route
refactored, with 10 fold speed increases on large (1000+) batches of lines.NEW FEATURES
Addition of new class definition SpatialLinesNetwork
, methods for plot
and summary
and functions calc_network_routes
and find_network_nodes
allowing fast route calculations via igraph and other network analysis
functions.
Functions for removing beginning and end of lines: toptail
and
toptailgs
. Helper functions buff_geo
,
crs_select_aeq
and line2points
added.
Functionality for reading in the UK's stats19 data: read_stats19_*
functions download, unzip and re-categorise the data.
read_table
functions added for reading Australian OD data.
decode_gl
added to decode Google polylines and other functions for
querying and reading data from OSRM services.
gtfs2sldf
added to import GTFS routes as SpatialLinesDataFrames.