Animate any plots in R using gifski

In this article, we will see how we can animate any plots in R. If you are looking to animate a simple plot (like barplot, line plot, etc.), then you can simply use libraries like gganimate or plotly. This gives many interesting features like adding shadows or creating a trail. But if you want to make a more custom animation involving any number and any kind of plots, you can use libraries like gifski to create a gif animation. One advantage of using gifski is that the color is not limited to 256.

To create the animation, it is not necessary to move a plot. But here we will simply make many individual plots and stitch them together as movie frames. Each frame is a different plot that is made using a subset of the full data.

Here, we will try to create an animation of two plots which I used in one article on modeling COVID-19 using the SIR model. First, let's look at our data. The data for creating the line plots has three columns which have the count of individuals in the three states - S, I, and R for all the days (the Day column will be used to animate).

Day State Count
1 S 19760
1 I 223
1 R 17
2 S 19715
2 I 249
... ... ...
The second dataset is for the heatmap that has four columns which have the values of the X and Y axis, infected population ratio (this will be used to color the heatmap), and day (this will be used to animate). One thing to note is that I have fixed the limit of x and y axis. This means that even if we take the subset of full data, the plot layout will be fixed.
X Y infection Day
1 1 0.7885 1
2 1 0.7837 1
3 1 0.7969 1
... ... ... ...

Now we can move the plot generation. As the next step, we will create the plots for day 1. Since we need to create plots multiple times, let's define a function for that.

# LOADING THE LIBRARIES ----------------------------------------
library(ggplot2)   # for plots
library(gridExtra) # to create a layout and combine the plots
library(stringr)   # for str_pad function to pad while writing filenames

# FUNCTION TO CREATE THE PLOTS ----------------------------------------
# Description: this function creates a line plot and a heat map for a given day
# INPUT:
# ______
# 		sir: dataset having the count of individuals in each state for each day
#		heat_: dataset for the heatmap
#		ti: day
# OUTPUT:
# _______
#		a plot having both the line plot and heatmap

GeneratePlots <- function(sir, heat_, ti) {
	
	# Filtering the data for given day
	sir2 <- sir[sir$Day <= ti, ]
	
	# creating the line plot
	lineplot <- ggplot(data=sir2, aes(x=Day, y=Count, group=State, color=State)) +
	  geom_line() +  
	  theme_minimal() +
	  scale_color_manual(breaks = c("S", "I", "R"), 
						 values=c("blue", "red", "green4"))+
	  theme(plot.title = element_text(hjust = 0.5, size = 10),
			axis.title = element_text(size = 8))+
	  labs(title = "SIR plot") +
	  xlim(1, tot_time) +ylim(0, 20000)
	
	# creating the heatmap
	heatplot <- ggplot(heat_[heat_$Day == ti, ], aes(X, Y, fill= infection)) + 
	  geom_tile(color = "gray") +
	  # defining the legend bar (setting the limit from 0 to 1 as this is a ratio)
	  scale_fill_gradient2(low="white", high="red", breaks=seq(0,1,0.25), limits=c(0, 1)) +
	  theme_minimal() +
	  # Plot title
	  labs(title="Spread of infection across communities")+
	  # Theme and layout of the plot
	  theme(axis.text.x=element_blank(),
			axis.text.y=element_blank(),
			axis.title.x=element_blank(),
			axis.title.y=element_blank(),
			panel.grid.major=element_blank(),
			plot.title = element_text(hjust = 0.5, size = 10))
	
	return(grid.arrange(lineplot, heatplot,  nrow = 1, top = paste0("Day: ", ti)))
  }

Calling the above function for day 100 gives the following output plot:

GeneratePlots(sir, heat_, 100)

Now the only thing left is to call the function GeneratePlots in a loop, save the plots as .png files and convert them into .gif animation. While saving the plot we have to make sure that the file name should be in proper order. Here, I am padding the day with 0 to ensure that.

for (i in 1:200) {
	# creating the plot
	p <- GeneratePlots(sir, heat_, i)
	# saving the plot locally using ggsave function
	ggsave(paste0("ComPlaceOnly_", str_pad(i, 3, pad = "0"), ".png"), p, width = 3, 
		   height = 1.2,  scale = 2, dpi = 150)
  }

The only step left is to read all these files and stitch them together to create an animation.

library(gifski)
# creating a vector of png file names
png_files <- list.files("png_files_location", pattern = "*.png", full.names = T)
# creating a gif using all the png files
gifski(png_files, gif_file = "animation_ComPlaceOnly.gif", width = 800, height = 350, delay = 0.2)

Following the above steps, we will have the below animation showing how the values change over time for both the line plot and heatmap.

Wrapping Up

Now you know how to create any plots in any layout into animation and show how the values change over time. In this article, I have used ggplot, but the same approach of creating .png and .gif files can be followed for any plotting libraries.

References:

  1. How to arrange different plots in a layout using gridExtra
  2. How to stitch multiple png files into one animation