Title: | Manipulate and Map Origin-Destination Data |
---|---|
Description: | The aim of 'od' is to provide tools and example datasets for working with origin-destination ('OD') datasets of the type used to describe aggregate urban mobility patterns (Carey et al. 1981) <doi:10.1287/trsc.15.1.32>. The package builds on functions for working with 'OD' data in the package 'stplanr', (Lovelace and Ellison 2018) <doi:10.32614/RJ-2018-053> with a focus on computational efficiency and support for the 'sf' class system (Pebesma 2018) <doi:10.32614/RJ-2018-009>. With few dependencies and a simple class system based on data frames, the package is intended to facilitate efficient analysis of 'OD' datasets and to provide a place for developing new functions. The package enables the creation and analysis of geographic entities representing large scale mobility patterns, from daily travel between zones in cities to migration between countries. |
Authors: | Robin Lovelace [aut, cre] , Malcolm Morgan [aut] , David Cooley [ctb] |
Maintainer: | Robin Lovelace <[email protected]> |
License: | GPL-3 |
Version: | 0.5.1 |
Built: | 2024-11-06 05:44:52 UTC |
Source: | https://github.com/itsleeds/od |
Takes geographic coordinates and converts them into a data frame representing the potential flows, or 'spatial interaction', between every combination of points.
coords_to_od(p, interzone_only = FALSE, ids_only = FALSE)
coords_to_od(p, interzone_only = FALSE, ids_only = FALSE)
p |
A spatial points object or a matrix of coordinates representing points |
interzone_only |
Should the result only include interzonal OD pairs, in
which the ID of the origin is different from the ID of the destination
zone? |
ids_only |
Should a data frame with only 2 columns (origin and
destination IDs) be returned? The default is |
A data frame object with O and D codes and origin and destination coordinates.
p = sf::st_coordinates(od_data_centroids[1:3, ]) od = points_to_od(p) (od = coords_to_od(p, interzone_only = TRUE)) l = odc_to_sf(od[3:6], d = od[1:2]) l$v = 1 (l_oneway = od_oneway(l)) plot(l_oneway)
p = sf::st_coordinates(od_data_centroids[1:3, ]) od = points_to_od(p) (od = coords_to_od(p, interzone_only = TRUE)) l = odc_to_sf(od[3:6], d = od[1:2]) l$v = 1 (l_oneway = od_oneway(l)) plot(l_oneway)
This function is for aggregating OD pairs. It generally decreases the number of rows in an OD dataset, while aiming to keep the amount of travel represented in the data the same.
od_aggregate(od, aggzones = NULL, FUN = sum) od_group(od, aggzones = NULL, FUN = sum)
od_aggregate(od, aggzones = NULL, FUN = sum) od_group(od, aggzones = NULL, FUN = sum)
od |
An origin-destination data frame |
aggzones |
Points within the zones defining the OD data |
FUN |
The aggregating function to use |
An alias for the function is od_group()
.
od_aggregated = od_data_df[1:2, c(1, 2, 9)] aggzones = od::od_data_zones_min subzones = od_data_zones_small plot(aggzones$geometry) plot(subzones$geometry, add = TRUE) od = od_disaggregate(od_aggregated, aggzones, subzones) od_agg = od_aggregate(od, aggzones) names(od_agg)[1:(ncol(od_agg) - 1)] = names(od_aggregated) attr(od_aggregated, "spec") = NULL identical(sf::st_drop_geometry(od_agg), od_aggregated)
od_aggregated = od_data_df[1:2, c(1, 2, 9)] aggzones = od::od_data_zones_min subzones = od_data_zones_small plot(aggzones$geometry) plot(subzones$geometry, add = TRUE) od = od_disaggregate(od_aggregated, aggzones, subzones) od_agg = od_aggregate(od, aggzones) names(od_agg)[1:(ncol(od_agg) - 1)] = names(od_aggregated) attr(od_aggregated, "spec") = NULL identical(sf::st_drop_geometry(od_agg), od_aggregated)
This function takes an 'od data frame' with the first two columns matching IDs of spatial objects, and matches them with objects representing origins and destinations in wide range of input data types (spatial lines, points or text strings). It returns a data frame of coordinates representing movement between all origin (ox, oy) and destination (dx, dy) points.
od_coordinates(x, p = NULL, pd = NULL, silent = TRUE, sfnames = FALSE)
od_coordinates(x, p = NULL, pd = NULL, silent = TRUE, sfnames = FALSE)
x |
A data frame in which the first two columns are codes representing points/zones of origin and destination |
p |
Points representing origins and destinations |
pd |
Points representing destinations, if different from origin points |
silent |
Hide messages? |
sfnames |
Should output column names be compatible with the sf package? |
See points_to_od()
for a function that creates
an 'od data frame' from a set (or two sets) of points.
A data frame with origin and destination coordinates
x = od_data_df p = od_data_centroids res = od_coordinates(x, p)[1:2, ] class(res) res od_coordinates(x, p, sfnames = TRUE)[1:2, ] od_coordinates(x, p, silent = FALSE)[1:2, ] od_coordinates(x, p) x = od_data_df2[1:3, ] p = od_data_centroids2 pd = od_data_destinations od_coordinates(x, p, pd)
x = od_data_df p = od_data_centroids res = od_coordinates(x, p)[1:2, ] class(res) res od_coordinates(x, p, sfnames = TRUE)[1:2, ] od_coordinates(x, p, silent = FALSE)[1:2, ] od_coordinates(x, p) x = od_data_df2[1:3, ] p = od_data_centroids2 pd = od_data_destinations od_coordinates(x, p, pd)
This function takes a matrix with 4 columns representing origin and destination coordinates and returns a data frame with 3 columns with the ID of each linestring, plus the coordinates representing origin and destination coordinates. Essentially the function is a pivot, converting from wide to long format, to feed into other functions for creating geographic desire lines.
od_coordinates_ids(odc)
od_coordinates_ids(odc)
odc |
A matrix containing coordinates representing line start and end points |
od_coordinates_ids(od_coordinates(od_data_df, p = od_data_zones, sfnames = TRUE))
od_coordinates_ids(od_coordinates(od_data_df, p = od_data_zones, sfnames = TRUE))
Building data from OSM for testing od_disaggregate.
nrow(od_data_buildings) head(od_data_buildings) plot(od_data_buildings$geometry) plot(od_data_zones_min$geometry, lwd = 3, col = NULL, add = TRUE)
nrow(od_data_buildings) head(od_data_buildings) plot(od_data_buildings$geometry) plot(od_data_zones_min$geometry, lwd = 3, col = NULL, add = TRUE)
These are provided as a geographic (sf) object and a simple
data frame with longitude (X
) and latitude (Y
) columns.
The schema data can be (re-)generated using code in the
data-raw
directory.
head(od_data_coordinates)
head(od_data_coordinates)
This dataset represents geographic centroids of Output Areas in Leeds, UK.
This dataset represents geographic centroids of Output Areas in Leeds, UK.
The schema data can be (re-)generated using code in the
data-raw
directory.
The schema data can be (re-)generated using code in the
data-raw
directory.
head(od_data_centroids2) head(od_data_centroids2)
head(od_data_centroids2) head(od_data_centroids2)
This dataset represents geographic centroids of Output Areas in Leeds, UK.
The schema data can be (re-)generated using code in the
data-raw
directory.
nrow(od_data_destinations) head(od_data_destinations)
nrow(od_data_destinations) head(od_data_destinations)
Datasets representing top commuter desire lines
in Leeds based on the 2011 Census.
The first two variables of the data frame are the zone code of origin and destination, respectively.
The other columns record the number of people who travel by different modes, including
all
, train
, bus
, bicycle
and by foot
.
od_data_df_medium
is a larger dataset with the same variables, with around 10k rows.
The schema data can be (re-)generated using code in the
data-raw
directory.
od_data_df
od_data_df
This dataset represents commuter flows between Output Areas
and Workplace Zones, the most detailed open OD data in the UK.
See https://wicid.ukdataservice.ac.uk/ and the script
data-raw/od_wpz.R
in the od
package's GitHub repo.
The dataset reports (in the 3rd column) the number of people travelling between origins and destinations.
The schema data can be (re-)generated using code in the
data-raw
directory.
head(od_data_df2)
head(od_data_df2)
Route network data for Leeds
The schema data can be (re-)generated using code in the
data-raw
directory.
head(od_data_network)
head(od_data_network)
Zone datasets for packages examples
The schema data can be (re-)generated using code in the
data-raw
directory.
This dataset represents geographic zones of Lower Super Output Areas in Leeds, UK.
They fit completely within the od_data_zones_min
dataset.
The schema data can be (re-)generated using code in the
data-raw
directory.
nrow(od_data_zones_small) head(od_data_zones_small) plot(od_data_zones_small$geometry) plot(od_data_zones_min$geometry, lwd = 3, col = NULL, add = TRUE)
nrow(od_data_zones_small) head(od_data_zones_small) plot(od_data_zones_small$geometry) plot(od_data_zones_min$geometry, lwd = 3, col = NULL, add = TRUE)
This function is for splitting-up OD pairs.
It increases the number of rows in an OD dataset, while aiming
to keep the amount of travel represented in the data the same.
To take an analogy from another package, it's roughly equivalent
to tidyr::pivot_longer()
.
od_disaggregate( od, z, subpoints = NULL, code_append = "_ag", population_column = 3, max_per_od = 5, keep_ids = TRUE, integer_outputs = FALSE ) od_split( od, z, subpoints = NULL, code_append = "_ag", population_column = 3, max_per_od = 5, keep_ids = TRUE, integer_outputs = FALSE )
od_disaggregate( od, z, subpoints = NULL, code_append = "_ag", population_column = 3, max_per_od = 5, keep_ids = TRUE, integer_outputs = FALSE ) od_split( od, z, subpoints = NULL, code_append = "_ag", population_column = 3, max_per_od = 5, keep_ids = TRUE, integer_outputs = FALSE )
od |
An origin-destination data frame |
z |
Zones representing origins and destinations |
subpoints |
Points, lines or polygons within the zones. These define the OD data start/end points. |
code_append |
The name of the column containing aggregate zone names |
population_column |
The column containing the total population (if it exists) |
max_per_od |
Maximum flow in the population_column to assign per OD pair. This only comes into effect if there are enough subpoints to choose from. |
keep_ids |
Should the origin and destination ids be kept?
|
integer_outputs |
Should integer outputs be returned? |
An alias for the function is od_split()
.
od = od_data_df[1:2, c(1, 2, 9)] od zones = od::od_data_zones_min od_sf = od_to_sf(od, zones) set.seed(2021) # for reproducibility od_disag = od_disaggregate(od, zones) od_disag2 = od_disaggregate(od, zones, max_per_od = 11) plot(zones$geometry) plot(od_sf$geometry, lwd = 9, add = TRUE) plot(od_disag$geometry, col = "grey", lwd = 1, add = TRUE) plot(od_disag2$geometry, col = "green", lwd = 1, add = TRUE) table(od_disag$o_agg, od_disag$d_agg) # integer results od_disaggregate(od, zones, integer_outputs = TRUE) # with more trips per disaggregated OD pair: disag = od_disaggregate(od_data_df[1:2, ], z = zones, max_per_od = 50) plot(disag[0]) # with subpoints subpoints = sf::st_sample(zones, 100) od_disag_subpoints = od_disaggregate(od, zones, subpoints = subpoints) plot(subpoints) plot(od_disag_subpoints$geometry, add = TRUE) # with buildings data od_disag_buildings = od_disaggregate(od, zones, od_data_buildings) summary(od_disag_buildings) plot(od_data_buildings$geometry) plot(od_disag_buildings[3], add = TRUE) # mapview::mapview(od_disag_buildings) od = od_data_df[1:2, 1:4] subzones = od_data_zones_small try(od_disaggregate(od, zones, subzones)) od_disag = od_disaggregate(od, zones, subzones, max_per_od = 500) ncol(od_disag) - 3 == ncol(od) # same number of columns, the same... # Except disag data gained geometry and new agg ids: sum(od_disag[[3]]) == sum(od[[3]]) sum(od_disag[[4]]) == sum(od[[4]]) plot(od_disag) # test with road network dataset (don't run as time consuming): ## Not run: od_disag_net = od_disaggregate(od, zones, od_road_network, max_per_od = 500) plot(zones$geometry) plot(od_road_network$geometry, add = TRUE, col = "green") plot(od_disag_net$geometry, add = TRUE) mapview::mapview(zones) + od_disag_net + od_road_network ## End(Not run)
od = od_data_df[1:2, c(1, 2, 9)] od zones = od::od_data_zones_min od_sf = od_to_sf(od, zones) set.seed(2021) # for reproducibility od_disag = od_disaggregate(od, zones) od_disag2 = od_disaggregate(od, zones, max_per_od = 11) plot(zones$geometry) plot(od_sf$geometry, lwd = 9, add = TRUE) plot(od_disag$geometry, col = "grey", lwd = 1, add = TRUE) plot(od_disag2$geometry, col = "green", lwd = 1, add = TRUE) table(od_disag$o_agg, od_disag$d_agg) # integer results od_disaggregate(od, zones, integer_outputs = TRUE) # with more trips per disaggregated OD pair: disag = od_disaggregate(od_data_df[1:2, ], z = zones, max_per_od = 50) plot(disag[0]) # with subpoints subpoints = sf::st_sample(zones, 100) od_disag_subpoints = od_disaggregate(od, zones, subpoints = subpoints) plot(subpoints) plot(od_disag_subpoints$geometry, add = TRUE) # with buildings data od_disag_buildings = od_disaggregate(od, zones, od_data_buildings) summary(od_disag_buildings) plot(od_data_buildings$geometry) plot(od_disag_buildings[3], add = TRUE) # mapview::mapview(od_disag_buildings) od = od_data_df[1:2, 1:4] subzones = od_data_zones_small try(od_disaggregate(od, zones, subzones)) od_disag = od_disaggregate(od, zones, subzones, max_per_od = 500) ncol(od_disag) - 3 == ncol(od) # same number of columns, the same... # Except disag data gained geometry and new agg ids: sum(od_disag[[3]]) == sum(od[[3]]) sum(od_disag[[4]]) == sum(od[[4]]) plot(od_disag) # test with road network dataset (don't run as time consuming): ## Not run: od_disag_net = od_disaggregate(od, zones, od_road_network, max_per_od = 500) plot(zones$geometry) plot(od_road_network$geometry, add = TRUE, col = "green") plot(od_disag_net$geometry, add = TRUE) mapview::mapview(zones) + od_disag_net + od_road_network ## End(Not run)
This function takes and OD dataset and a character vector of codes and returns an OD dataset with rows matching origin and destinations zones present in the codes.
od_filter(x, codes, silent = FALSE)
od_filter(x, codes, silent = FALSE)
x |
A data frame in which the first two columns are codes representing points/zones of origin and destination |
codes |
The zone codes that must be in origins and destination |
silent |
Hide messages? |
A data frame
x = od_data_df z = od_data_zones codes = z[[1]] z_in_x_o = codes %in% x[[1]] z_in_x_d = codes %in% x[[2]] sum(z_in_x_d) sum(z_in_x_o) z = z[which(z_in_x_o | z_in_x_d)[-1], ] z[[1]] unique(c(x[[1]], x[[2]])) try(od_to_sf(x, z)) # fails nrow(x) x = od_filter(x, z[[1]]) nrow(x) od_to_sf(x, z)
x = od_data_df z = od_data_zones codes = z[[1]] z_in_x_o = codes %in% x[[1]] z_in_x_d = codes %in% x[[2]] sum(z_in_x_d) sum(z_in_x_o) z = z[which(z_in_x_o | z_in_x_d)[-1], ] z[[1]] unique(c(x[[1]], x[[2]])) try(od_to_sf(x, z)) # fails nrow(x) x = od_filter(x, z[[1]]) nrow(x) od_to_sf(x, z)
Combine two ID values to create a single ID number
od_id_szudzik(x, y, ordermatters = FALSE) od_id_max_min(x, y) od_id_character(x, y)
od_id_szudzik(x, y, ordermatters = FALSE) od_id_max_min(x, y) od_id_character(x, y)
x |
a vector of numeric, character, or factor values |
y |
a vector of numeric, character, or factor values |
ordermatters |
logical, does the order of values matter to pairing, default = FALSE |
In OD data it is common to have many 'oneway' flows from "A to B" and "B to A". It can be useful to group these an have a single ID that represents pairs of IDs with or without directionality, so they contain 'twoway' or bi-directional values.
od_id*
functions take two vectors of equal length and return a vector of IDs,
which are unique for each combination but the same for twoway flows.
the Szudzik pairing function, on two vectors of equal length. It returns a vector of ID numbers.
This function superseeds od_id_order as it is faster on large datasets
od_oneway
Other od:
od_to_odmatrix()
,
odmatrix_to_od()
(d = od_data_df[2:9, 1:2]) (id = od_id_character(d[[1]], d[[2]])) duplicated(id) od_id_szudzik(d[[1]], d[[2]]) od_id_max_min(d[[1]], d[[2]])
(d = od_data_df[2:9, 1:2]) (id = od_id_character(d[[1]], d[[2]])) duplicated(id) od_id_szudzik(d[[1]], d[[2]]) od_id_max_min(d[[1]], d[[2]])
Generate ordered ids of OD pairs so lowest is always first This function is slow on large datasets, see szudzik_pairing for faster alternative
od_id_order(x, id1 = names(x)[1], id2 = names(x)[2])
od_id_order(x, id1 = names(x)[1], id2 = names(x)[2])
x |
A data frame representing OD pairs |
id1 |
Optional (it is assumed to be the first column) text string referring to the name of the variable containing the unique id of the origin |
id2 |
Optional (it is assumed to be the second column) text string referring to the name of the variable containing the unique id of the destination |
x = data.frame(id1 = c(1, 1, 2, 2, 3), id2 = c(1, 2, 3, 1, 4)) od_id_order(x) # 4th line switches id1 and id2 so oneway_key is in order
x = data.frame(id1 = c(1, 1, 2, 2, 3), id2 = c(1, 2, 3, 1, 4)) od_id_order(x) # 4th line switches id1 and id2 so oneway_key is in order
This function takes an OD dataset and returns only the rows corresponding to movements in which the origin is different than the destination.
od_interzone(x) od_intrazone(x)
od_interzone(x) od_intrazone(x)
x |
A data frame in which the first two columns are codes representing points/zones of origin and destination |
od_data = points_to_od(od_data_centroids) nrow(od_data) nrow(od_interzone(od_data)) nrow(od_intrazone(od_data))
od_data = points_to_od(od_data_centroids) nrow(od_data) nrow(od_interzone(od_data)) nrow(od_intrazone(od_data))
These functions tackle the problem associated with OD data representing movement to and from large zones. Typically the associated desire lines start and end in one point per zone. This function produces desire lines that can start and end anywhere (or at predefined points) within each zone. See issue #11 for details.
od_jitter( od, z, subpoints = NULL, code_append = "_ag", population_column = 3, max_per_od = 1e+05, keep_ids = TRUE, integer_outputs = FALSE, zd = NULL, subpoints_o = NULL, subpoints_d = NULL, disag = FALSE )
od_jitter( od, z, subpoints = NULL, code_append = "_ag", population_column = 3, max_per_od = 1e+05, keep_ids = TRUE, integer_outputs = FALSE, zd = NULL, subpoints_o = NULL, subpoints_d = NULL, disag = FALSE )
od |
An origin-destination data frame |
z |
Zones representing origins and destinations |
subpoints |
Points, lines or polygons within the zones. These define the OD data start/end points. |
code_append |
The name of the column containing aggregate zone names |
population_column |
The column containing the total population (if it exists) |
max_per_od |
Maximum flow in the population_column to assign per OD pair. This only comes into effect if there are enough subpoints to choose from. |
keep_ids |
Should the origin and destination ids be kept?
|
integer_outputs |
Should integer outputs be returned? |
zd |
Zones with ids matching the destination codes in input OD data |
subpoints_o |
Points within origin zones representing possible destinations |
subpoints_d |
Points within destination zones representing possible destinations |
disag |
Should the od_disaggregate function be used as a 'back end' where possible? FALSE by default. See https://github.com/ITSLeeds/od/issues/39. |
An sf
data frame
# Basic example od = od_data_df z = od_data_zones_min dlr = od_jitter(od, z) # desire_lines_random desire_lines = od_to_sf(od, z) plot(z$geometry) plot(dlr["all"], add = TRUE, lwd = 3) dlr$all desire_lines$all plot(desire_lines["all"], add = TRUE, lwd = 5) # Example showing use of subpoints subpoints_o = sf::st_sample(z, 200) subpoints_d = sf::st_sample(z, 100) dlr_d = od_jitter(od, z, subpoints_o = subpoints_o, subpoints_d = subpoints_d) plot(z$geometry) plot(dlr_d$geometry, add = TRUE) plot(subpoints_o, add = TRUE) plot(subpoints_d, col = "red", add = TRUE) plot(desire_lines, add = TRUE, lwd = 5) # mapview::mapview(desire_lines) + dlr + z # interactive map sp = sf::st_sample(z, 100) dlr2 = od_jitter(desire_lines, z, subpoints_o = sp, subpoints_d = sp) plot(z$geometry) plot(sp, add = TRUE) plot(dlr2, add = TRUE, lwd = 3) plot(desire_lines, add = TRUE, lwd = 5) # Example showing jittering with origin and destination zones od = od_data_df2 z = sf::st_buffer(od_data_centroids2, dist = 1000) zd = sf::st_buffer(od_data_destinations, dist = 300) zd = zd[zd[[1]] %in% od[[2]], ] desire_lines = od_to_sf(od, od_data_centroids2, zd = od_data_destinations) dlr = od_jitter(od, z, zd = zd) plot(z$geometry) plot(od_data_centroids2$geometry, add = TRUE) plot(od_data_destinations$geometry, add = TRUE) plot(zd$geometry, add = TRUE) plot(dlr, add = TRUE, lwd = 3) plot(desire_lines, add = TRUE, lwd = 5) # Larger example with only subset of matching zones # od = od_data_df_medium # od_sf = od_to_sf(od, od_data_zones) # dlr3 = od_jitter(od_sf, od_data_zones) # plot(od_sf[od$all > 200, 1]) # plot(dlr3[od$all > 200, 1]) # mapview::mapview(od_sf$geometry[od$all > 200])
# Basic example od = od_data_df z = od_data_zones_min dlr = od_jitter(od, z) # desire_lines_random desire_lines = od_to_sf(od, z) plot(z$geometry) plot(dlr["all"], add = TRUE, lwd = 3) dlr$all desire_lines$all plot(desire_lines["all"], add = TRUE, lwd = 5) # Example showing use of subpoints subpoints_o = sf::st_sample(z, 200) subpoints_d = sf::st_sample(z, 100) dlr_d = od_jitter(od, z, subpoints_o = subpoints_o, subpoints_d = subpoints_d) plot(z$geometry) plot(dlr_d$geometry, add = TRUE) plot(subpoints_o, add = TRUE) plot(subpoints_d, col = "red", add = TRUE) plot(desire_lines, add = TRUE, lwd = 5) # mapview::mapview(desire_lines) + dlr + z # interactive map sp = sf::st_sample(z, 100) dlr2 = od_jitter(desire_lines, z, subpoints_o = sp, subpoints_d = sp) plot(z$geometry) plot(sp, add = TRUE) plot(dlr2, add = TRUE, lwd = 3) plot(desire_lines, add = TRUE, lwd = 5) # Example showing jittering with origin and destination zones od = od_data_df2 z = sf::st_buffer(od_data_centroids2, dist = 1000) zd = sf::st_buffer(od_data_destinations, dist = 300) zd = zd[zd[[1]] %in% od[[2]], ] desire_lines = od_to_sf(od, od_data_centroids2, zd = od_data_destinations) dlr = od_jitter(od, z, zd = zd) plot(z$geometry) plot(od_data_centroids2$geometry, add = TRUE) plot(od_data_destinations$geometry, add = TRUE) plot(zd$geometry, add = TRUE) plot(dlr, add = TRUE, lwd = 3) plot(desire_lines, add = TRUE, lwd = 5) # Larger example with only subset of matching zones # od = od_data_df_medium # od_sf = od_to_sf(od, od_data_zones) # dlr3 = od_jitter(od_sf, od_data_zones) # plot(od_sf[od$all > 200, 1]) # plot(dlr3[od$all > 200, 1]) # mapview::mapview(od_sf$geometry[od$all > 200])
For example, sum total travel in both directions.
od_oneway( x, attrib = names(x[-c(1:2)])[vapply(x[-c(1:2)], is.numeric, TRUE)], FUN = sum, ..., id1 = names(x)[1], id2 = names(x)[2], oneway_key = NULL )
od_oneway( x, attrib = names(x[-c(1:2)])[vapply(x[-c(1:2)], is.numeric, TRUE)], FUN = sum, ..., id1 = names(x)[1], id2 = names(x)[2], oneway_key = NULL )
x |
A data frame or SpatialLinesDataFrame, representing an OD matrix |
attrib |
A vector of column numbers or names, representing variables to be aggregated. By default, all numeric variables are selected. |
FUN |
The aggregating function such as |
... |
Further arguments passed to or used by methods |
id1 |
Optional (it is assumed to be the first column) text string referring to the name of the variable containing the unique id of the origin |
id2 |
Optional (it is assumed to be the second column) text string referring to the name of the variable containing the unique id of the destination |
oneway_key |
Optional key of unique OD pairs regardless of the order,
e.g., as generated by |
Flow data often contains movement in two directions: from point A to point B and then from B to A. This can be problematic for transport planning, because the magnitude of flow along a route can be masked by flows the other direction. If only the largest flow in either direction is captured in an analysis, for example, the true extent of travel will by heavily under-estimated for OD pairs which have similar amounts of travel in both directions. Flows in both direction are often represented by overlapping lines with identical geometries which can be confusing for users and are difficult to plot.
oneway
outputs a data frame (or sf
data frame) with rows containing
results for the user-selected attribute values that have been aggregated.
(od_min = od_data_df[c(1, 2, 1), 1:4]) od_min[3, 1:2] = rev(od_min[3, 1:2]) od_min[3, 3:4] = od_min[3, 3:4] - 5 (od_oneway = od_oneway(od_min)) nrow(od_oneway) < nrow(od_min) # result has fewer rows sum(od_min$all) == sum(od_oneway$all) # but the same total flow (od_oneway = od_oneway(od_min, FUN = mean)) od_oneway(od_min, attrib = "all") od_min$all[3] = NA (od_oneway = od_oneway(od_min, FUN = mean, na.rm = TRUE))
(od_min = od_data_df[c(1, 2, 1), 1:4]) od_min[3, 1:2] = rev(od_min[3, 1:2]) od_min[3, 3:4] = od_min[3, 3:4] - 5 (od_oneway = od_oneway(od_min)) nrow(od_oneway) < nrow(od_min) # result has fewer rows sum(od_min$all) == sum(od_oneway$all) # but the same total flow (od_oneway = od_oneway(od_min, FUN = mean)) od_oneway(od_min, attrib = "all") od_min$all[3] = NA (od_oneway = od_oneway(od_min, FUN = mean, na.rm = TRUE))
Road network data from OSM for testing od_disaggregate.
library(sf) nrow(od_road_network) head(od_road_network) plot(od_road_network$geometry) plot(od_data_zones_min$geometry, lwd = 3, col = NULL, add = TRUE)
library(sf) nrow(od_road_network) head(od_road_network) plot(od_road_network$geometry) plot(od_data_zones_min$geometry, lwd = 3, col = NULL, add = TRUE)
Todo: export this at some point
od_sample_vertices(x, fraction = 1)
od_sample_vertices(x, fraction = 1)
x |
An sf object representing a road network |
fraction |
What percent of the network to sample? |
## Not run: u = "https://github.com/ITSLeeds/od/releases/download/v0.3.1/road_network_min.Rds" f = basename(u) if (!file.exists(f)) download.file(u, f) road_network_min = readRDS(f) od_sample_vertices(road_network_min) ## End(Not run)
## Not run: u = "https://github.com/ITSLeeds/od/releases/download/v0.3.1/road_network_min.Rds" f = basename(u) if (!file.exists(f)) download.file(u, f) road_network_min = readRDS(f) od_sample_vertices(road_network_min) ## End(Not run)
Convert OD data into lines with start and end points sampled on a network
od_to_network( x, z, zd = NULL, silent = TRUE, package = "sf", crs = 4326, network = NULL )
od_to_network( x, z, zd = NULL, silent = TRUE, package = "sf", crs = 4326, network = NULL )
x |
A data frame in which the first two columns are codes representing points/zones of origin and destination |
z |
Zones representing origins and destinations |
zd |
Zones representing destinations |
silent |
Hide messages? |
package |
Which package to use to create the sf object? |
crs |
The coordinate reference system of the output, if not known in |
network |
An sf object representing a transport network |
x = od_data_df z = od_data_zones_min network = od_data_network (lines_to_points_on_network = od_to_network(x, z, network = network)) (lines_to_points = od_to_sf(x, z))
x = od_data_df z = od_data_zones_min network = od_data_network (lines_to_points_on_network = od_to_network(x, z, network = network)) (lines_to_points = od_to_sf(x, z))
This function takes a data frame representing travel between origins
(with origin codes in name_orig
, typically the 1st column)
and destinations
(with destination codes in name_dest
, typically the second column) and returns a matrix
with cell values (from attrib
, the third column by default) representing travel between
origins and destinations.
od_to_odmatrix(x, attrib = 3, name_orig = 1, name_dest = 2)
od_to_odmatrix(x, attrib = 3, name_orig = 1, name_dest = 2)
x |
A data frame representing flows between origin and destinations |
attrib |
A number or character string representing the column containing the attribute data
of interest from the |
name_orig |
A number or character string representing the zone of origin |
name_dest |
A number or character string representing the zone of destination |
Other od:
od_id
,
odmatrix_to_od()
x = od_data_df[1:4, ] x_matrix = od_to_odmatrix(x) class(x_matrix) od_to_odmatrix(x, attrib = "bicycle")
x = od_data_df[1:4, ] x_matrix = od_to_odmatrix(x) class(x_matrix) od_to_odmatrix(x, attrib = "bicycle")
Convert OD data into geographic 'desire line' objects
od_to_sf( x, z, zd = NULL, odc = NULL, silent = FALSE, filter = TRUE, package = "sfheaders", crs = 4326 ) od_to_sfc( x, z, zd = NULL, silent = TRUE, package = "sfheaders", crs = 4326, filter = TRUE )
od_to_sf( x, z, zd = NULL, odc = NULL, silent = FALSE, filter = TRUE, package = "sfheaders", crs = 4326 ) od_to_sfc( x, z, zd = NULL, silent = TRUE, package = "sfheaders", crs = 4326, filter = TRUE )
x |
A data frame in which the first two columns are codes representing points/zones of origin and destination |
z |
Zones representing origins and destinations |
zd |
Zones representing destinations |
odc |
A matrix containing coordinates representing line start and end points |
silent |
Hide messages? |
filter |
Remove rows with no matches in |
package |
Which package to use to create the sf object? |
crs |
The coordinate reference system of the output, if not known in |
x = od_data_df z = od_data_zones desire_lines = od_to_sf(x, z) desire_lines[1:3] plot(desire_lines) desire_lines_d = od_to_sf(od_data_df2, od_data_centroids2, od_data_destinations) o1 = od_data_centroids2[od_data_centroids2[[1]] == od_data_df2[[1]][1], ] d1 = od_data_destinations[od_data_destinations[[1]] == od_data_df2[[2]][1], ] plot(desire_lines_d$geometry) plot(od_data_centroids2$geometry, add = TRUE, col = "green") plot(od_data_destinations$geometry, add = TRUE) plot(o1, add = TRUE) plot(d1, add = TRUE) plot(desire_lines_d$geometry[1], lwd = 3, add = TRUE) n = 7 on = od_data_centroids2[od_data_centroids2[[1]] == od_data_df2[[1]][n], ] dn = od_data_destinations[od_data_destinations[[1]] == od_data_df2[[2]][n], ] plot(desire_lines_d$geometry) plot(on, add = TRUE) plot(dn, add = TRUE) plot(desire_lines_d$geometry[n], lwd = 3, add = TRUE)
x = od_data_df z = od_data_zones desire_lines = od_to_sf(x, z) desire_lines[1:3] plot(desire_lines) desire_lines_d = od_to_sf(od_data_df2, od_data_centroids2, od_data_destinations) o1 = od_data_centroids2[od_data_centroids2[[1]] == od_data_df2[[1]][1], ] d1 = od_data_destinations[od_data_destinations[[1]] == od_data_df2[[2]][1], ] plot(desire_lines_d$geometry) plot(od_data_centroids2$geometry, add = TRUE, col = "green") plot(od_data_destinations$geometry, add = TRUE) plot(o1, add = TRUE) plot(d1, add = TRUE) plot(desire_lines_d$geometry[1], lwd = 3, add = TRUE) n = 7 on = od_data_centroids2[od_data_centroids2[[1]] == od_data_df2[[1]][n], ] dn = od_data_destinations[od_data_destinations[[1]] == od_data_df2[[2]][n], ] plot(desire_lines_d$geometry) plot(on, add = TRUE) plot(dn, add = TRUE) plot(desire_lines_d$geometry[n], lwd = 3, add = TRUE)
Convert origin-destination coordinates into geographic desire lines
odc_to_sf(odc, d = NULL, crs = 4326)
odc_to_sf(odc, d = NULL, crs = 4326)
odc |
A matrix containing coordinates representing line start and end points |
d |
An optional data frame to add to the geometry column |
crs |
The coordinate reference system of the output, if not known in |
(odc = od_coordinates(od_data_df, p = od_data_zones, sfnames = TRUE)) (l = odc_to_sf(odc)) plot(l) lsfc = odc_to_sfc(odc)
(odc = od_coordinates(od_data_df, p = od_data_zones, sfnames = TRUE)) (l = odc_to_sf(odc)) plot(l) lsfc = odc_to_sfc(odc)
Convert origin-destination coordinates into geographic desire lines
odc_to_sfc(odc)
odc_to_sfc(odc)
odc |
A matrix containing coordinates representing line start and end points |
(odc = od_coordinates(od_data_df, p = od::od_data_zones, sfnames = TRUE)) (l = odc_to_sfc(odc)) plot(l)
(odc = od_coordinates(od_data_df, p = od::od_data_zones, sfnames = TRUE)) (l = odc_to_sfc(odc)) plot(l)
This function takes a matrix representing travel between origins
(with origin codes in the rownames
of the matrix)
and destinations
(with destination codes in the colnames
of the matrix)
and returns a data frame representing origin-destination pairs.
odmatrix_to_od(odmatrix)
odmatrix_to_od(odmatrix)
odmatrix |
A matrix with row and columns representing origin and destination zone codes and cells representing the flow between these zones. |
The function returns a data frame with rows ordered by origin and then destination
zone code values and with names orig
, dest
and flow
.
Other od:
od_id
,
od_to_odmatrix()
x = od_data_df x[1:3] odmatrix = od_to_odmatrix(od_data_df) odmatrix odmatrix_to_od(odmatrix)
x = od_data_df x[1:3] odmatrix = od_to_odmatrix(od_data_df) odmatrix odmatrix_to_od(odmatrix)
Takes a series of geographical points and converts them into a data.frame representing the potential flows, or 'spatial interaction', between every combination of points.
points_to_od( p, pd = NULL, interzone_only = FALSE, ids_only = FALSE, max_dist = Inf, max_dest = Inf ) points_to_odl(p, pd = NULL, crs = 4326, ...)
points_to_od( p, pd = NULL, interzone_only = FALSE, ids_only = FALSE, max_dist = Inf, max_dest = Inf ) points_to_odl(p, pd = NULL, crs = 4326, ...)
p |
A spatial points object or a matrix of coordinates representing points |
pd |
Optional spatial points object objects representing
destinations.
|
interzone_only |
Should the result only include interzonal OD pairs, in
which the ID of the origin is different from the ID of the destination
zone? |
ids_only |
Should a data frame with only 2 columns (origin and
destination IDs) be returned? The default is |
max_dist |
Numeric, maximum distance to consider. Default Inf.
Not applicable when |
max_dest |
The maximum number of destinations for each origin (numeric)
sorted from closest to furthest. Default is Inf. Alternative to max_dist
for limiting the number of ODs.
Not applicable when |
crs |
The coordinate reference system of the output, if not known in |
... |
Additional arguments passed to |
points_to_odl()
generates the same output but returns a geographic object
representing desire lines in the class sf
.
library(sf) p = od_data_centroids[1:2, ] points_to_od(p) points_to_od(p, ids_only = TRUE) (l = points_to_odl(p, interzone_only = TRUE)) plot(l) points_to_od(od_data_centroids[1:2, ], od_data_centroids[3, ]) l = points_to_odl(od_data_centroids[1:2, ], od_data_centroids[3, ]) plot(l) (od = points_to_od(p, interzone_only = TRUE)) l2 = od_to_sf(od, od_data_centroids) l2$v = 1 (l2_oneway = od_oneway(l2)) sf::st_length(l2) # With max_dist: if (require(nngeo)) { (l3 = points_to_odl(p, max_dist = 10000)) sf::st_length(l3) }
library(sf) p = od_data_centroids[1:2, ] points_to_od(p) points_to_od(p, ids_only = TRUE) (l = points_to_odl(p, interzone_only = TRUE)) plot(l) points_to_od(od_data_centroids[1:2, ], od_data_centroids[3, ]) l = points_to_odl(od_data_centroids[1:2, ], od_data_centroids[3, ]) plot(l) (od = points_to_od(p, interzone_only = TRUE)) l2 = od_to_sf(od, od_data_centroids) l2$v = 1 (l2_oneway = od_oneway(l2)) sf::st_length(l2) # With max_dist: if (require(nngeo)) { (l3 = points_to_odl(p, max_dist = 10000)) sf::st_length(l3) }
This functions takes point geometries with class sfc
from the sf
package
and returns a matrix representing x and y (typically lon/lat) coordinates.
sfc_point_to_matrix(x)
sfc_point_to_matrix(x)
x |
An |
See https://github.com/dcooley/sfheaders/issues/52 for details
Dave Cooley
sfc_point_to_matrix(od_data_centroids$geometry[1:6])
sfc_point_to_matrix(od_data_centroids$geometry[1:6])