Home » The final frontier: animating visualizations using gganimate

The final frontier: animating visualizations using gganimate

  • by
  • 3 min read

One of the aspects of a visualization I have been ignoring for most of the time, is animation. I saw a LinkedIn post on gganimate and I decided it was time for me to deal with the final frontier of visualization. Half the world is in quarantaine and financial media have been speculating about the impact on GDP. So… let’s plot the GDP/Capita over the past couple of years in the biggest countries of the EU. Animated!

First of all, we load in the necessary packages. Ggplot2 does not produce anti-aliased visualizations, so that’s why I load the Cairo package (I wrote a blog post about cairo here). The file ‘req.R’ contains some theming and libraries I use a lot. Feel free to browse it in the GitHub repository.



I downloaded the GDP/Capita data from the world bank and loaded it into a data table named dt. I select column 45 to 63 which contains data from 2000 to 2018. Finally, I merge with the metadata and remove rows that contain NAs.

dt <- fread('API_NY.GDP.PCAP.CD_DS2_en_csv_v2_821084.csv', skip = 4, header = T)
dt <- dt[,c(1:2,45:63)]
colnames(dt) <- c('COUNTRY','CODE',paste0('YEAR_',colnames(dt[,3:21])))

meta <- fread('Metadata_Country_API_NY.GDP.PCAP.CD_DS2_en_csv_v2_821084.csv', skip = 0, header = T)
meta <- meta[,1:3]
colnames(meta) <- c('CODE','REGION','INCOME_GROUP')

dt <- merge(meta,dt)

dt[dt == ''] <- NA
dt <- dt[complete.cases(dt),]

Next, I do some transformations. First, I pivot the data so that the years are nicely lined up in one column. Then, I transform the country into a factor, the year into a date and the GDP into an integer (no decimals). Finally, I select six big EU countries.

dt <- melt(dt, id.vars = c('CODE','REGION','INCOME_GROUP','COUNTRY'), 
           variable.name = 'YEAR',
           variable.factor = F,
           value.name = 'GDP_CAP')

dt[,YEAR := as.numeric(gsub('YEAR_','',YEAR))]
dt[,COUNTRY := factor(COUNTRY, levels = dt[YEAR == 2011][order(GDP_CAP)]$COUNTRY)]
dt[,YEAR := ymd(paste0(YEAR,'-01-01'))]
dt[,GDP_CAP := as.integer(round(GDP_CAP,0))]

europe <- dt[REGION == 'Europe & Central Asia']
europe <- europe[COUNTRY %in% c('France','Germany','Italy','Spain','Poland','United Kingdom')]

And finally, I produce the animation. I use transition_reveal to slowly transition the graph from year to year. Ease_aes is configured to behave like a sinoid, slow in the beginning and in the end, but fast in the middle. I have configured the animate function to use Cairo, so the lines are properly anti-aliased.

g <- ggplot(europe, aes(x = YEAR, y = GDP_CAP, color = COUNTRY)) + 
  geom_line(size=1, stat = 'identity', alpha = 0.9) +
  geom_point(size = 2.5) +
  geom_text(aes(x = YEAR, label = COUNTRY), hjust = -0.2) +
  # Settings
  scale_x_date(date_breaks = '1 year', date_labels = '%Y') +
  coord_cartesian(clip = 'off') + 
  xlab('') +
  ylab('GDP/Capita') +
  ylim(0,60000) +
  # Theme
  t +
  # Colors
  scale_color_manual(values = pal) +
  # Extra theming
  theme(legend.title = element_blank(), legend.position = 'none') +
  # Animation
  transition_reveal(YEAR) +

animate(g, duration = 15, fps = 20, width = 1280, height = 720, type = 'cairo')

And this is the result. Brexit has been hard on the UK it seems.

Say thanks, ask questions or give feedback

Technologies get updated, syntax changes and honestly… I make mistakes too. If something is incorrect, incomplete or doesn’t work, let me know in the comments below and help thousands of visitors.

Leave a Reply

Your email address will not be published. Required fields are marked *