Making animated GIFs in R: ten years of emerald ash borer spread in Minnesota

June 29, 2019
Data viz GIF animation R magick

The popularity of GIFs have exploded in recent years and they give photojournalists a great way to tell a story. Sometimes the right GIF image can bring data to life.

The general process to make a GIF image with maps in R is:
1. Create the images you want (e.g., using ggplot),
2. Stitch the images together with magick, and
3. Write the images as a GIF and share!

Making GIFs with maps can be accomplished in R primarily using the ggplot2 and magick packages. Here is a short description of how various packages can be used to create a GIF image:

library(ggplot2) #Provides the visualization tools
library(gsheet) #Links to the data in a Google Sheet
library(GGally) #Extension of ggplot mapping attributes
library(rgdal) #Provides geospatial attributes
library(usmap) #Provides a basemap of the US
library(magick) #Processes images

The emerald ash borer (EAB) is a non-native insect that kills ash trees. It was first observed in Minnesota in 2009 in the city of St. Paul and in Houston County. EAB has spread over the last 10 years and as of 2019 is found in 18 counties in Minnesota.

The dataset eab contains each Minnesota county from 2009 through 2019, whether or not EAB is found in the county, and if so, which year the infestation began (yearinfest). The dataset is read into R using the gsheet2tbl() function from the gsheet package. A 0,1 indicator variable separates the infested counties from the non-infested ones:

eab<-gsheet2tbl('https://docs.google.com/spreadsheets/d/1S5ypnWcL0uOG50YrhxyAGHsQk356qyyDzTTCBkiXL80/edit?usp=sharing')
eab$state<-fips("MN")
eab$infest<-ifelse(eab$yearinfest>0,"YES","NO") 

The workflow will begin by first creating separate images using ggplot of infected counties in each year. Each year of data will be subset into its own data frame, for example for 2009:

eab2009<-subset(eab,year==2009)

Next we can make a map of Minnesota for each year, indicating which counties were infested with EAB in that year. The plot_usmap function will use ggplot2 to create the map, and we can replicate these maps for the other ten years:

p.eab2009<-plot_usmap("counties", data = eab2009, 
                      values = "infest", include = "MN") +
                      ggplot2::scale_fill_discrete()+
                      theme(legend.position="none",
                            plot.title=element_text(size=18))+
                      ggtitle("2009")
p.eab2009

It may be worthwhile to save the yearly plots you create to your local directory. For this you can use ggsave(). Then you can read the image again using the image_read() function from the magick package. Any images can be read from a file path or URL:

ggsave(filename = "eab2009.png", plot=p.eab2009,width=4,height=4,units="in",scale=1)
d.eab2009 <- image_read("eab2009.png")

Then, you can stitch the images together using the image_append function, and see what they look like:

img <- c(d.eab2009,d.eab2010,d.eab2011,d.eab2012,d.eab2013,d.eab2014,d.eab2015,d.eab2016,d.eab2017,d.eab2018,d.eab2019)

image_append(image_scale(img, "x200"))

The purpose of the image_animate() function is to animate the GIF. The frames per second (fps) can be changed to speed up/slow down the animation depending on what works best. The final step is to write the animation as a GIF using image_write():

my.animation<-image_animate(image_scale(img, "400x400"), fps = 1, dispose = "previous")
image_write(my.animation, "eab-spread.gif")

In the end you’ll get a GIF showing the spread of EAB in Minnesota during the last ten years:

Thanks to the excellent vignette with magick for tips and tricks!

By Matt Russell. Leave a comment below or email Matt with any questions or comments.

Tree measurements on the Rockefeller Center Christmas Tree

December 17, 2023
Rockefeller tree Data viz Christmas tree tree height

A list of R packages for forestry applications

November 24, 2023
analytics R R packages statistics data science forestry

Recent updates to tidyverse functions

September 14, 2023
analytics data science R tidyverse