-
-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathanimations.qmd
More file actions
156 lines (127 loc) · 6.6 KB
/
animations.qmd
File metadata and controls
156 lines (127 loc) · 6.6 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
```{r animations-1}
#| echo: false
source("code/before_script.R")
```
# Animations {#sec-animations}
\index{animation}
Animations are a powerful way to visualize changes in data over time -- to illustrate trends, patterns, and dynamics that might not be immediately apparent in static maps.
They can also be used to create engaging visualizations that capture the viewer's attention or just to break the monotony of static maps, for example, by comparing different locations.
In **tmap**, animations are created by stitching together a series of static maps into a single animated image.
This is done with two types of functions:
- `tm_animate()` and `tm_animate_fast()`, which create the animation from a **tmap** object
- `tmap_animation()`, which saves the animation to files in formats such as GIF and MP4
## Creating animations
Let's create some animations using the `slo_regions_ts` dataset, which contains various measures of Slovenian regions over time.
```{r animations-2}
#| message: false
library(sf)
library(tmap)
slo_regions_ts = read_sf("data/slovenia/slo_regions_ts.gpkg")
```
The basis for our animations is a **tmap** object that contains the data and the way we want to visualize it.
```{r animations-3}
tm = tm_shape(slo_regions_ts) +
tm_polygons("gdppercap")
```
<!-- idea: animating charts along the data: -->
<!-- tm_polygons("gdppercap", fill.chart = tm_chart_donut()) -->
\index{tm\_animate}
\index{tm\_animate\_fast}
To make it animated, we can use the `tm_animate()` or `tm_animate_fast()` functions and specify the variable that we want to animate by, in this case, `time` (@fig-anims).
The difference between the two functions is that `tm_animate()` renders the animation at 2 frames per second (specified by the `fps` argument), while `tm_animate_fast()` renders it at 24 frames per second.
The former is more suitable for smaller datasets and cases where we want to allow the viewer to read the values on the map, while the latter is more suitable for larger datasets and cases where we want to create a smooth, cinematic animation.
```{r}
#| eval: false
tm +
tm_animate(frame = "time")
```
```{r}
#| echo: false
#| message: false
#| label: fig-anims
#| fig-cap: "Animations of GDP per capita in Slovenian regions over time using `tm_animate()`."
anims = tm +
tm_animate(frame = "time")
view_animation(anims, "anims")
```
Two main additional arguments for the *animate* functions are `fps` (frames per second) and `play` (playback mode).
The first one controls the speed of the animation, while the second one controls how the animation is played back:
either `"loop"` (default), which plays the animation in a loop, `"once"`, which plays the animation only once and then stops, or `"pingpong"`, which plays the animation back and forth (@fig-anims2).
```{r}
#| eval: false
tm +
tm_animate_fast(frame = "time", fps = 5, play = "pingpong")
```
```{r}
#| echo: false
#| message: false
#| label: fig-anims2
#| fig-cap: "Animations of GDP per capita in Slovenian regions over time with a pingpong playback mode."
anims2 = tm +
tm_animate(frame = "time", fps = 5, play = "pingpong")
view_animation(anims2, "anims2")
```
Animations can also be created from raster data, such as satellite imagery or climate data.
@fig-anims3 shows an example of an animation of the average temperature in Slovenia over monthly time steps.
First, the raster data is defined, and its scale is set to the continuous one.
Next, we define the animation using `tm_animate()`<!--and specify the `by` argument to animate by the `band` variable, which represents the time steps in the raster data-->.
Finally, we add the borders of Slovenian regions to the map to provide context for the animation.
```{r}
#| eval: false
library(terra)
slo_tavg = rast("data/slovenia/slo_tavg.tif")
slo_regions = read_sf("data/slovenia/slo_regions.gpkg")
tm_shape(slo_tavg) +
tm_raster(col.scale = tm_scale_continuous(),
col.free = FALSE) +
tm_animate(fps = 6) +
tm_shape(slo_regions) +
tm_borders()
```
```{r}
#| echo: false
#| message: false
#| label: fig-anims3
#| fig-cap: "Animation of average temperature in Slovenia over time."
library(terra)
slo_tavg = rast("data/slovenia/slo_tavg.tif")
slo_regions = read_sf("data/slovenia/slo_regions.gpkg")
anims3 = tm_shape(slo_tavg) +
tm_raster(col.scale = tm_scale_continuous(),
col.free = FALSE) +
tm_animate(fps = 6) +
tm_shape(slo_regions) +
tm_borders()
view_animation(anims3, "anims3")
```
## Combining animations with facets
<!-- https://github.com/r-tmap/tmap/issues/1160 -->
If you read the previous chapters, you may see the similarity between the `tm_animate()` and `tm_facets()` functions, which create a series of static maps based on the values of a variable.
The main difference is that `tm_animate()` creates an animation -- one frame after another, while `tm_facets()` creates a grid of static maps, where each map corresponds to a value of the variable.
However, we can also combine the two functions to create animations of facets.
@fig-anims4 shows an example of an animation of GDP per capita in Slovenian regions over time, faceted by region group.
To create it, we first facet the **tmap** object by the `region_group` variable using `tm_facets()`, and then we animate it by the `time` variable using `tm_animate()`.
```{r}
#| label: fig-anims4
#| fig-cap: "Animation of GDP per capita in Slovenian regions over time, faceted by region group."
tm +
tm_facets(by = "region_group", nrow = 2) +
tm_animate(frame = "time")
```
It is important to note that each layer group can have at most one `tm_facets()` and at most one `tm_animate()`.
## Saving animations
\index{tmap\_animation}
The `tm_animate()` and `tm_animate_fast()` functions create a **tmap** object that contains the animation and shows it.
Now, to save the animation, we can use the `tmap_animation()` function.
It takes the animation object as the first argument and the file name as the second argument -- the extension of the file name determines the format of the saved animation.
We may save the animation in either graphical format (GIF) or video format (including MP4).
```{r animations-10}
#| eval: false
tma1 = tm +
tm_animate_fast(frame = "time")
tmap_animation(tma1, "tma1.gif")
# or
# tmap_animation(tma1, "tma1.mp4")
```
Additionally, we can customize the output of the animation with various arguments, such as `width`, `height`, `dpi`, `asp`, and `scale` (similarly to `tmap_save()` as shown in @sec-save).
Moreover, if the animation is saved in a video format, we can also specify various additional arguments, such as `codec` from the **av** package^[Check the documentation of the `av::av_encode_video()` function for more details.].