How to create animations in R with gganimate

A plot is a good way of presenting our data. However, many times a plot is not powerful enough or simply it is not a good way of showing the evolution of a process. Luckily, with animations we can have a huge impact on our audience, but do you know how to create animations? In this post, I will explain to you how you can create animations in R with gganimate, so that you can take your plots to the next level. Does it sound good? So let’s do it!

How to create animations in R with gganimate

Preparing the data to create an animation with gganimate

As when we make a graph with ggplot2, the first thing we need to create animations in R with gganimate is that our data has to have a tidy shape. This means that:

  1. Each column has to be a variable.
  2. All the rows should refer to only one observation.
  3. Each cell should contain just one value.

In our case we will use the gapminder dataset, as it is a classic dataset in the animation field.

library(gapminder)
datos = gapminder
head(datos)
## # A tibble: 6 x 6
##   country     continent  year lifeExp      pop gdpPercap
##   <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
## 1 Afghanistan Asia       1952    28.8  8425333      779.
## 2 Afghanistan Asia       1957    30.3  9240934      821.
## 3 Afghanistan Asia       1962    32.0 10267083      853.
## 4 Afghanistan Asia       1967    34.0 11537966      836.
## 5 Afghanistan Asia       1972    36.1 13079460      740.
## 6 Afghanistan Asia       1977    38.4 14880372      786.

If your dataset is not a tidy dataset, most probably the dplyr and tidyr packages will help you achieve that. Just in case you didn’t know them, here I left you their cheatsheet.

Once we have the dataset in a tidy format, we are ready to create animation in R with gganimate.

Creating animations in R

In order to create our animation, we will begin by creating a normal ggplot graph. If a lot of data overlays on a single state (in our case the year) the graph won’t be very visual. So, we will do it just for one country so that it is much more visual. In the end, the goal of creating the graph is that we display the data in a way that we like and make it attractive and then create the animation on that.

library(ggplot2)
library(dplyr)

grafico <- datos %>%
  ggplot() + 
    geom_point(aes(x = gdpPercap, y = lifeExp, col = continent, size = pop), alpha = 0.8) + theme_minimal() + 
    theme(legend.position = "bottom") + guides(size = "none") + 
    labs(x = "PIB per Capita" ,y = "Esperanza de Vida",  col = "") 

grafico
The base graph with which we will create our animation in R with gganimate

Now we can create the animation simply by passing the transaction function. Just with this function gganimate will create the animation. Yes, just with a function we can create an animation. Let’s see it:

library(gganimate)

grafico +
  transition_time(year)
Animation 1. Basic animation with gganimate
Animation 1. Basic animation with gganimate

We have just created our animation! Despite it looks fine, it is not so impactful, is it? It is quite small, the axes are fixed, we don’t know which year is it… And that’s because while you can create an animation with only one function, there are a lot of settings to adjust to make your animation look awesome.

Don’t worry, now that you already know how to create basic animations in R with gganimate, we will now learn how to make that animation look awesome.

Adjusting our animations in R

1. Indicating the number of frame on the transition

One of the key aspects of a good animation is that the user knows why the graph is moving, that is, that the user knows what each moment on the animation means.

To do so, the gganimate functions includes a really interesting functionality: to include those variables on ggplot labs function. As you can see in the table below, each transaction function has each own variable that we should include in the labs. In the case of transitimo_time the variable is frame_time.

Name of the functionLabs variable
transition_components frame_time
transition_events frame_time
transition_filter previous_filter, closest_filter, next_filter
transition_layer previous_layer, closest_layer, next_layer, nlayers
transition_manual previous_frame, current_frame, next_frame
transition_reveal frame_along
transition_states previous_state, closest_state, next_state
transition_time frame_time
grafico +
  transition_time(year) +
  labs(title = "Año: {frame_time}")
Animation 2. Including the state on the animation
Animation 2. Including the state on the animation

As you can see the date is included in the title but… it is small, it is out of the graph and disables to use the title for telling other things… That is why I don’t like this option.

In my opinion, it is much more visual and impactful to include the data on the same graph with an extra ggplot layer. In this way, we can use the title for whatever we want, we can give the transition state the look and feel that we want and it’s within the graph. Let’s see an example:

grafico +
  geom_text(aes(x = min(gdpPercap), y = min(lifeExp), label = as.factor(year)) , hjust=-2, vjust = -0.2, alpha = 0.2,  col = "gray", size = 20) +
  transition_states(as.factor(year), state_length = 0)
Animation 3. Include the state inside the graph in animations in R with gganimate
Animation 3. Include the state inside the graph in animations in R with gganimate

As you can see, in this case, I have used the function transition_states instead of transition_time and I have also change the year variables to a factor. The reason is that the transition functions interpolate numeric data, which makes it look terribly bad. When we convert the number into a factor the problem disappears.

Besides, I have also included the parameter state_length to be zero. This parameter allows us to control for how long will pause before changing to the new state. In my case, I will set as zero, because with higher values the transition wouldn’t be smooth.

Esta variable permite controlar el tiempo que la animación debe ‘detenerse’ cuando llegas a un nuevo estado. En mi caso, lo pongo a cero porque sino nuestra animación iría a tirones y quedaría feo, pero en otros casos donde se quieren marcar las diferencias, puedes incrementarlo.

That being said, let’s see how to keep improving our animations!

Show the growth by freeing the scales of the animation

If you have notices, the scales of the animation do not change during the animation. This generates two things:

  • The growth is not that well represented. By having the final value visible from the beginning, we do not have as much growth prospects.
  • If the scale is very wide and the initial values are low (for example in aggregate data), we lose perspective of what happens at the beginning, when the values are low.

If we want to avoid this and we want to better see how the variables grow, it is better to adjust the scale in each frame. For this, we will use the view_follow function.

A very clear impact of this issue is the impact on the evolution graphs. Let’s see an example of the evolution of the Spanish GDP.

datos %>%
  filter(country == "Spain") %>%
  ggplot(aes(year, pop)) + geom_point() + geom_line() +
  theme_minimal() +
  transition_reveal(year)
Animation 4. Evolution of the GDP without changing the scale
Animation 4. Evolution of the GDP without changing the scale

As you can see, as we do not change the scales, the plot does not look that alive and it’s not so impactful. However, if we make the axis scales change automatically the speed of the change will make us better see how the GPD per Capita has evolved.

datos %>%
  filter(country == "Spain") %>%
  ggplot(aes(year, pop)) + geom_point() + geom_line() + 
  geom_text(aes(x = min(year), y = min(pop), label = as.factor(year)) , hjust=-2, vjust = -0.2, alpha = 0.5,  col = "gray", size = 20) +
  theme_minimal() +
  transition_reveal(year) + 
  view_follow()
Animation 5. Evolution of the GDP changing the axis
Animation 5. Evolution of the GDP changing the axis

As you can see, these two tricks have suppose a significant improvement in our animation. But there is still a very important thing to learn: the animation renderization.

Rendering: the key to create incredible animations in R

Frames and duration: the key for a good visualization

To render is to convert our R commands into an animation. Is at this step when we can personalize a lot of the key elements of our animations, such as:

  • The width and height of the animation to create an animation that it is correctly seen on the device that we want to see it.
  • Duration, number of frames, and number of frames per second (fps): this will make you the animation see fluently.
  • Output file format: if you don’t want to create a gif, you can also create a video too.

To render our animation first we need to save the result of the animation as an object. By doing so, we can now pass this object to the animate function. This function has many other parameters with which we can adjust the things we have commented on previously.

  • fps: the human being is able to distinguish between 10 and 12 frames per second. If we add more frames, the brain does not see many images together, but rather it sees an animation (link).Thus, the fps parameter should always be higher than 12. I would recommend setting it at 25fps, as it balances between fluentness and lightness.
  • duration: it sets for how long should the animation long. This will depend on the number of states that we have. In my opinion, for transitions with a lot of states, I would set the state to last for 0.5 seconds. Anyway, there is not a global option and I would recommend trying several durations.

Example: bar chart race

Now we will apply everything that we have learned on how to create animations in R with gganimate to create an awesome animation: a bar chart race.

To create our bar chart race we will analyze the evolution of the countries with the highest GDP per capita on the gapminder dataset. To do so, first, we need to get the rank the countries on each year. This is something that we can easily do with dplyr:

datos2 <- datos %>%
  group_by(year) %>%
  arrange(year, desc(gdpPercap)) %>%
  mutate(ranking = row_number()) %>%
  filter(ranking <=15)

head(datos2)
## # A tibble: 6 x 7
## # Groups:   year [1]
##   country       continent  year lifeExp       pop gdpPercap ranking
##   <fct>         <fct>     <int>   <dbl>     <int>     <dbl>   <int>
## 1 Kuwait        Asia       1952    55.6    160000   108382.       1
## 2 Switzerland   Europe     1952    69.6   4815000    14734.       2
## 3 United States Americas   1952    68.4 157553000    13990.       3
## 4 Canada        Americas   1952    68.8  14785584    11367.       4
## 5 New Zealand   Oceania    1952    69.4   1994794    10557.       5
## 6 Norway        Europe     1952    72.7   3327728    10095.       6

After that, we can easily create the bar chart race animation with gganimate. In this case, we will include the functions enter_fade and exit_fade, which will create a fade off effect when the countries appear or disappear. Besides, we will use the function ease_aes to create a non-linear animation that looks better:

animacion <- datos2 %>%
  ggplot() +
  geom_col(aes(ranking, gdpPercap, fill = country)) +
  geom_text(aes(ranking, gdpPercap, label = gdpPercap), hjust=-0.1) +
  geom_text(aes(ranking, y=0 , label = country), hjust=1.1) + 
  geom_text(aes(x=15, y=max(gdpPercap) , label = as.factor(year)), vjust = 0.2, alpha = 0.5,  col = "gray", size = 20) +
  coord_flip(clip = "off", expand = FALSE) + scale_x_reverse() +
  theme_minimal() + theme(
    panel.grid = element_blank(), 
    legend.position = "none",
    axis.ticks.y = element_blank(),
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    plot.margin = margin(1, 4, 1, 3, "cm")
  ) +
  transition_states(year, state_length = 0, transition_length = 2) +
  enter_fade() +
  exit_fade() + 
  ease_aes('quadratic-in-out') 

animate(animacion, width = 700, height = 432, fps = 25, duration = 15, rewind = FALSE)
Bar chart race animation created in R with gganimate
Bar chart race animation created in R with gganimate

Conclusion on how to create animations in R: taking the graphs to the next level

Knowing how to create animation in R is something very easy, but very practical too. If you want to create graphs that have a higher impact and you have the chance of showing that graph as an animation, I would recommend you to do so. But animations are more useful than that.

In my case, for example, I have used the animations to explain in a super simple and visual way how the K-means algorithm works (link). This could also be used on how neural networks work or how a neural network performance improves with more learning. We could even use animations on sports analytics!

In summary, whatever your work is, I hope that you have found interesting learning how to create animations in R with gganimate.

As always, if you would like me to write about a specific topic, do not hesitate to reach out on Linkedin. See you at the next one!