-
Notifications
You must be signed in to change notification settings - Fork 5
/
03-nutshell.Rmd
231 lines (179 loc) · 12.1 KB
/
03-nutshell.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
# **tmap** in a nutshell {#nutshell}
The **tmap** package allows the creation of thematic maps with great flexibility.
It accepts spatial data in various formats shape objects (section \@ref(shape-objects))
Next, the data can be used to create simple, quick maps (section \@ref(quick-maps)) and more complex and expandable maps (section \@ref(regular-maps)).
These maps can be presented in two modes - as a static map and an interactive one.
Additionally, **tmap** makes it possible to create small multiples map (section \@ref(sm-section)) and map animations (section \@ref(ani-section)).
## Shape objects
As we established in chapter \@ref(geodata), spatial data comes in various file formats related to two main data models - vector and raster.
There are also several spatial object classes in R, for example, `sf` from the **sf** package for vector data and `stars` from **stars** for raster data and spatial data cubes.
Additionally, packages such as **sp**, **raster**, or **terra** offer their own classes, and this abundance of spatial object classes can be generally overwhelming.
Gladly, **tmap** can work with all of the above objects - it treats all supported spatial data classes as so-called *shape objects*.
For example, we read the `ei_points.gpkg` file contains several points on Easter Island into a new object, `ei_points`, and select only points with the `type` of `"volcano"`.
The `volcanoes` object is a *shape object*.
```{r, message=FALSE}
library(tmap)
library(sf)
ei_points = read_sf("data/easter_island/ei_points.gpkg")
volcanoes = subset(ei_points, type == "volcano")
```
<!-- ref also to data appendix -->
Spatial data, no matter the class, usually stores two interrelated sets of information - about the locations/geometries and their associated values/attributes.
Visualization of the attributes only can be done with regular plotting functions (e.g., `plot()`, `hist()`, `barplot()`) or dedicated packages, such as **ggplot2** <!--cite-->.
On the other hand, **tmap** is suitable when our goal is to visualize spatial geometries only or spatial geometries together with their attributes.
## Quick maps
The **tmap** package offers a distinction between quick and regular maps.
The first approach, using the `qtm()` function, could be handy for data exploration.
It works even if we just provide any *shape object* - in that case, only the geometry is plotted.
Figure \@ref(fig:qtm):A shows a visualization of the geometries from the `volcanoes`.
```{r, eval=FALSE}
qtm(volcanoes)
```
The `qtm()` function allows to customize many map elements for the provided *shape object*.
For example, we can change the shapes of the points in `volcanoes`, make their sizes related to the the `"elevation"` argument, and add a title (Figure \@ref(fig:qtm):B).
```{r, eval=FALSE}
qtm(volcanoes, symbols.shape = 24, symbols.size = "elevation", title = "Volcanoes")
```
(ref:qtm) Two maps created with `qtm()`: (A) by providing only a shape object, (B) by providing a shape object and some other arguments.
```{r qtm, fig.cap="(ref:qtm)", echo=FALSE}
tmq1 = qtm(volcanoes) + tm_layout(title = "A")
tmq2 = qtm(volcanoes, symbols.shape = 24, symbols.size = "elevation", title = "Volcanoes") +
tm_layout(title = "B Volcanoes")
tmap_arrange(tmq1, tmq2)
```
The `qtm()` function offers similar flexibility to the regular map approach.
However, it only supports one shape object.
## Regular maps
Therefore, for most applications, we recommend using the regular map approach.
This approach operates on many functions that start with `tm_`.
The first element always is `tm_shape()`, which specified the input shape object.
Next, map layers, additional map elements, and overall layout can be customized.
<!-- update terminology later -->
<!-- references -->
The last example in \@ref(quick-maps) can be reproduced with the regular map approach using the following code:
```{r, eval=FALSE}
tm_shape(volcanoes) +
tm_symbols(shape = 24, size = "elevation") +
tm_layout(title = "volcanoes")
```
Here, we specify the input data (our shape object) with `tm_shape()`, aesthetics (also known as *visual variables*) of map layers with `tm_symbols()`, and the map title with `tm_layout()`.
The **tmap** package has a number of possible map layers, but the most prominent ones are `tm_polygons()`, `tm_symbols()`, `tm_lines()`, `tm_raster()`, and `tm_text()` (chapter \@ref(layers)).
Overall, most visual variables of map layers can be assigned in two main ways.
First, they accept a fixed, constant value, for instance, `shape = 24`, which sets the symbols' shapes to triangles.
Second, it is also possible to provide a variable name, for example `size = "elevation"`.
This plots each point with a size based on the `elevation` attribute from the `volcanoes` object and automatically adds a related map legend.
The `tm_shape()` function and one or more following map layers create a *group* together.
In other words, map layers are related only to the preceding `tm_shape()` call.
One map can have several *groups*.
Let's see how many *groups* work by reading some additional datasets - the `ei_elev` raster with elevation data for Easter Island, the `ei_borders` polygon with the island outline, and the `ei_roads` lines contains a road network for this island.
<!-- ref data appendix -->
```{r, message=FALSE}
library(sf)
library(stars)
ei_elev = read_stars("data/easter_island/ei_elev.tif")
ei_borders = read_sf("data/easter_island/ei_border.gpkg")
ei_roads = read_sf("data/easter_island/ei_roads.gpkg")
```
Look at the following example and try to guess how many *groups* it has, and how many layers exist for each *group* (Figure \@ref(fig:rmap1)).
(ref:rmap1) Example of a map with four groups of map layers: an elevation layer, island borders layer, roads layer, and volcanoes layer.
```{r rmap1, warning=FALSE, fig.height=9, fig.asp=0.73, fig.cap="(ref:rmap1)"}
tm_shape(ei_elev) +
tm_raster(style = "cont", palette = "-RdYlGn",
title = "Elevation (m asl)") +
tm_shape(ei_borders) +
tm_borders() +
tm_shape(ei_roads) +
tm_lines(lwd = "strokelwd", legend.lwd.show = FALSE) +
tm_shape(volcanoes) +
tm_symbols(shape = 24, size = "elevation",
title.size = "Volcanoes (m asl)") +
tm_layout(main.title = "Easter Island",
bg.color = "lightblue")
```
The correct answer is four groups, all with just one layer.
Each *group* is put on the top of the previous one - the **tmap** uses a layered approach.
The first *group* represents elevation data with a continuous color scale style, a color palette called `"RdYlGn"`, and a legend title.
The second *group* shows the borders of Easter Island with the default aesthetics, while the third *group* presents the road network (the `ei_roads` object), with each line's width based on the values from the `"strokelwd"` column, but with a legend hidden.
The last *group* is similar to our previous example with fixed symbol shapes and sizes related to the `"elevation"` attribute, but also with the legend title instead of the map title.
Additionally, we use the `tm_layout()` function to add a map title.
<!-- ref to other parts of the book -->
Often, maps also have additional map elements, such as graticule lines, north arrow, scale bar, or map credits (Figure \@ref(fig:rmap2)).
They help map readers to understand data location or its size, and provide some ancillary information.
The **tmap** package offers a set of functions for additional map elements.
The `tm_graticules()` function draws latitude and longitude graticules and adds their labels.
It also uses the layered approach, and thus, the lines will be drawn either below or above the shape objects, depending on the position of this function in the code.
In our example below, `tm_graticules()` is used after all of the map groups, and that is why the graticule lines are put on the top of the spatial data.
We can also use `tm_compass()` to create a north arrow, `tm_scale_bar()` to add a scale bar, and `tm_credits()` to add a text annotation representing credits or acknowledgments.
The location of all these three elements on the map is, by default, automatically determined.
It, however, can be adjusted with the `position` argument - see an example of its use in the `tm_compass()` function below.
Moreover, it is possible to add any type of manual legend with `tm_add_legend()`.
It includes simple legends, such as the `"Roads"` legend below that is only represented by a single black line, but more complex legends with several elements are also possible.
<!-- ref to other parts of the book -->
```{r, warning=FALSE}
my_map = tm_shape(ei_elev) +
tm_raster(style = "cont", palette = "-RdYlGn",
title = "Elevation (m asl)") +
tm_shape(ei_borders) +
tm_borders() +
tm_shape(ei_roads) +
tm_lines(lwd = "strokelwd", legend.lwd.show = FALSE) +
tm_shape(volcanoes) +
tm_symbols(shape = 24, size = "elevation",
title.size = "Volcanoes (m asl)") +
tm_graticules() +
tm_compass(position = c("right", "top")) +
tm_scale_bar() +
tm_credits("Author, 2021") +
tm_add_legend(type = "line", col = "black", title = "Roads") +
tm_layout(main.title = "Easter Island",
bg.color = "lightblue")
```
Maps created with **tmap** can be saved as an R object.
This is a useful feature, which allows to use one map in a few places in a code, modify existing **tmap** objects, or save these objects to files.
(ref:rmap2) Example of a map with four groups of map layers and additional map elements, such as graticule lines, north arrow, scale bar, and text annotation. It also has a manually added legend.
```{r rmap2, fig.height=9, fig.asp=0.73, fig.cap="(ref:rmap2)"}
my_map
```
<!-- refs -->
## Map modes
Each map created with **tmap** can be viewed in one of two modes: `"plot"` and `"view"`.
The `"plot"` mode is used by default and creates static maps similar to those shown before in this chapter.
<!-- You can think of static maps as of images. -->
This mode supports almost all of **tmap**'s features, and it is recommended, for example, for scientific publications or printing.
The second mode, `"view"`, allows creating interactive maps.
They can be zoomed in and out or panned, allow for changing background tiles, or click on map objects to get some additional information.
This mode has, however, some constraints and limitations comparing to `"plot"`, for example
the legend cannot be fully customized, and some additional map elements are not supported.
The **tmap** package allows using both modes on the same code.
Therefore, there is no need to create two separate maps for static and interactive use.
The `tmap_mode()` function can be used to switch from one mode to the other^[Map modes can be also changed globally using `tmap_options()` or switched using `ttm()`.].
```{r}
tmap_mode("view")
```
The above line of code just changes the mode - it does not return anything except the message.
Now, if we want to use this mode, we need to either write a new **tmap** code provide some existing **tmap** object, such as `my_map`.
```{r, eval=FALSE}
my_map
```
As a result, we get several messages and an interactive map.
These messages inform us that some map elements specified in the previous code are not possible in the `"view"` mode.
It includes the text annotation ("Credits"), the north arrow ("Compass"), and some legend options.
```{r imap1, echo=FALSE, fig.cap='Map from the previous figure shown using the interactive ("view") mode.', cache=FALSE, message=FALSE}
view_map(my_map, "imap1")
```
Our main result is the interactive map (Figure \@ref(fig:imap1)).
<!-- improve -->
It shows our spatial data using similar aesthetics to Figure \@ref(fig:rmap2), but allows us to zoom in and out or move the map.
We also can select a background tile or click on any line and point to get some information.
To go back to the `"plot"` mode, we need to use the `tmap_mode()` function again - map not shown:
```{r, fig.show='hide'}
tmap_mode("plot")
my_map
```
More information about the interactive `"view"` mode and how to customize its outputs is in chapter \@ref(interactive).
## Small multiples {#sm-section}
<!-- to write after the \@ref(multiples) chapter is done -->
Chapter \@ref(multiples)
## Animations {#ani-section}
<!-- to write after the \@ref(animations) chapter is done -->
Chapter \@ref(animations)