GDP per capita in Europe

An animated chloropleth shows the transition of GDP per Capita in Europe from 1980 to 2022, with country-wise data

Maps
Data Is Plural
Animation
Governance
Author

Aditya Dahiya

Published

September 28, 2024

Figure 1: An animated chloropleth map of Europe depicting change in GDP per capita from 1980 to 2022.

How I made this graphic?

Loading libraries & data

Code
# Data Import and Wrangling Tools
library(tidyverse)            # All things tidy
library(sf)                   # Maps

# Final plot tools
library(scales)               # Nice Scales for ggplot2
library(fontawesome)          # Icons display in ggplot2
library(ggtext)               # Markdown text support for ggplot2
library(showtext)             # Display fonts in ggplot2
library(colorspace)           # Lighten and Darken colours
library(seecolor)             # To print and view colours
library(patchwork)            # Combining plots
library(openxlsx)             # Get Excel File data from Web Sources

library(gganimate)            # Animation

url <- "https://dataverse.nl/api/access/datafile/421302"
rawdf <- read.xlsx(
  url,
  sheet = "Full data",
  na.strings = ""
)

Data Wrangling and EDA

Code
sf_df <- rnaturalearth::ne_countries(
  scale = "large",
  returnclass = "sf"
  ) |> 
  filter(name == sovereignt) |> 
  filter(continent == "Europe") |> 
  select(name, iso_a3, admin, geometry) |> 
  mutate(
    iso_a3 = case_when(
      name == "Norway" ~ "NOR",
      name == "France" ~ "FRA",
      .default = iso_a3
    )
  )

select_countries <- distinct(sf_df, iso_a3) |> pull()

df <- rawdf |> 
  as_tibble() |> 
  rename(iso_a3 = countrycode) |> 
  filter(year > 1980 & year <= 2022) |> 
  filter(iso_a3 %in% select_countries) |> 
  filter(!(iso_a3 %in% c("RUS"))) |> 
  # filter(region %in% c("Eastern Europe", "Western Europe")) |> 
  select(-pop, -country) |> 
  left_join(sf_df) |> 
  st_as_sf()


# Get the suitable rangle for fill scale to exagerrate differences
range_cols <- c(12000, 60000)

df$gdppc |> range(na.rm = TRUE)

df2 <- df |> 
  mutate(gdppc = log(gdppc))

# range_log_fill <- range(df2$gdppc)

breaks_fill <- c(10000, 20000, 40000, 70000)

breaks_log_fill <- log(breaks_fill)

Visualization Parameters

Code
# Font for titles
font_add_google("Fira Sans",
  family = "title_font"
) 

# Font for the caption
font_add_google("Barlow Condensed",
  family = "caption_font"
) 

# Font for plot text
font_add_google("Fira Sans",
  family = "body_font"
) 

showtext_auto()

bg_col <- "white"

text_col <- "grey15"
text_hil <- "grey15"

bts <- 20

plot_title <- "GDP per Capita" 

plot_subtitle <- "Year: {closest_state}"

plot_caption <- paste0(
  "Data: Maddison Project Database 2023",
  "  |  Code & Graphics: @aditya-dahiya (GitHub)"
  )

The static plot

Code
g <- df2 |> 
  ggplot(
    mapping = aes(
      fill = gdppc
    )
  ) +
  geom_sf(
    colour = bg_col,
    linewidth = 0.1
  ) +
  
  # Coordinates and Scales
  coord_sf(
    xlim = c(-11, 41),
    ylim = c(33, 70)
  ) +
   paletteer::scale_fill_paletteer_c(
    "viridis::turbo",
    direction = -1,
    name = NULL,
    limits = range(breaks_log_fill),
    breaks = breaks_log_fill,
    labels = number(
      breaks_fill,
      accuracy = 1,
      prefix = "$",
      scale_cut = cut_short_scale()
    ),
    oob = scales::squish,
    na.value = "grey80"
  ) +
  
  # Labels and Themes
  labs(
    title = plot_title,
    caption = plot_caption,
    subtitle = plot_subtitle
  ) +
  ggthemes::theme_map(
    base_family = "body_font",
    base_size = bts
  ) +
  theme(
    legend.position = c(0.5, 0),
    legend.justification = c(0.5, 0),
    legend.direction = "horizontal",
    legend.key.height = unit(5, "mm"),
    legend.key.width = unit(30, "mm"),
    text = element_text(
      colour = text_col
    ),
    
    # Labels
    plot.title = element_text(
      family = "title_font",
      hjust = 0,
      size = bts * 1.1
    ),
    plot.subtitle = element_text(
      hjust = 0,
      margin = margin(10,0,-30,0, "mm"),
      face = "bold",
      size = bts * 1.2
    ),
    plot.caption = element_text(
      family = "caption_font",
      size = 0.6 * bts,
      hjust = 0.5, 
      margin = margin(0,0,4,0, "mm")
    )
  ) +
  transition_states(
    year,
    transition_length = 0.1,
    state_length = 1
  )

anim_save(
  filename = here::here("data_vizs", "dip_eu_gdppc.gif"),
  animation = g,
  fps = 5,
  start_pause = 1,
  end_pause = 1,
  rewind = FALSE,
  height = 600,
  width = 600,
  units = "px"
)

A static plot for thumbnail

Code
bts = 40

g <- df2 |>
  filter(year == 2022) |> 
  ggplot(
    mapping = aes(
      fill = gdppc
    )
  ) +
  geom_sf(
    colour = bg_col,
    linewidth = 0.2
  ) +
  
  # Coordinates and Scales
  coord_sf(
    xlim = c(-11, 41),
    ylim = c(33, 70)
  ) +
   paletteer::scale_fill_paletteer_c(
    "viridis::turbo",
    direction = -1,
    name = NULL,
    limits = range(breaks_log_fill),
    breaks = breaks_log_fill,
    labels = number(
      breaks_fill,
      accuracy = 1,
      prefix = "$",
      scale_cut = cut_short_scale()
    ),
    oob = scales::squish,
    na.value = "grey80"
  ) +
  
  # Labels and Themes
  labs(
    title = "GDP per Capita\n(2022)",
    caption = plot_caption,
    subtitle = "Year: 2022"
  ) +
  ggthemes::theme_map(
    base_family = "body_font",
    base_size = bts
  ) +
  theme(
    plot.margin = margin(2,2,2,2, "mm"),
    legend.position = c(0.5, 0),
    legend.justification = c(0.5, 0),
    legend.direction = "horizontal",
    legend.key.height = unit(2, "mm"),
    legend.key.width = unit(10, "mm"),
    text = element_text(
      colour = text_col
    ),
    legend.margin = margin(0,0,0,0, "mm"),
    legend.text = element_text(
      margin = margin(1,0,0,0, "mm")
    ),
    
    
    # Labels
    plot.title = element_text(
      family = "title_font",
      hjust = 0,
      size = bts * 1.1,
      margin = margin(2,0,-10,0, "mm"),
      lineheight = 0.4
    ),
    plot.subtitle = element_blank(),
    plot.caption = element_text(
      family = "caption_font",
      size = 0.6 * bts,
      hjust = 0.5, 
      margin = margin(0,0,1,0, "mm")
    )
  )

ggsave(
  filename = here::here("data_vizs", "dip_eu_gdppc.png"),
  plot = g,
  width = 100,    # Best Twitter Aspect Ratio = 5:4
  height = 100,   
  units = "mm",
  bg = "white"
)


library(magick)
# Saving a thumbnail for the webpage
image_read(here::here("data_vizs", "dip_eu_gdppc.png")) |> 
  image_resize(geometry = "400") |> 
  image_write(
    here::here(
      "data_vizs", 
      "thumbnails", 
      "dip_eu_gdppc.png"
    )
  )