Motivations

Original graph by Financial Times can be replicated as follows:

R Codes

R codes for replicating the chart:

# Clear R environment: 
rm(list = ls())


# Load data: 
library(tidyverse)

read_csv("http://infographics.economist.com/databank/Economist_pensions.csv") -> pensions_data

# Rename for all columns: 

names(pensions_data) <- c("country", "pop_over65", "gov_spending")

# Remove mising: 

pensions_data %>% filter(!is.na(gov_spending)) -> pensions_data

# The Financial colors (https://www.r-bloggers.com/2018/06/the-financial-times-and-bbc-use-r-for-publication-graphics/): 

bgr_color <- "#262a33"

pink_color <- "#ff0055"

blue1_color <- "#0d64fc"

grey_color <- "#526171"

grey_text <- "#9b9da1"


some_countries <- c("Brazil", "Turkey", "Mexico", "Poland", "South Kore", "Italy", 
                    "United States", "France", "OECD average", "Japan", "Greece")


# Extract OECD countries from web: 


"https://en.wikipedia.org/wiki/OECD" %>% 
  rvest::read_html() %>% 
  rvest::html_nodes(xpath = '//*[@id="mw-content-text"]/div[1]/div[3]') %>% 
  rvest::html_text() %>% 
  str_split("\n", simplify = TRUE) %>% 
  as.vector() %>% 
  .[-1] -> oecd_countries

# Averages for OECD countries: 

pensions_data %>% 
  filter(country %in% oecd_countries) %>% 
  mutate(country = "OECD average") %>% 
  group_by(country) %>% 
  summarise(pop_over65 = mean(pop_over65), 
            gov_spending = mean(gov_spending)) -> data_oecd

# Joint the two data sets: 

bind_rows(pensions_data, data_oecd) -> data_for_ploting

data_for_ploting %>% 
  mutate(text_face = case_when(country == "Brazil" ~ "bold", 
                               country == "OECD average" ~ "italic", 
                               TRUE ~ "plain")) -> data_for_ploting


data_for_ploting %>% filter(country %in% some_countries) -> df1

data_for_ploting %>% filter(!country %in% some_countries) -> df2

p_title <- "Brazil's golden oldie blowout"

p_subtitle <- "Latest available"

p_caption <- "Source: OECD; World Bank; PrevidĂȘncia Social | Graphic Designer: Nguyen Chi Dung"

left_text <- "Government spending\non pension benefits\n% of GDP"

library(ggrepel)

library(showtext) # Package for using extra fonts. 

# Fira Sans Condensed

my_font <- "Fira Sans Condensed" 

# Load font for ploting: 

font_add_google(name = my_font, family = my_font) 

showtext_auto() # Automatically render text. 

ggplot() + 
  geom_point(data = data_for_ploting, aes(pop_over65, gov_spending), color = "#90aac6", size = 5, alpha = 0.4) + 
  geom_point(data = data_for_ploting %>% filter(country == "Brazil"), 
             aes(pop_over65, gov_spending), shape = 21, size = 5, fill = blue1_color, color = "white", stroke = 1) + 
  geom_point(data = data_for_ploting %>% filter(country %in% c("France", "Italy", "Greece", "Japan")), 
             aes(pop_over65, gov_spending), shape = 21, size = 5, fill = pink_color, color = "white", stroke = 1) + 
  geom_point(data = data_for_ploting %>% filter(country %in% c("United States", "OECD average")), 
             aes(pop_over65, gov_spending), color = pink_color, size = 5, alpha = 0.8) + 
  geom_point(data = data_for_ploting %>% filter(country %in% c("Mexico", "Turkey")), 
             aes(pop_over65, gov_spending), color = blue1_color, size = 5, alpha = 0.8) +  
  theme(plot.background = element_rect(fill = bgr_color, color = NA)) + 
  theme(panel.background = element_rect(fill = bgr_color, color = NA)) + 
  theme(panel.grid.major = element_line(size = 0.8, color = "#3e4046")) + 
  theme(panel.grid.minor = element_blank()) + 
  geom_text_repel(data = df1 %>% filter(country == "France"), 
                  aes(pop_over65, gov_spending, label = country), force = 0, direction = "y", seed = 12, 
                  family = my_font, size = 4, color = "grey95", nudge_y = 1) +  
  geom_text_repel(data = df1 %>% filter(country == "Greece"), 
                  aes(pop_over65, gov_spending, label = country), force = 1, direction = "x", seed = 12, 
                  family = my_font, size = 4, color = "grey95", nudge_x = 1.4) + 
  geom_text_repel(data = df1 %>% filter(country == "Italy"), 
                  aes(pop_over65, gov_spending, label = country), force = 1, direction = "y", seed = 12, 
                  family = my_font, size = 4, color = "grey95", nudge_y = 1) + 
  geom_text_repel(data = df1 %>% filter(country == "Japan"), 
                  aes(pop_over65, gov_spending, label = country), force = 1, direction = "y", seed = 12, 
                  family = my_font, size = 4, color = "grey95", nudge_y = -0.8) + 
  geom_text_repel(data = df1 %>% filter(country == "United States"), 
                  aes(pop_over65, gov_spending, label = country), force = 4, direction = "x", seed = 12, 
                  family = my_font, size = 4, color = "grey95", nudge_x = -2.4) + 
  geom_text_repel(data = df1 %>% filter(country == "OECD average"), 
                  aes(pop_over65, gov_spending, label = country), force = 1, direction = "x", seed = 12, 
                  family = my_font, size = 4, color = "grey95", nudge_x = -2.5, fontface = "italic") + 
  geom_text_repel(data = df1 %>% filter(country == "Brazil"), 
                  aes(pop_over65, gov_spending, label = country), force = 1, direction = "y", seed = 12, 
                  family = my_font, size = 4, nudge_y = 1.1, fontface = "bold", color = "white") + 
  geom_text_repel(data = df1 %>% filter(country == "Turkey"), 
                  aes(pop_over65, gov_spending, label = country), force = 1, direction = "y", seed = 12, 
                  family = my_font, size = 4, color = "grey95", nudge_y = 0.9) +  
  geom_text_repel(data = df1 %>% filter(country == "Mexico"), 
                  aes(pop_over65, gov_spending, label = country), force = 1, direction = "y", seed = 12, 
                  family = my_font, size = 4, color = "grey95", nudge_y = 0.9) + 
  labs(subtitle = left_text, x = "Population aged 65 years and over, % of total") + 
  scale_x_continuous(limits = c(5, 30.5), breaks = seq(5, 30, 5), expand = c(0, 0)) + 
  scale_y_continuous(limits = c(0, 20), breaks = seq(0, 20, 5), expand = c(0, 0), position = "right") +  
  theme(axis.title.y.right = element_blank()) + 
  theme(panel.grid.minor = element_blank()) + 
  theme(plot.subtitle = element_text(hjust = 1.05, color = "grey95", family = my_font, size = 12, vjust = 4)) + 
  theme(axis.title.x = element_text(color = "grey95", family = my_font, size = 12)) + 
  theme(axis.text = element_text(color = "grey95", family = my_font, size = 14)) -> p 

library(patchwork)  

p + 
  plot_annotation(title = p_title, subtitle = p_subtitle, caption = p_caption) + 
  plot_annotation(theme = theme(plot.background = element_rect(fill = bgr_color))) + 
  plot_annotation(theme = theme(plot.title = element_text(family = my_font, size = 18, face = "bold", vjust = -1.5, color = "white"))) + 
  plot_annotation(theme = theme(plot.subtitle = element_text(family = my_font, size = 13, color = "grey95", vjust = -2))) + 
  plot_annotation(theme = theme(plot.caption = element_text(family = my_font, color = "grey60", size = 11, hjust = 0))) + 
  theme(plot.margin = unit(c(0.5, 0.5, 0.1, 0.7), "cm")) 

# Make Financial Times icon: 

library(grid)

grid.rect(x = 0.055, y = 1, width = 0.05*1.7, height = 0.008, just = c("left", "top"), gp = gpar(fill = "grey95", col = "grey95"))