Racing Barplots with {ggpattern}, {flagon} & {gganimate}

Racing Barplot

A racing barplot is a way to visualize changed rankings and magnitudes over time.

In this post, I use flag images from the flagon package to decorate the a barplot (using ggpattern)

I adapted a great presentation/flipbook by Gina Reynolds which can be found here.

Use the gapminder data

Keep only the top 10 most populous countries for all available years.

library(tidyverse)
library(ggplot2)
library(gganimate)
library(gapminder)
library(ggpattern)


ranked_by_year <- gapminder %>%  
  select(country, pop, year, continent) %>%  
  group_by(year) %>%  
  arrange(year, -pop) %>%  
  mutate(rank = 1:n()) %>%  
  filter(rank <= 10) %>%
  mutate(pop = pop / 1e6)

Assign a flag for each country

Lookup a flag image for each country in the flagon package.

ccodes <- flagon::country_codes %>% select(country, ccode)

ranked_by_year <- ranked_by_year %>%
  left_join(ccodes, by = 'country') %>%
  mutate(
    flag = flagon::flags(ccode)
  )
Warning: Column `country` joining factor and character vector, coercing into
character vector
ranked_by_year %>%
  head(5) %>%
  knitr::kable(caption = "Attach a flag image to each country")
Table 1: Attach a flag image to each country
country pop year continent rank ccode flag
China 556.26353 1952 Asia 1 cn /Library/Frameworks/R.framework/Versions/3.6/Resources/library/flagon/png/cn.png
India 372.00000 1952 Asia 2 in /Library/Frameworks/R.framework/Versions/3.6/Resources/library/flagon/png/in.png
United States 157.55300 1952 Americas 3 us /Library/Frameworks/R.framework/Versions/3.6/Resources/library/flagon/png/us.png
Japan 86.45902 1952 Asia 4 jp /Library/Frameworks/R.framework/Versions/3.6/Resources/library/flagon/png/jp.png
Indonesia 82.05200 1952 Asia 5 id /Library/Frameworks/R.framework/Versions/3.6/Resources/library/flagon/png/id.png

Animate the bar plot of population over time

plot_df <- ranked_by_year #%>% filter(year %in% c(1957, 1987, 2007))

dev.off()
dev.off()

p <- ggplot(plot_df, aes(group = country)) + 
  geom_rect_pattern(
    aes(
      xmin = 0, 
      xmax = pop, 
      ymin = rank - 0.45, 
      ymax = rank + 0.45,
      pattern_filename = I(flag)
    ), 
    pattern = 'image',
    fill    = 'grey70',
    pattern_gravity = 'East',  # Push flag to the right
    pattern_type    = 'none',  # no auto-rescale
    pattern_scale   = -2       # Scale to height.
  ) +   
  geom_text(aes(y = rank, label = country), x = -50, col = "gray13",  hjust = "right", size = 10) +
  geom_text(aes(label = as.character(year)), x = 1000 , y = -10, size = 30, col = "grey18") +
  scale_y_reverse() + 
  scale_fill_brewer(palette = 'Set2') + 
  labs(x = 'Population (millions)', fill = NULL) +  
  theme_bw() + 
  theme(
    axis.text.y     = element_blank(),
    axis.title.y    = element_blank(),
    axis.ticks.y    = element_blank(),
    legend.key.size = unit(2, 'cm'),
    axis.text       = element_text(size = 20),
    axis.title      = element_text(size = 20)
  ) +   
  scale_x_continuous(  
    limits = c(-450, 1400),  
    breaks = c(0, 400, 800, 1200)
  ) +
  gganimate::transition_time(year)