-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjittering.qmd
More file actions
189 lines (148 loc) · 5.05 KB
/
jittering.qmd
File metadata and controls
189 lines (148 loc) · 5.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
---
title: "OD Jittering"
author: "R Felix"
eval: false
code-fold: false
bibliography: references.bib
---
::: callout-warning
## 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 [@Lovelace2022].
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`](https://itsleeds.github.io/od/articles/od.html) package [@od].
```{r}
# Load packages
library(sf)
library(tidyverse)
library(mapview)
# install.packages("od")
library(od)
```
```{r}
# Load data
# road network
road_network = st_read("data/Lisbon/Lisbon_road_network.gpkg")
# polygons
lisbon_zones = st_read("https://github.com/U-Shift/Traffic-Simulation-Models/releases/download/2025/Freguesias_Lx.gpkg")
# OD data
od_lisbon = readRDS(url("https://github.com/U-Shift/Traffic-Simulation-Models/releases/download/2025/ODtrips_Freguesias_Lx.rds"))
od_lisbon = od_lisbon |>
filter(Bike > 0) # keep only with more than 0 bike trips
head(od_lisbon)
```
```{r}
#| eval: true
#| echo: false
#| message: false
#| warning: false
table = readRDS("data/Lisbon/ODtrips_Freguesias_Lx.rds")
head(table)
```
```{r}
# create desire lines between centroids
od_lisbon_dl = od::od_to_sf(od_lisbon, lisbon_zones)
mapview(od_lisbon_dl, zcol = "Bike")
```
{fig-align="center" width="601"}
```{r}
od_lisbon_jit = od::od_jitter(
od = od_lisbon,
z = lisbon_zones,
population_column = 8, #total trips
disag = FALSE
)
od_lisbon_jit_disag = od::od_jitter(
od = od_lisbon,
z = lisbon_zones,
population_column = 8, #total trips
disag = TRUE,
max_per_od = 200 # max trips per line
)
mapview::mapview(od_lisbon_jit, lwd = 0.2)
mapview::mapview(od_lisbon_jit_disag, lwd = 0.2)
```
:::::: columns
::: {.column width="49%"}
{fig-align="center"}
:::
::: {.column width="2%"}
:::
::: {.column width="49%"}
{fig-align="center"}
:::
::::::
See the [`od::od_jitter()`](https://itsleeds.github.io/od/reference/od_jitter.html) function for more options.
### With `odjitter` package
The same but with [Rust](https://github.com/dabreegster/odjitter), which is faster:
```{sh}
sudo apt install cargo
# (restart current shell)
# sudo apt install cmake
# install odjitter in rust
cargo install odjitter
# git clone https://github.com/dabreegster/odjitter && cd odjitter && cargo build --release && cp ./target/release/odjitter /usr/local/bin/
```
```{r}
# install odjitter in R
remotes::install_github("itsleeds/odjitter", subdir = "r")
# Load packages
library(odjitter)
```
```{r}
# Jitter with disagregation threshold of 200 trips
od_lisbon_jittered = odjitter::jitter( #jitter
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::mapview(od_lisbon_jittered, lwd = 0.2)
```

## Jittered origins and destinations
From the jittered **desire lines** to the **points** of origin and destination.
```{r}
library(stplanr)
# add an id to the jittered pairs, so we can join later
od_lisbon_jittered_id = od_lisbon_jittered
od_lisbon_jittered_id$id = 1:nrow(od_lisbon_jittered_id)
#with stplanr
od_lisbon_jittered_points = line2df(od_lisbon_jittered)
od_lisbon_jittered_points_OR = od_lisbon_jittered_points |>
select(L1, fx, fy) |> # from
rename(id = L1,
lon = fx,
lat = fy)
od_lisbon_jittered_points_DE = od_lisbon_jittered_points |>
select(L1, tx, ty) |> # to
rename(id = L1,
lon = tx,
lat = ty)
# as sf
od_lisbon_jittered_points_OR_geo = st_as_sf(od_lisbon_jittered_points_OR,
coords = c("lon", "lat"),
crs = 4326)
od_lisbon_jittered_points_DE_geo = st_as_sf(od_lisbon_jittered_points_DE,
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")
```
{fig-align="center" width="647"}
After routing with r5r, you may want to add the original O and D codes.
```{r}
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
od_lisbon_jittered_r5r = st_as_sf(as.data.frame(st_drop_geometry(od_lisbon_jittered_r5r)),
geometry = od_lisbon_jittered_r5r$geometry)
```