My first #TidyTuesday - A world map GIF

About TidyTuesday

Tidy Tuesday is a nice initiative from the R4DS online community. The goal is is to apply your R skills, get feedback, explore other’s work, and connect with the greater RStats community.
It’s also my blogging motivation.

The challenge

This post is about the following challenge

The dataset contains mortality rates for all countries from 1990 to 2016, the aim was build a meaningful visualization. My idea was show the variation of a specific cause of death through space-time.

You can download the data from here

Ingredients

To achieve my goal I used the packages:

  • dplyr - data manipulation;
  • ggplot2 - graphs;
  • ggthemes - map theme;
  • sf - spatial data manipulation. This package interacts beautifully with ggplot2 and dplyr, which makes spatial data manipulation and visualization very easy (and tidy);
  • magick - build the GIF’s;
  • magrittr - it’s not just the %>%;
  • readxl - reading .xlsx files;
  • maps - world map ‘shape’.

Alyssa Goldberg suggestion: You can use gganimate instead of magick, it will need fewer lines of code.

Reading and manipulating the data

The following code is used to read and make the first manipulations at the data provided for the challenge. Here, mutate and case_when, are being used to modify the names of some countries to coincide with country names at the map that will be used.

library(ggplot2)
library(dplyr)
library(sf)
library(magrittr)

data <- readxl::read_excel("data/global_mortality.xlsx") %>% 
  mutate(country = case_when(
    country == 'Antigua and Barbuda' ~ 'Antigua',
    country == 'United States' | country == 'United States and Virgin Islands' ~ 'USA',
    country == 'United Kingdom' ~ 'UK',
    country == 'England' ~ 'UK',
    country == 'Scotland' ~ 'UK',
    country == 'Trinidad and Tobago' ~ 'Trinidad',
    TRUE ~ country
  ))

Now we need a map and merge our data with it. This would be a little bit more difficult if we did not have the sf package.

world_map <- st_as_sf(maps::map('world', plot = FALSE, fill = TRUE))

Then we will merge the data from the map with the data provided by the R4DS challenge. Thank’s to dplyr and sf, we can do this with the following lines of code. Here the variables ID from world map and country from data must be equal at each country.

map_years <- world_map %>% 
  full_join(data, by = c('ID' = 'country'))

Creating a GIF

Building the gif_map function

To make easier to create a GIF for different causes of death, I built the following function. The inputs are the data and a string representing the name of the variable corresponding to the cause of death you want to visualize.

gif_map <- function(data, cause_of_death) {
  # Create limits to fix the scales
  fill_lim <- range(data %$% get(cause_of_death), na.rm = T)
  
  # Split the data set for different years
  data_list <- split(data, data$year)
  
  out <- lapply(data_list, function(data, cause_of_death, fill_lim){
    p <- ggplot(data, aes(fill = get(cause_of_death))) +
      geom_sf(size = .2, color = 'black') +
      scale_fill_gradient(low = "#ffefef", high = "#720000", space = "Lab",
                          na.value = "#c6c6c6", guide = "colourbar", 
                          limits = c(fill_lim[1], fill_lim[2]),
                          name = cause_of_death) +
      ggthemes::theme_map() +
      labs(title = paste('Year:', unique(data$year))) +
      theme(panel.grid.major = element_line(colour = 'gray', size = .2, linetype = 'dashed'),
            legend.position = 'bottom')
    print(p)
  }, cause_of_death, fill_lim)
}

Using it

Now that we’ve already built a function, use it’s very easy.

# Specifying the width, height and resolution
img <- magick::image_graph(width = 800, height = 350, res = 96)

# gif for Homicide mortality rate
gif_map(map_years, "Homicide (%)")
dev.off()

# building a gif with 8 frames per second
animation <- magick::image_animate(img, fps = 8)

# Visualize it
print(animation)

# Save it
magick::image_write(animation, path = 'img/homicide.gif')

gganimate code (outdated)

There is an option to create the GIF with gganimate, the syntax is very simple and it is attached at the following block of code.

library(gganimate)
ggplot(map_years, aes(fill = `Homicide (%)`, frame = years)) +
      geom_sf(size = .2, color = 'black') +
      scale_fill_gradient(low = "#ffefef", high = "#720000", space = "Lab",
                          na.value = "#c6c6c6", guide = "colourbar") +
      ggthemes::theme_map() +
      labs(title = paste('Year:', unique(data$year))) +
      theme(panel.grid.major = element_line(colour = 'gray', size = .2, linetype = 'dashed'),
            legend.position = 'bottom')

Final remarks

At this post, I showed how to build GIF’s considering space-time data with a few lines of code. I hope that you enjoyed the post, and if you have any doubt or consideration, you can contact me at twitter or email.

Avatar
Lucas Godoy
PhD Candidate / TA /GA

I’m a PhD Candidate in Stats interested in R, Open Data, and the most diverse applications of statistics.

comments powered by Disqus