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
#r4ds presents Week 3 of #TidyTuesday! Let's explore global causes of mortality!
— Tom Mock (@thomas_mock) April 16, 2018
Make a meaningful graphic, and post your code!
Data: https://t.co/ygKv8PqOfI
Article: https://t.co/MOnlCBzdaL
Blog: https://t.co/cZJ94Hhz7U #tidyverse #rstats #dataviz #ggplot2 @R4DScommunity pic.twitter.com/52rktsOcSQ
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 withggplot2
anddplyr
, 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 ofmagick
, 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.