This project uses GDP dataset downloaded from the WorldBank Database. The dataset can be accessed in GitHub Repository

1 Part A: Loading libraries and data pre-processing

1.1 Libraries

knitr::opts_chunk$set(echo = TRUE)

library(tidyverse)
library(janitor)
library(gganimate)
#install.packages("gifski")
library(gifski)
library(readr)

1.2 Load GDP data

gdp <- read_delim("gdp_ori.csv", 
    ";", escape_double = FALSE, trim_ws = TRUE)
## Parsed with column specification:
## cols(
##   .default = col_double(),
##   country_name = col_character(),
##   country_code = col_character(),
##   Region = col_character(),
##   indicator_name = col_character()
## )
## See spec(...) for full column specifications.
head(gdp)
gdp

Drop non-country rows

gdp_clean <- filter(gdp, !(country_code %in% c("ARB", "CEB", "CSS","EAP", "EAR", "EAS", "ECA", "ECS", "EMU", "EUU", "FCS", "HIC", "HPC", "IBD", "IBT", "IDA", "IDB", "IDX", "INX", "LAC", "LCN", "LDC", "LIC", "LMC", "LMY", "LTE", "MIC", "MEA", "MNA", "NAC", "OED", "OSS", "PST", "PSS", "PRE", "SSA", "SSF", "TEA", "TLA", "TMN", "TSA", "TSS", "UMC", "WLD")))
gdp_clean

Drop all rows with NA in “Region” column

gdp_clean <- subset(gdp_clean, !is.na(Region))
gdp_clean

Transform the dataframe into long shape

gdp_long <- gdp_clean %>% 
  mutate_at(vars(contains("yr")),as.numeric) %>% 
  gather(year,gdp,5:54)

1.3 Save the dataframe that is ready to use

write_csv(gdp_long, "gdp_ready.csv")

2 Part B: Building the static plots using ggplot

2.1 Import the ready-to-use data

gdp_ready <- read_csv("gdp_ready.csv")
## Parsed with column specification:
## cols(
##   country_name = col_character(),
##   country_code = col_character(),
##   Region = col_character(),
##   indicator_name = col_character(),
##   year = col_double(),
##   gdp = col_double()
## )
gdp_ready

2.2 Arrange the ranking

gdp_set <- gdp_ready %>%
  group_by(year) %>%
  mutate(rank = rank(-gdp),
         gdp_rel = gdp/gdp[rank==1],
         gdp_lbl = paste0(" ",round(gdp/1e9))) %>%
  group_by(country_name) %>% 
  filter(rank <=30) %>%
  ungroup()

2.3 Building the static plot

static_plot <- ggplot(gdp_set, aes(rank, group = country_name)) +  
  geom_tile(aes(y = gdp/2,
                height = gdp, fill = Region,
                width = 0.9), alpha = 0.8, color = NA) +
  geom_text(aes(y = 0, label = paste(country_name, " ")), vjust = 0.2, hjust = 1) +
  geom_text(aes(y=gdp,label = gdp_lbl, hjust=0)) +
  geom_text(aes(x=30, y=max(gdp) , label = as.factor(year)), vjust = 0.2, alpha = 0.5,  col = "gray", size = 20) +
  coord_flip(clip = "off", expand = FALSE) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_reverse() +
  scale_fill_discrete(guide = guide_legend(title.theme = element_text(
      size = 20), label.theme = element_text(size = 15))) +
  theme(axis.line=element_blank(),
        axis.text.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks=element_blank(),
        axis.title.x=element_blank(),
        axis.title.y=element_blank(),
        panel.background=element_blank(),
        panel.border=element_blank(),
        panel.grid.major=element_blank(),
        panel.grid.minor=element_blank(),
        panel.grid.major.x = element_line( size=.1, color="grey" ),
        panel.grid.minor.x = element_line( size=.1, color="grey" ),
        plot.title=element_text(size=25, hjust=0, face="bold", colour="black", vjust=-1),
        plot.subtitle=element_text(size=18, hjust=1, face="italic", color="grey"),
        plot.caption =element_text(size=14, hjust=1, face="italic", color="grey"),
        plot.background=element_blank(),
       plot.margin = margin(2,2, 2, 4, "cm"))

3 Part C: Animating the static plot

animated <- static_plot + transition_states(year,
transition_length = 3, state_length = 0, wrap = FALSE) +
  view_follow(fixed_x = TRUE)  +
  ease_aes('linear')+
    enter_fade()+
    exit_fade() +
  labs(title = 'Top 30 World GDP, 1970-2019',  
       subtitle  =  "GDP in Billions USD (constant 2010)",
       caption  = "Data Source: World Bank Data")

3.1 Render the animated chart to .gif file

animate(animated, 150, fps = 5, end_pause = 30, width = 1500, height = 1000, 
        renderer = gifski_renderer("anim_gdp.gif"))

LS0tDQp0aXRsZTogIkNyZWF0aW5nIEFuaW1hdGVkIEJhciBDaGFydCBSYWNlIGluIFIiDQphdXRob3I6ICJIYXJyeSBBZ2ludGEiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlDQogICAgdG9jX2RlcHRoOiA0DQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyINCiAgICB0aGVtZTogImNvc21vIg0KICAgIGhpZ2hsaWdodDogIm1vbm9jaHJvbWUiDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KICBodG1sX25vdGVib29rOg0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIGhpZ2hsaWdodDogbW9ub2Nocm9tZQ0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IGNvc21vDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogICAgICBzbW9vdGhfc2Nyb2xsOiBubw0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KPHN0eWxlPg0KaDEudGl0bGUge2ZvbnQtc2l6ZTogMThwdDsgY29sb3I6IERhcmtCbHVlO30gDQpib2R5LCBoMSwgaDIsIGgzLCBoNCB7Zm9udC1mYW1pbHk6ICJQYWxhdGlubyIsIHNlcmlmO30NCmJvZHkge2ZvbnQtc2l6ZTogMTJwdDt9DQovKiBIZWFkZXJzICovDQpoMSxoMixoMyxoNCxoNSxoNntmb250LXNpemU6IDE0cHQ7IGNvbG9yOiAjMDAwMDhCO30NCmJvZHkge2NvbG9yOiAjMzMzMzMzO30NCmEsIGE6aG92ZXIge2NvbG9yOiAjOEIzQTYyO30NCnByZSB7Zm9udC1zaXplOiAxMnB4O30NCjwvc3R5bGU+DQoNClRoaXMgcHJvamVjdCB1c2VzIEdEUCBkYXRhc2V0IGRvd25sb2FkZWQgZnJvbSB0aGUgV29ybGRCYW5rIERhdGFiYXNlLiBUaGUgZGF0YXNldCBjYW4gYmUgYWNjZXNzZWQgaW4gW0dpdEh1YiBSZXBvc2l0b3J5XShodHRwczovL2dpdGh1Yi5jb20vaGFnaW50YS9hbmltYXRlZC1iYXItY2hhcnQtaW4tUikNCg0KDQojIFBhcnQgQTogTG9hZGluZyBsaWJyYXJpZXMgYW5kIGRhdGEgcHJlLXByb2Nlc3NpbmcNCiMjIExpYnJhcmllcw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCg0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGphbml0b3IpDQpsaWJyYXJ5KGdnYW5pbWF0ZSkNCiNpbnN0YWxsLnBhY2thZ2VzKCJnaWZza2kiKQ0KbGlicmFyeShnaWZza2kpDQpsaWJyYXJ5KHJlYWRyKQ0KYGBgDQoNCiMjIExvYWQgR0RQIGRhdGENCmBgYHtyfQ0KZ2RwIDwtIHJlYWRfZGVsaW0oImdkcF9vcmkuY3N2IiwgDQogICAgIjsiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIHRyaW1fd3MgPSBUUlVFKQ0KYGBgDQoNCmBgYHtyfQ0KaGVhZChnZHApDQpgYGANCg0KYGBge3J9DQpnZHANCmBgYA0KDQpEcm9wIG5vbi1jb3VudHJ5IHJvd3MNCmBgYHtyfQ0KZ2RwX2NsZWFuIDwtIGZpbHRlcihnZHAsICEoY291bnRyeV9jb2RlICVpbiUgYygiQVJCIiwgIkNFQiIsICJDU1MiLCJFQVAiLCAiRUFSIiwgIkVBUyIsICJFQ0EiLCAiRUNTIiwgIkVNVSIsICJFVVUiLCAiRkNTIiwgIkhJQyIsICJIUEMiLCAiSUJEIiwgIklCVCIsICJJREEiLCAiSURCIiwgIklEWCIsICJJTlgiLCAiTEFDIiwgIkxDTiIsICJMREMiLCAiTElDIiwgIkxNQyIsICJMTVkiLCAiTFRFIiwgIk1JQyIsICJNRUEiLCAiTU5BIiwgIk5BQyIsICJPRUQiLCAiT1NTIiwgIlBTVCIsICJQU1MiLCAiUFJFIiwgIlNTQSIsICJTU0YiLCAiVEVBIiwgIlRMQSIsICJUTU4iLCAiVFNBIiwgIlRTUyIsICJVTUMiLCAiV0xEIikpKQ0KZ2RwX2NsZWFuDQpgYGANCg0KRHJvcCBhbGwgcm93cyB3aXRoIE5BIGluICJSZWdpb24iIGNvbHVtbg0KYGBge3J9DQpnZHBfY2xlYW4gPC0gc3Vic2V0KGdkcF9jbGVhbiwgIWlzLm5hKFJlZ2lvbikpDQpnZHBfY2xlYW4NCmBgYA0KDQpUcmFuc2Zvcm0gdGhlIGRhdGFmcmFtZSBpbnRvIGxvbmcgc2hhcGUNCmBgYHtyfQ0KZ2RwX2xvbmcgPC0gZ2RwX2NsZWFuICU+JSANCiAgbXV0YXRlX2F0KHZhcnMoY29udGFpbnMoInlyIikpLGFzLm51bWVyaWMpICU+JSANCiAgZ2F0aGVyKHllYXIsZ2RwLDU6NTQpDQpgYGANCg0KIyMgU2F2ZSB0aGUgZGF0YWZyYW1lIHRoYXQgaXMgcmVhZHkgdG8gdXNlDQpgYGB7cn0NCndyaXRlX2NzdihnZHBfbG9uZywgImdkcF9yZWFkeS5jc3YiKQ0KYGBgDQoNCiMgUGFydCBCOiBCdWlsZGluZyB0aGUgc3RhdGljIHBsb3RzIHVzaW5nIGdncGxvdA0KIyMgSW1wb3J0IHRoZSByZWFkeS10by11c2UgZGF0YQ0KYGBge3J9DQpnZHBfcmVhZHkgPC0gcmVhZF9jc3YoImdkcF9yZWFkeS5jc3YiKQ0KZ2RwX3JlYWR5DQpgYGANCg0KIyMgQXJyYW5nZSB0aGUgcmFua2luZw0KYGBge3J9DQpnZHBfc2V0IDwtIGdkcF9yZWFkeSAlPiUNCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIG11dGF0ZShyYW5rID0gcmFuaygtZ2RwKSwNCiAgICAgICAgIGdkcF9yZWwgPSBnZHAvZ2RwW3Jhbms9PTFdLA0KICAgICAgICAgZ2RwX2xibCA9IHBhc3RlMCgiICIscm91bmQoZ2RwLzFlOSkpKSAlPiUNCiAgZ3JvdXBfYnkoY291bnRyeV9uYW1lKSAlPiUgDQogIGZpbHRlcihyYW5rIDw9MzApICU+JQ0KICB1bmdyb3VwKCkNCmBgYA0KDQojIyBCdWlsZGluZyB0aGUgc3RhdGljIHBsb3QNCmBgYHtyfQ0Kc3RhdGljX3Bsb3QgPC0gZ2dwbG90KGdkcF9zZXQsIGFlcyhyYW5rLCBncm91cCA9IGNvdW50cnlfbmFtZSkpICsgIA0KICBnZW9tX3RpbGUoYWVzKHkgPSBnZHAvMiwNCiAgICAgICAgICAgICAgICBoZWlnaHQgPSBnZHAsIGZpbGwgPSBSZWdpb24sDQogICAgICAgICAgICAgICAgd2lkdGggPSAwLjkpLCBhbHBoYSA9IDAuOCwgY29sb3IgPSBOQSkgKw0KICBnZW9tX3RleHQoYWVzKHkgPSAwLCBsYWJlbCA9IHBhc3RlKGNvdW50cnlfbmFtZSwgIiAiKSksIHZqdXN0ID0gMC4yLCBoanVzdCA9IDEpICsNCiAgZ2VvbV90ZXh0KGFlcyh5PWdkcCxsYWJlbCA9IGdkcF9sYmwsIGhqdXN0PTApKSArDQogIGdlb21fdGV4dChhZXMoeD0zMCwgeT1tYXgoZ2RwKSAsIGxhYmVsID0gYXMuZmFjdG9yKHllYXIpKSwgdmp1c3QgPSAwLjIsIGFscGhhID0gMC41LCAgY29sID0gImdyYXkiLCBzaXplID0gMjApICsNCiAgY29vcmRfZmxpcChjbGlwID0gIm9mZiIsIGV4cGFuZCA9IEZBTFNFKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArDQogIHNjYWxlX3hfcmV2ZXJzZSgpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShndWlkZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZS50aGVtZSA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIHNpemUgPSAyMCksIGxhYmVsLnRoZW1lID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpKSArDQogIHRoZW1lKGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJvcmRlcj1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9saW5lKCBzaXplPS4xLCBjb2xvcj0iZ3JleSIgKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9saW5lKCBzaXplPS4xLCBjb2xvcj0iZ3JleSIgKSwNCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0yNSwgaGp1c3Q9MCwgZmFjZT0iYm9sZCIsIGNvbG91cj0iYmxhY2siLCB2anVzdD0tMSksDQogICAgICAgIHBsb3Quc3VidGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTgsIGhqdXN0PTEsIGZhY2U9Iml0YWxpYyIsIGNvbG9yPSJncmV5IiksDQogICAgICAgIHBsb3QuY2FwdGlvbiA9ZWxlbWVudF90ZXh0KHNpemU9MTQsIGhqdXN0PTEsIGZhY2U9Iml0YWxpYyIsIGNvbG9yPSJncmV5IiksDQogICAgICAgIHBsb3QuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMiwyLCAyLCA0LCAiY20iKSkNCmBgYA0KDQojIFBhcnQgQzogQW5pbWF0aW5nIHRoZSBzdGF0aWMgcGxvdA0KYGBge3J9DQphbmltYXRlZCA8LSBzdGF0aWNfcGxvdCArIHRyYW5zaXRpb25fc3RhdGVzKHllYXIsDQp0cmFuc2l0aW9uX2xlbmd0aCA9IDMsIHN0YXRlX2xlbmd0aCA9IDAsIHdyYXAgPSBGQUxTRSkgKw0KICB2aWV3X2ZvbGxvdyhmaXhlZF94ID0gVFJVRSkgICsNCiAgZWFzZV9hZXMoJ2xpbmVhcicpKw0KICAgIGVudGVyX2ZhZGUoKSsNCiAgICBleGl0X2ZhZGUoKSArDQogIGxhYnModGl0bGUgPSAnVG9wIDMwIFdvcmxkIEdEUCwgMTk3MC0yMDE5JywgIA0KICAgICAgIHN1YnRpdGxlICA9ICAiR0RQIGluIEJpbGxpb25zIFVTRCAoY29uc3RhbnQgMjAxMCkiLA0KICAgICAgIGNhcHRpb24gID0gIkRhdGEgU291cmNlOiBXb3JsZCBCYW5rIERhdGEiKQ0KYGBgDQoNCg0KIyMgUmVuZGVyIHRoZSBhbmltYXRlZCBjaGFydCB0byAuZ2lmIGZpbGUNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQphbmltYXRlKGFuaW1hdGVkLCAxNTAsIGZwcyA9IDUsIGVuZF9wYXVzZSA9IDMwLCB3aWR0aCA9IDE1MDAsIGhlaWdodCA9IDEwMDAsIA0KICAgICAgICByZW5kZXJlciA9IGdpZnNraV9yZW5kZXJlcigiYW5pbV9nZHAuZ2lmIikpDQpgYGANCg0KDQo=