Load libraries


library(tidyverse)
library(gganimate)
library(gifski)

Introduction


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.

Basics of 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.

Example #1 - transition_reveal() using US tuition data

The 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.

Animate the 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.

Lab Exercise


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.

Animate time series data using gapminder data set from World Bank


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)

Explanation of the code


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.

Save animation as a gif file


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")

Lab Exercise


Try to reproduce the following graph:

Lab Homework (Optional)


Try to reproduce the following graph:

Other controlling functions


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.

Lab Exercise


Try to reproduce the following graph with the diamonds data set:

Lab Homework (Required)


  1. Finish all lab exercises in this module.

Submit your answer in a single pdf or html knitted from a R markdown file. Submit your R markdown file as well.