-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path04-making-maps.Rmd
423 lines (331 loc) · 15.2 KB
/
04-making-maps.Rmd
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# Making maps in R
This chapter requires the following packages:
```{r 04-making-maps-1}
#| message = FALSE
library(tmap)
library(sf)
library(terra)
```
Additionally, we will use three datasets:
- `nz`: a set of polygons representing 16 regions of New Zealand
- `nz_ports`: a point dataset with locations of New Zealand main ports
- `nz_elev`: an elevation raster data of the New Zealand area
```{r 04-making-maps-2}
#| message = FALSE
library(spData)
data("nz")
nz_ports <- read_sf("data/nz_ports.gpkg")
nz_elev <- rast(system.file("raster/nz_elev.tif", package = "spDataLarge"))
```
## Mapping tools in R
R has many packages dedicated to spatial data visualizations.
They include tools for making both static maps, interactive maps, specific-purpose maps, animations, etc.
Packages for creating static maps include {graphics}, {rasterVis}, {ggplot2}, {ggspatial}, {mapsf}, {tidyterra}, etc.
Interactive maps' packages are, for example, {leaflet}, {mapview}, {mapdeck}.
Specific-purpose mapping can be achieved with {cartogram} (to construct area cartograms), {geofacet} ("geofaceting"), {geogrid} (to turn polygons into regular or hexagonal grids), and {rayshader} (raytracing to produce 2D and 3D data visualizations).
In this workshop, we will focus on the {tmap} package.
It accepts spatial data in various formats, allows to create static and interactive maps, and makes it possible to create small multiples map and map animations.
## Basic example
The code below shows a basic example of the {tmap} use:
```{r 04-making-maps-3}
tm_shape(nz) +
tm_graticules() +
tm_polygons(col = "Median_income", title = "Median income (USD)") +
tm_shape(nz_ports) +
tm_symbols(size = 0.75) +
tm_scale_bar(breaks = c(0, 100, 200)) +
tm_compass(position = c("right", "top")) +
tm_layout(bg.color = "lightblue")
```
It combines eight function calls using the `+` operator to create the above map.
Each function can be adjusted using its arguments.
We can divide the above tmap functions into a few groups:
- shapes and layers: `tm_shape()`, `tm_polygons()`, `tm_symbols()`.
They are used to read the spatial data and specify how it should be presented.
- attribute layers: `tm_graticules()`, `tm_scale_bar()`, `tm_compass()`.
They add additional information.
- other map elements: `tm_layout()`.
It specifies the overall map look, including its background color or title.
We expand the explanation of these functions in the next few sections.
## Shapes and layers
A simple instance of a (t)map consists of specifying spatial object with `tm_shape()` (this can be, for example, an {sf} vector or a {terra} raster) and then how this object should be visualized.
For example, the code below takes the `nz` object (sf object with polygons) and plots it as polygons:
```{r 04-making-maps-4}
tm_shape(nz) +
tm_polygons()
```
Table \@ref(tab:04-making-maps-5) gives a list of basic map layers allowed by {tmap}.
We can use different functions depending on our input spatial data type.
```{r 04-making-maps-5}
#| echo = FALSE
map_layers <- data.frame(Geometry = c("polygons", "points, lines, and polygons",
"lines", "raster", "points, lines, and polygons"),
Function = c("`tm_polygons()`", "`tm_symbols()`",
"`tm_lines()`", "`tm_raster()`",
"`tm_text()`"))
knitr::kable(map_layers, caption = "Basic map layers")
```
As we have seen above, polygons can be visualized with `tm_polygons()`; however, we can also show them using `tm_symbols()` or `tm_text()`:
```{r}
tm_shape(nz) +
tm_symbols()
```
Each map layer can be adjusted.
For example, `tm_polygons()` can be represented by either:
- one consistent color (e.g., `col = "darkblue"`)
- unique colors for adjacent polygons (`col = "MAP_COLORS"`)
- color representing values of a given variable (`col = Median_income`)
One consistent color may be set with [a color name](https://www.stat.columbia.edu/~tzheng/files/Rcolor.pdf) or a hex color code:
```{r 04-making-maps-6}
tm_shape(nz) +
tm_polygons(col = "darkblue") #or #00008b
```
To use unique colors for adjacent polygons we need to use `col = "MAP_COLORS"`:
```{r 04-making-maps-7}
tm_shape(nz) +
tm_polygons(col = "MAP_COLORS")
```
We also can provide a variable name to color each polygon based on its value (note: you can check your variables names with `head(nz)`).
Let's create a choropleth map of the `"Median_income"` variable:
```{r 04-making-maps-9}
tm_shape(nz) +
tm_polygons(col = "Median_income")
```
Next, we customize the map with additional arguments, such as `title` to change the legend title or `palette` to provide a name of the color palette to use:
```{r 04-making-maps-10}
tm_shape(nz) +
tm_polygons(col = "Median_income", title = "Median income (USD)",
palette = "viridis")
```
The {tmap} package accepts names of a few dozens of color palettes (note: try `tmaptools::palette_explorer()`), but it is also possible to provide a vector of colors here.
By default, {tmap} behaves differently depending on the input variable type, e.g., uses unique colors for categorical variables and pretty breaks for continuous variables.
We can use [the `style` argument](https://geocompr.github.io/post/2019/tmap-color-scales/) if we want to change the color breaks.
For example, `style = "cont"` creates a continuous color gradient:
```{r 04-making-maps-12}
tm_shape(nz) +
tm_polygons(col = "Median_income", title = "Median income (USD)",
palette = "viridis", style = "cont")
```
Many spatial objects and their related map layers can be connected with the `+` operator.
Importantly, subsequent map layers are drawn on top of the previous ones:
```{r 04-making-maps-13}
tm_shape(nz) +
tm_polygons(col = "Median_income", title = "Median income (USD)",
palette = "viridis", style = "cont") +
tm_shape(nz_ports) +
tm_symbols()
```
The previous examples used spatial vector data.
However, plotting raster data works in the same fashion -- we need to provide a spatial object with `tm_shape()`, and then plot it with `tm_raster()`:
```{r 04-making-maps-14}
#| message = FALSE
tm_shape(nz_elev) +
tm_raster(title = "Elevation (m asl)",
palette = "-Spectral", style = "cont") +
tm_shape(nz_ports) +
tm_symbols()
```
The tmap functions do not only result in a plot, but their output can be also attach to an R object:
```{r 04-making-maps-15}
tm <- tm_shape(nz) +
tm_polygons(col = "Median_income", title = "Median income (USD)",
palette = "viridis", style = "cont") +
tm_shape(nz_ports) +
tm_symbols()
```
This is useful when we want to add new layers to our map or save it to a file.
## Attributes layers
Attributes layers allow to draw often used map elements, such as [graticules](https://geocompr.github.io/post/2019/tmap-grid/), scale bars, north arrows, logos, or credits (Table \@ref(tab:04-making-maps-16)).
```{r 04-making-maps-16}
#| echo = FALSE
attr_layers <- data.frame(Description = c("draws latitude and longitude graticules",
"adds a scale bar", "adds a compass rose",
"adds a logo", "adds a text annotation"),
Function = c("`tm_graticules()`", "`tm_scale_bar()`",
"`tm_compass()`", "`tm_logo()`", "`tm_credits()`"))
knitr::kable(attr_layers, caption = "Basic attributes layers")
```
We can add these elements to our previous map with the following code:
```{r 04-making-maps-17}
#| message = FALSE
tm +
tm_graticules() +
tm_scale_bar(breaks = c(0, 100, 200)) +
tm_compass(position = c("right", "top")) +
tm_logo("https://foss4g.org/logos/2022-v2.png") +
tm_credits("N. Roelandt and J. Nowosad")
```
Each map element can be also customized (e.g., by specifying breaks for the scale bar or a text in the credits), and its location can be set with `position`.
Let's save our new map to the `tm2` object:
```{r 04-making-maps-18}
#| message = FALSE
tm2 <- tm +
tm_graticules() +
tm_scale_bar(breaks = c(0, 100, 200)) +
tm_compass(position = c("right", "top")) +
tm_logo("https://foss4g.org/logos/2022-v2.png") +
tm_credits("N. Roelandt and J. Nowosad")
```
## Other map elements
The {tmap} also has some other map elements.
It includes `tm_add_legend()` that allows to add a manual legend by specifying its type, color, and title.
In the example below, we also use `tm_layout()` -- this function specifies the overall map look, including its background color, title, fonts, etc.
```{r 04-making-maps-19}
#| message = FALSE
tm2 +
tm_add_legend(type = "symbol", col = "grey", title = "Main ports") +
tm_layout(main.title = "New Zealand", bg.color = "lightblue")
```
Here, we save our new map to the `tm3` object:
```{r 04-making-maps-20}
tm3 <- tm2 +
tm_add_legend(type = "symbol", col = "grey", title = "Main ports") +
tm_layout(main.title = "New Zealand", bg.color = "lightblue")
```
## Interactive mode
Each map created with {tmap} can be viewed in either `"plot"` and `"view"` mode: the default `"plot"` mode returns a static map, while the `"view"` mode results in an interactive map.
We can change the mode with `tmap_mode()`:
```{r 04-making-maps-21}
tmap_mode("view")
```
Then we just need to open the map object (or write a (t)map code):
```{r}
#| collapse = TRUE,
#| results = "hold"
tm3
```
As you can see above, the interactive mode has the same map layers, colors, and legend.
However, both modes have their own features.
For example, `tm_compass()`, `tm_logo()`, and `tm_credits()` only work in the static mode.
On the other hand, the interactive mode allows for zooming or panning, and also makes it possible to select and change the background tiles.^[Try `tm_basemap()` and `tm_tiles()` if you want to customize the interactive tiles.] We can also add some map elements available for interactive mode only, such as `tm_minimap()` or `tm_mouse_coordinates()`.
```{r 04-making-maps-22}
#| collapse = TRUE,
#| results = "hold"
tm3 +
tm_minimap() +
tm_mouse_coordinates()
```
To return to the static mode, we need to use `tmap_mode("plot")`:
```{r 04-making-maps-23}
#| message = FALSE
tmap_mode("plot")
tm3
```
## Saving maps
Maps created with {tmap} can be saved to various file formats.
It includes `.png` for raster graphic files, `.svg` for vector graphic files, or even `.html` to save an interactive map.
All of the saving can be done with `tmap_save()`, which accepts the map object and a file path.
It also allows customizing the output map resolution.
```{r 04-making-maps-24}
#| eval = FALSE
tmap_save(tm3, "my_map.png")
tmap_save(tm3, "my_map.svg")
tmap_save(tm3, "my_map.html")
```
:::: {.infobox .tip data-latex="note"}
Note that some {tmap} functions have a `tm_` prefix, while other a `tmap_` prefix.
This syntax allows to distinct between making maps functions (e.g., `tm_shape()` or `tm_polygons()`) and other functions (e.g., `tmap_save()`).
::::
## What else?
The above examples showed basic (and probably the most often used) features of {tmap}.
However, this package has much more to offer, including:
- Facet maps: using `tm_facets()` to create small multiples map
- Animations: using `tm_facets()` + `tmap_animation()` to create map animations
- Mapping applications: using the {shiny} package with `renderTmap()`, `tmapOutput()`, etc.
- `tmap_tip()`
## More resources
For more resources check [the {tmap} repo](https://github.com/r-tmap/tmap), read [the tmap book (work in progress)](https://r-tmap.github.io/tmap-book) and [the Making maps with R chapter](https://geocompr.robinlovelace.net/adv-map.html).
## Exercises
Read the following datasets:
```{r}
srtm <- rast(system.file("raster/srtm.tif", package = "spDataLarge"))
zion <- read_sf((system.file("vector/zion.gpkg", package = "spDataLarge")))
zion_points <- read_sf(system.file("vector/zion_points.gpkg", package = "spDataLarge"))
```
E1. Create a simple map using {tmap} with three map layers: (1) `srtm` (colored based on its values), (2) `zion` (as a grey polygon), (3) `zion_points` (as grey symbols).
```{r}
#| include = FALSE
tm_shape(srtm) +
tm_raster() +
tm_shape(zion) +
tm_polygons(alpha = 0.3) +
tm_shape(zion_points) +
tm_symbols()
```
E2. Customize the map from E1, for example by: improving the legend title, changing the color palette, etc.
```{r}
#| include = FALSE
tm_shape(srtm) +
tm_raster(style = "cont", palette = "-Spectral", title = "Elevation (m als)") +
tm_shape(zion) +
tm_polygons(alpha = 0.3) +
tm_shape(zion_points) +
tm_symbols(shape = 6, col = "black")
```
E3. Add some attribute layers to your map, including the scale bar and north arrow.
Also, add your name in the bottom left corner of the map.
```{r}
#| include = FALSE
tm_shape(srtm) +
tm_raster(style = "cont", palette = "-Spectral", title = "Elevation (m als)") +
tm_shape(zion) +
tm_polygons(alpha = 0.3) +
tm_shape(zion_points) +
tm_symbols(shape = 6, col = "black") +
tm_scale_bar(position = c("left", "bottom"), breaks = c(0, 2, 4)) +
tm_compass(position = c("right", "top")) +
tm_credits("My Name", position = c("left", "bottom"))
```
E4. Try to adjust the overall map look by, for example, removing the map frame and adding a map title.
```{r}
#| include = FALSE
tm_shape(srtm) +
tm_raster(style = "cont", palette = "-Spectral", title = "Elevation (m als)") +
tm_shape(zion) +
tm_polygons(alpha = 0.3) +
tm_shape(zion_points) +
tm_symbols(shape = 6, col = "black") +
tm_scale_bar(position = c("left", "bottom"), breaks = c(0, 2, 4)) +
tm_compass(position = c("right", "top")) +
tm_credits("My Name", position = c("left", "bottom")) +
tm_layout(frame = FALSE, main.title = "Zion National Park",
legend.position = c("left", "center"))
```
E5. Bonus: add two manual legend: one for the `zion` and one for `zion_points`.
```{r}
#| include = FALSE
tm_shape(srtm) +
tm_raster(style = "cont", palette = "-Spectral", title = "Elevation (m als)") +
tm_shape(zion) +
tm_polygons(alpha = 0.3) +
tm_shape(zion_points) +
tm_symbols(shape = 6, col = "black") +
tm_add_legend(type = "symbol", shape = 6, col = "black", labels = "My points") +
tm_add_legend(type = "fill", alpha = 0.3, labels = "Park's area") +
tm_scale_bar(position = c("left", "bottom"), breaks = c(0, 2, 4)) +
tm_compass(position = c("right", "top")) +
tm_credits("My Name", position = c("left", "bottom")) +
tm_layout(frame = FALSE, main.title = "Zion National Park",
legend.position = c("left", "center"))
```
E6. Try saving your map to different file formats: `.png`, `.pdf`, and `.html`.
Can you notice any difference between the files?
```{r}
#| include = FALSE
my_map <- tm_shape(srtm) +
tm_raster(style = "cont", palette = "-Spectral", title = "Elevation (m als)") +
tm_shape(zion) +
tm_polygons(alpha = 0.3) +
tm_shape(zion_points) +
tm_symbols(shape = 6, col = "black") +
tm_add_legend(type = "symbol", shape = 6, col = "black", labels = "My points") +
tm_add_legend(type = "fill", alpha = 0.3, labels = "Park's area") +
tm_scale_bar(position = c("left", "bottom"), breaks = c(0, 2, 4)) +
tm_compass(position = c("right", "top")) +
tm_credits("My Name", position = c("left", "bottom")) +
tm_layout(frame = FALSE, main.title = "Zion National Park",
legend.position = c("left", "center"))
tmap_save(my_map, "my_map2.png")
tmap_save(my_map, "my_map2.pdf")
tmap_save(my_map, "my_map2.html")
```