# Load packages
library(sf)
library(tidyverse)
library(mapview)
# install.packages("od")
library(od)
OD Jittering
Note
This page is only relevant when using travel survey data.
When having OD pairs with a macro-scale zoning, we can jitter these desire lines by randomly spread the origins and destinations points at a given area, making the trips (in particular active modes) more realistic (Lovelace, Félix, and Carlino 2022).
For that, zones, OD pairs, as well as the trip volume are needed.
Jittered desire lines
With od
package
See the example bellow, using OD tirps between districts in Lisbon, with the od
package (Lovelace and Morgan 2024).
# Load data
# road network
= st_read("data/Lisbon/Lisbon_road_network.gpkg")
road_network
# polygons
= st_read("https://github.com/U-Shift/Traffic-Simulation-Models/releases/download/2025/Freguesias_Lx.gpkg")
lisbon_zones
# OD data
= readRDS(url("https://github.com/U-Shift/Traffic-Simulation-Models/releases/download/2025/ODtrips_Freguesias_Lx.rds"))
od_lisbon = od_lisbon |>
od_lisbon filter(Bike > 0) # keep only with more than 0 bike trips
head(od_lisbon)
DICOFREor11 DICOFREde11 Car CarP Bike Walk Other Total Active
1 110601 110601 143.98 43.67 12.76 622.82 116.68 939.91 67.621368
2 110601 110602 136.85 36.10 2.74 403.72 231.32 810.73 50.135063
3 110601 110607 21.64 18.90 0.00 0.00 23.75 64.29 0.000000
4 110601 110608 133.25 5.44 0.00 8.65 377.05 524.39 1.649536
5 110601 110610 48.55 0.00 0.00 0.00 63.55 112.10 0.000000
6 110601 110611 31.18 22.83 0.00 0.00 7.28 61.29 0.000000
# create desire lines between centroids
= od::od_to_sf(od_lisbon, lisbon_zones)
od_lisbon_dl
mapview(od_lisbon_dl, zcol = "Bike")
= od::od_jitter(
od_lisbon_jit od = od_lisbon,
z = lisbon_zones,
population_column = 8, #total trips
disag = FALSE
)= od::od_jitter(
od_lisbon_jit_disag od = od_lisbon,
z = lisbon_zones,
population_column = 8, #total trips
disag = TRUE,
max_per_od = 200 # max trips per line
)
::mapview(od_lisbon_jit, lwd = 0.2)
mapview::mapview(od_lisbon_jit_disag, lwd = 0.2) mapview
See the od::od_jitter()
function for more options.
With odjitter
package
The same but with Rust, wich is faster:
# install odjitter in rust
git clone https://github.com/dabreegster/odjitter && cd odjitter && cargo build --release && cp ./target/release/odjitter /usr/local/bin/
# install odjitter in R
::install_github("dabreegster/odjitter", subdir = "r")
remotes# Load packages
library(odjitter)
# Jitter with disagregation threshold of 200 trips
= odjitter::jitter( #jitter
od_lisbon_jittered od = od_lisbon,
zones = lisbon_zones,
subpoints = road_network, # road network verices. we can choose buildings, or so
disaggregation_key = "Total",
disaggregation_threshold = 200
)
::mapview(od_lisbon_jittered, lwd = 0.2) mapview
Jittered origins and destinations
From the jittered desire lines to the points of origin and destination.
library(stplanr)
# add an id to the jittered pairs, so we can join later
= od_lisbon_jittered
od_lisbon_jittered_id $id = 1:nrow(od_lisbon_jittered_id)
od_lisbon_jittered_id
#with stplanr
= line2df(od_lisbon_jittered)
od_lisbon_jittered_points = od_lisbon_jittered_points |>
od_lisbon_jittered_points_OR select(L1, fx, fy) |> # from
rename(id = L1,
lon = fx,
lat = fy)
= od_lisbon_jittered_points |>
od_lisbon_jittered_points_DE select(L1, tx, ty) |> # to
rename(id = L1,
lon = tx,
lat = ty)
# as sf
= st_as_sf(od_lisbon_jittered_points_OR,
od_lisbon_jittered_points_OR_geo coords = c("lon", "lat"),
crs = 4326)
= st_as_sf(od_lisbon_jittered_points_DE,
od_lisbon_jittered_points_DE_geo coords = c("lon", "lat"),
crs = 4326)
mapview(od_lisbon_jittered_points_OR_geo, col.regions = "red") +
mapview(od_lisbon_jittered_points_DE_geo, col.regions = "blue")
After routing with r5r, you may want to add the original O and D codes.
= od_lisbon_jittered_r5r |>
od_lisbon_jittered_r5r mutate(id = as.integer(from_id)) |>
select(id, total_duration, total_distance, route) |>
left_join(od_lisbon_jittered_id |>
st_drop_geometry(), # drop geom for left_join
by="id")
# get geometry back
= st_as_sf(as.data.frame(st_drop_geometry(od_lisbon_jittered_r5r)),
od_lisbon_jittered_r5r geometry = od_lisbon_jittered_r5r$geometry)
References
Lovelace, Robin, Rosa Félix, and Dustin Carlino. 2022. “Jittering: A Computationally Efficient Method for Generating Realistic Route Networks from Origin-Destination Data.” Findings, April. https://doi.org/10.32866/001c.33873.
Lovelace, Robin, and Malcolm Morgan. 2024. Od: Manipulate and Map Origin-Destination Data. https://github.com/itsleeds/od.