Skip to content

Commit 5133e5d

Browse files
committed
Merge branch 'master' of https://github.com/ITSLeeds/TDS
2 parents 16fc6e6 + 468baed commit 5133e5d

19 files changed

Lines changed: 569 additions & 172 deletions

practicals/2-od.Rmd

Lines changed: 156 additions & 137 deletions
Large diffs are not rendered by default.

practicals/2-od.md

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
Origin-destination data
2+
================
3+
Malcolm Morgan and Robin Lovelace
4+
University of Leeds
5+
<br/><img class="img-footer" alt="" src="https://comms.leeds.ac.uk/wp-content/themes/toolkit-wordpress-theme/img/logo.png">
6+
7+
# 1 Review Homework
8+
9+
You should now be familiar with the basics of R and the `tidyverse`. If
10+
you have not completed these tasks go back and do them first:
11+
12+
- Read Chapters 2, 3, and 4 of [Reproducible road safety research with
13+
R](https://itsleeds.github.io/rrsrr/basics.html)
14+
- Read Chapters 3 and 5 of [R for Data
15+
Science](https://r4ds.had.co.nz/data-visualisation.html)
16+
17+
# 2 Getting started with GIS in R
18+
19+
Note that this practical takes sections from Chapters 2 - 8 of
20+
[Geocomputation with R](https://r.geocompx.org). You should expand your
21+
knowledge by reading these chapters in full.
22+
23+
## Pre-requisites
24+
25+
You need to have a number of packages installed and loaded. Install the
26+
packages by typing in the following commands into RStudio (you do not
27+
need to add the comments after the `#` symbol)
28+
29+
If you need to install any of these packages use:
30+
31+
``` r
32+
install.packages("sf") # Install a package from CRAN
33+
remotes::install_github("Nowosad/spDataLarge") # install from GitHub using the remotes package
34+
```
35+
36+
``` r
37+
library(sf) # vector data package
38+
library(tidyverse) # tidyverse packages
39+
```
40+
41+
- It relies on **spData**, which loads datasets used in the code
42+
examples of this chapter:
43+
44+
``` r
45+
library(spData) # spatial data package
46+
```
47+
48+
1. Check your packages are up-to-date with `update.packages()`
49+
2. Create an RStudio project with an appropriate name for this session
50+
(e.g. `practical2`)
51+
3. Create appropriate folders for code, data and anything else
52+
(e.g. images)
53+
4. Create a script called `learning-OD.R`, e.g. with the following
54+
command:
55+
56+
``` r
57+
dir.create("code") #
58+
file.edit("code/learning-OD.R")
59+
```
60+
61+
## 2.1 Basic sf operations
62+
63+
We will start with a simple map of the world. Load the `world` object
64+
from the `spData` package. Notice the use of `::` to say that you want
65+
the `world` object from the `spData` package.
66+
67+
``` r
68+
world = spData::world
69+
```
70+
71+
Use some basic R functions to explore the `world` object.
72+
e.g. `class(world)`, `dim(world)`, `head(world)`, `summary(world)`. Also
73+
view the `world` object by clicking on it in the Environment panel.
74+
75+
`sf` objects can be plotted with `plot()`.
76+
77+
``` r
78+
plot(world)
79+
```
80+
81+
![](2-od_files/figure-gfm/unnamed-chunk-5-1.png)<!-- -->
82+
83+
Note that this makes a map of each column in the data frame. Try some
84+
other plotting options
85+
86+
``` r
87+
plot(world[3:6])
88+
```
89+
90+
![](2-od_files/figure-gfm/unnamed-chunk-6-1.png)<!-- -->
91+
92+
``` r
93+
plot(world["pop"])
94+
```
95+
96+
![](2-od_files/figure-gfm/unnamed-chunk-6-2.png)<!-- -->
97+
98+
## 2.2 Basic spatial operations
99+
100+
Load the `nz` and `nz_height` datasets from the `spData` package.
101+
102+
``` r
103+
nz = spData::nz
104+
nz_height = spData::nz_height
105+
```
106+
107+
We can use `tidyverse` functions like `filter` and `select` on `sf`
108+
objects in the same way you did in Practical 1.
109+
110+
``` r
111+
canterbury = nz %>% filter(Name == "Canterbury")
112+
canterbury_height = nz_height[canterbury, ]
113+
```
114+
115+
In this case we filtered the `nz` object to only include places called
116+
`Canterbury` and then did and intersection to find objects in the
117+
`nz_height` object that are in Canterbury.
118+
119+
This syntax is not very clear. But is the equivalent to
120+
121+
``` r
122+
canterbury_height = nz_height[canterbury, , op = st_intersects]
123+
```
124+
125+
There are many different types of relationships you can use with `op`.
126+
Try `?st_intersects()` to see more. For example this would give all the
127+
places not in Canterbury
128+
129+
``` r
130+
nz_height[canterbury, , op = st_disjoint]
131+
```
132+
133+
![Topological relations between vector geometries, inspired by Figures 1
134+
and 2 in Egenhofer and Herring (1990). The relations for which the
135+
function(x, y) is true are printed for each geometry pair, with x
136+
represented in pink and y represented in blue. The nature of the spatial
137+
relationship for each pair is described by the Dimensionally Extended
138+
9-Intersection Model
139+
string.](https://r.geocompx.org/figures/relations-1.png)
140+
141+
# 3 Getting started with OD data
142+
143+
In this section we will look at basic transport data in the R package
144+
**stplanr**.
145+
146+
Load the `stplanr` package as follows:
147+
148+
``` r
149+
library(stplanr)
150+
```
151+
152+
## Warning: package 'stplanr' was built under R version 4.2.2
153+
154+
The `stplanr` package contains some data that we can use to demonstrate
155+
principles in Data Science, illustrated in the Figure below. Source:
156+
Chapter 1 of R for Data Science (Grolemund and Wickham 2016) [available
157+
online](https://r4ds.had.co.nz/introduction.html).
158+
159+
![](https://d33wubrfki0l68.cloudfront.net/571b056757d68e6df81a3e3853f54d3c76ad6efc/32d37/diagrams/data-science.png)
160+
161+
First we will load some sample data:
162+
163+
You can click on the data in the environment panel to view it or use
164+
`head(od_data)` Now we will rename one of the columns from `foot` to
165+
`walk`
166+
167+
Next we will made a new dataset `od_data_walk` by taking `od_data` and
168+
piping it (`%>%`) to `filter` the data frame to only include rows where
169+
`walk > 0`. Then `select` a few of the columns and calculate two new
170+
columns `proportion_walk` and `proportion_drive`.
171+
172+
We can use the generic `plot` function to view the relationships between
173+
variables
174+
175+
``` r
176+
plot(od_data_walk)
177+
```
178+
179+
![](2-od_files/figure-gfm/unnamed-chunk-15-1.png)<!-- -->
180+
181+
R has built in modelling functions such as `lm` lets make a simple model
182+
to predict the proportion of people who walk based on the proportion of
183+
people who drive.
184+
185+
We can use the `ggplot2` package to graph our model predictions.
186+
187+
``` r
188+
ggplot(od_data_walk) +
189+
geom_point(aes(proportion_drive, proportion_walk)) +
190+
geom_line(aes(proportion_drive, proportion_walk_predicted))
191+
```
192+
193+
![](2-od_files/figure-gfm/unnamed-chunk-17-1.png)<!-- -->
194+
195+
Exercises
196+
197+
1. What is the class of the data in `od_data`?
198+
2. Subset (filter) the data to only include OD pairs in which at least
199+
one person (`> 0`) person walks (bonus: on what % of the OD pairs
200+
does at least 1 person walk?)
201+
3. Calculate the percentage who cycle in each OD pair in which at least
202+
1 person cycles
203+
4. Is there a positive relationship between walking and cycling in the
204+
data?
205+
5. Bonus: use the function `od2line()` in to convert the OD dataset
206+
into geographic desire lines
207+
208+
# 4 Processing origin-destination data in Bristol
209+
210+
This section is based on [Chapter 12 of Geocomputation with
211+
R](https://geocompr.robinlovelace.net/transport.html). You should read
212+
this chapter in full in your own time.
213+
214+
We need the `stplanr` package which provides many useful functions for
215+
transport analysis and `tmap` package which enables advanced mapping
216+
features.
217+
218+
``` r
219+
library(stplanr)
220+
library(tmap)
221+
```
222+
223+
We will start by loading two datasets:
224+
225+
``` r
226+
od = spDataLarge::bristol_od
227+
zones = spDataLarge::bristol_zones
228+
```
229+
230+
Explore these datasets using the functions you have already learnt
231+
(e.g. `head`,`nrow`).
232+
233+
You will notice that the `od` datasets has shared id values with the
234+
`zones` dataset. We can use these to make desire lines between each
235+
zone. But first we must filter out trips that start and end in the same
236+
zone.
237+
238+
``` r
239+
od_inter = filter(od, o != d)
240+
desire_lines = od2line(od_inter, zones)
241+
```
242+
243+
Let’s calculate the percentage of trips that are made by active travel
244+
245+
``` r
246+
desire_lines$Active = (desire_lines$bicycle + desire_lines$foot) /
247+
desire_lines$all * 100
248+
```
249+
250+
Now use `tmap` to make a plot showing the number of trips and the
251+
percentage of people using active travel.
252+
253+
``` r
254+
desire_lines = desire_lines[order(desire_lines$Active),]
255+
256+
tm_shape(desire_lines) + # Define the data frame used to make the map
257+
tm_lines(col = "Active", # We want to map lines, the colour (col) is based on the "Active" column
258+
palette = "plasma", # Select a colour palette
259+
alpha = 0.7, # Make lines slightly transparent
260+
lwd = "all") + # The line width (lwd) is based on the "all" column
261+
tm_layout(legend.outside = TRUE) + # Move the ledgend outside the map
262+
tm_scale_bar() # Add a scale bar to the map
263+
```
264+
265+
![](2-od_files/figure-gfm/unnamed-chunk-27-1.png)<!-- -->
266+
267+
Now that we have geometry attached to our data we can calculate other
268+
variables of interest. For example let’s calculate the distacne
269+
travelled and see if it relates to the percentage of people who use
270+
active travel.
271+
272+
``` r
273+
desire_lines$distance_direct_m = as.numeric(st_length(desire_lines))
274+
```
275+
276+
Note the use of `as.numeric` by default `st_length` and many other
277+
functions return a special type of result with `unit`. Here we force the
278+
results back into the basic R numerical value. But be careful! The units
279+
you get back depend on the coordinate reference system, so check your
280+
data before you assume what values mean.
281+
282+
``` r
283+
ggplot(desire_lines) +
284+
geom_point(aes(x = distance_direct_m, y = Active, size = all)) +
285+
geom_smooth(aes(x = distance_direct_m, y = Active))
286+
```
287+
288+
![](2-od_files/figure-gfm/unnamed-chunk-29-1.png)<!-- -->
289+
290+
The blue line is a smoothed average of the data. It shows a common
291+
concept in transport research, the distance decay curve. In this case it
292+
shows that the longer the journey the less likely people are to use
293+
active travel. But this concept applies to all kinds of travel
294+
decisions. For example you are more likely to travel to a nearby coffee
295+
shop than a far away coffee shop. Different types of trip have different
296+
curves, but most people always have a bias for shorter trips.
297+
298+
# 5 Homework
299+
300+
1. Read Chapters 2-5 of [Geocomputation with
301+
R](https://r.geocompx.org/transport.html)
302+
2. Work though Sections 13.1 to 13.4 of the Transport Chapter in
303+
[Geocomputation with R](https://r.geocompx.org/transport.html)
304+
3. Bonus: Read more about using the [tmap
305+
package](https://r-tmap.github.io/tmap/)
306+
4. Bonus: Read more about the [ggplot2
307+
package](https://ggplot2.tidyverse.org/)
308+
5. Bonus: Read Chapter 7 & 8 of [Geocomputation with
309+
R](https://r.geocompx.org/transport.html)
310+
311+
# 6 References
312+
313+
<div id="refs" class="references csl-bib-body hanging-indent">
314+
315+
<div id="ref-grolemund_r_2016" class="csl-entry">
316+
317+
Grolemund, Garrett, and Hadley Wickham. 2016. *R for Data Science*.
318+
O’Reilly Media.
319+
320+
</div>
321+
322+
</div>
13.8 KB
Loading
5.83 KB
Loading
33.4 KB
Loading
10.2 KB
Loading
16 KB
Loading
13.8 KB
Loading
10.6 KB
Loading

0 commit comments

Comments
 (0)