library(tidyverse)
library(gganimate)
library(gifski)
In this module, we will learn how to create animated visualizations
with gganimate
package.
gganimate
extends the grammar of graphics as implemented
by ggplot2
to include the description of animation.
The help documentation of gganimate
can be found at https://gganimate.com/index.html.
gganimate
The gganimate
package provides a range of new grammar
classes that can be added to the plot object in order to customise how
it should change with time:
transition_*()
defines how the data should be spread
out and how it relates to itself across time.view_*()
defines how the positional scales should
change along the animation.shadow_*()
defines how data from other points in time
should be presented in the given point in time.enter_*()
/exit_*()
defines how new data
should appear and how old data should disappear during the course of the
animation.ease_aes()
defines how different aesthetics should be
eased during transitions.A full list of functions from gganimate
can be found at
https://gganimate.com/reference/index.html.
transition_reveal()
using US tuition
dataThe transition_reveal()
function reveals data along a
given dimension. Let’s use US college tuition data set as an
example.
read_csv("us_avg_tuition.csv") -> tuition_data
tuition_data <- tuition_data %>%
pivot_longer(cols = 2:13, names_to = "year", values_to = "tuition") %>%
mutate(tuition = parse_number(tuition)) %>%
tidyr::extract(year, into = "year", "^(....)") %>%
mutate(year = as.numeric(year))
ny_data <- filter(tuition_data, State == "New York")
ggplot(ny_data, aes(x = year, y = tuition, color = State, group = State)) +
geom_line() +
geom_point() +
annotate("text", label = "New York", x = 2004.5, y = ny_data[[1,3]] + 60) +
labs(x = "Year", y = "Average tuition (in USD)", title = "College Tuition in New York State") +
xlim(2003.5, 2015.5) + theme(plot.title = element_text(hjust = 0.5)) +
scale_x_continuous(breaks = seq(2004, 2015, by = 1))
The code above tidies the data, keeps only data for New York State and then do a line plot.
The gganimate
package offers functions that can
seamlessly embed into ggplot2
codes. In this example, if we
add transition_reveal(year)
into the plotting code, it
becomes an animated graph.
ggplot(ny_data, aes(x = year, y = tuition, color = State, group = State)) +
geom_line() +
geom_point() +
annotate("text", label = "New York", x = 2004.5, y = ny_data[[1,3]] + 60) +
labs(x = "Year", y = "Average tuition (in USD)", title = "College Tuition in New York State") +
xlim(2003.5, 2015.5) + theme(plot.title = element_text(hjust = 0.5)) +
scale_x_continuous(breaks = seq(2004, 2015, by = 1)) +
transition_reveal(year)
Here transition_reveal()
requires year
must
be a numeric variable.
Add the data of New Jersey (including a new annotation) to the same plot so that the graph shows evolution of college tuition in New York and New Jersey in the same plot.
Animated graph is particularly useful for time series data (or longitudinal data). Let’s use the World Bank data as an example.
gapminder <- read_csv("gapminder_DAS522.csv")
The following code creates an animated graph showing the change of all world countries in life expectancy against fertility rate.
ggplot(gapminder, aes(Fertility, LifeExp, size = Pop, colour = region)) +
geom_point(alpha = 0.7, show.legend = T) +
scale_size_continuous(range = c(0.5, 15), guide = "none") +
# Here comes the gganimate specific bits
labs(title = 'Year: {frame_time}', x = 'Fertility Rate', y = 'life expectancy') +
xlim(0, 10) + ylim(0, 100) + theme(plot.title = element_text(hjust = 0.5)) +
transition_time(date) +
ease_aes('linear') -> p
animate(p, duration = 15, fps = 4)
ggplot(gapminder, aes(Fertility, LifeExp, size = Pop, colour = region)) +
geom_point(alpha = 0.7, show.legend = T) +
scale_size_continuous(range = c(0.5, 15), guide = "none") +
# Here comes the gganimate specific bits
labs(title = 'Year: {frame_time}', x = 'Fertility Rate', y = 'life expectancy') +
xlim(0, 10) + ylim(0, 100) + theme(plot.title = element_text(hjust = 0.5)) +
transition_time(date) +
ease_aes('linear') -> p
animate(p, duration = 15, fps = 4)
In the code,
animate
function controls the output parameters.
Here we have a data span of 60 years, so make it 4 frame per second
(fps) and last 15 seconds so that each frame corresponds to a year
exactly.
In the labs
function,
title = 'Year:{frame_time}'
reads the year for each frame
and put that into the title.
transtion_time(date)
is the key line of code here to
facilitate the animation by specifying date
as the
controlling variable for time in creating frames.
ease_aes('linear')
controls the easing aesthetics
between transition which will be discussed later.
The following code saves the output graph as a gif image with controlling parameters (duration, fps, resolution etc.)
animate(p, duration = 15, fps = 4, width = 1500, height = 800, renderer = gifski_renderer(), res = 300)
anim_save("gapminder.gif")
Try to reproduce the following graph:
Try to reproduce the following graph:
We can also transit between each label for a categorical variable
using transition_states()
function. As below is an
example
ggplot(mpg) +
geom_point(aes(x = cty, y = hwy, color = class)) +
labs(title = "Manufacturer:{closest_state}", x = "MPG in city", y = "MPG in highway") +
theme(plot.title = element_text(hjust = 0.5)) +
enter_fade() + exit_shrink() +
transition_states(manufacturer) -> p4
animate(p4, fps = 5, res = 300)
Here we use enter_fade()
and exit_shrink()
functions to control the visual effect of appearing and disappearing
during the animation.
For view_*()
functions and shade_*()
functions, we will not introduce here and you can check the help
documentation by yourself.
Try to reproduce the following graph with the diamonds
data set: