The CIA World Factbook Data Visualization

A cartogram of World Map that distorts the size of each country based on its population, with larger areas representing more populous nations.

#TidyTuesday
Maps
{cartogram}
Author

Aditya Dahiya

Published

October 22, 2024

The dataset for this analysis comes from the CIA World Factbook, specifically the 2014 Country Comparisons section. This comprehensive resource provides essential intelligence on various global aspects, including demographics, government, economics, and military statistics across 265 world entities. The data has been accessed via the {openintro} R package and the {usdatasets} R package, with additional insights shared through this LinkedIn post.

Key variables in the dataset include country names, population figures, birth and death rates, life expectancy, maternal and infant mortality rates, internet users, migration statistics, and more. These metrics provide a well-rounded view of each country’s demographic and social health indicators. No further data cleaning was necessary as the dataset was already well-prepared for analysis.

This cartogram distorts the size of each country based on its population, with larger areas representing more populous nations. The colors indicate population density, where darker shades show higher concentrations of people per square kilometer, offering a visual contrast between vast, sparsely populated regions and densely packed areas.

How I made this graphic?

Loading required libraries, data import & creating custom functions.

Code
# Data Import and Wrangling Tools
library(tidyverse)            # All things tidy
library(janitor)              # Cleaning names etc.
library(here)                 # Root Directory Management

# 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(patchwork)            # Combining plots
library(cartogram)            # Cartogram maps in R
library(sf)                   # Handling sf objects

cia_factbook <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2024/2024-10-22/cia_factbook.csv')

Visualization Parameters

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

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

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

showtext_auto()

# Background Colour
bg_col <- "white"

# Colour for the text (highlighted)
text_hil <- "#00778BFF" 

# Colour for text
text_col <- "#211747FF" 

# Define Base Text Size
bts <- 90 

# Caption stuff for the plot
sysfonts::font_add(
  family = "Font Awesome 6 Brands",
  regular = here::here("docs", "Font Awesome 6 Brands-Regular-400.otf")
)
github <- "&#xf09b"
github_username <- "aditya-dahiya"
xtwitter <- "&#xe61b"
xtwitter_username <- "@adityadahiyaias"
social_caption_1 <- glue::glue("<span style='font-family:\"Font Awesome 6 Brands\";'>{github};</span> <span style='color: {text_hil}'>{github_username}  </span>")
social_caption_2 <- glue::glue("<span style='font-family:\"Font Awesome 6 Brands\";'>{xtwitter};</span> <span style='color: {text_hil}'>{xtwitter_username}</span>")

plot_title <- "A Cartogram of the countries' population\n and Population Density"

plot_caption <- paste0(
  "**Data:** CIA World Factbook, {openintro}", 
  " |  **Code:** ", 
  social_caption_1, 
  " |  **Graphics:** ", 
  social_caption_2
  )

subtitle_text <- "Countries resized to reflect their population, with vibrant shades depicting population density (persons per square kilometer) -- revealing the dominance of Asia and Africa."
plot_subtitle <- str_wrap(subtitle_text, width = 95)
plot_subtitle |> str_view()

rm(github, github_username, xtwitter, 
   xtwitter_username, social_caption_1, 
   social_caption_2)

Exploratory Data Analysis and Wrangling

Code
# Get world map data
world_map <- rnaturalearth::ne_countries(scale = "medium") |> 
  select(name, geometry, iso_a3, pop_est) |> 
  group_by(name) |> 
  slice_max(order_by = pop_est, n = 1) |> 
  ungroup()


df1 <- cia_factbook |> 
  mutate(
    iso_a3 = countrycode::countrycode(
      country,
      origin = "country.name",
      destination = "iso3c"
    )
  ) |> 
  select(country, iso_a3, population, area) |> 
  drop_na() |> 
  mutate(pop_density = population / area)

plotdf <- world_map |> 
  left_join(df1) |> 
  st_transform(3857) |> 
  cartogram_cont(
    weight = "population"
  )

# Other types of cartograms
# 
# plotdf2 <- world_map |> 
#   left_join(df1) |> 
#   st_transform(3857) |> 
#   cartogram_ncont(
#     weight = "population"
#   )
# 
# plotdf3 <- world_map |> 
#   left_join(df1) |> 
#   st_transform(3857) |>
#   filter(!is.na(population)) |> 
#   cartogram_dorling(
#     weight = "population"
#   )
# 
# plotdf2 |> 
#   ggplot() +
#   geom_sf()
# 
# plotdf3 |> 
#   ggplot() +
#   geom_sf() +
#   geom_sf_text(aes(label = name, size = population)) +
#   coord_sf(crs = 3857)

The Base Plot (Kahle and Wickham 2013)

Code
g <- plotdf |> 
  arrange(desc(area)) |> 
  ggplot() +
  geom_sf(
    mapping = aes(
      fill = pop_density
    ),
    colour = bg_col,
    linewidth = 0.5
  ) +
  geom_sf_text(
    mapping = aes(
      label = name,
      size = population
    ),
    family = "body_font",
    check_overlap = TRUE
  ) +
  paletteer::scale_fill_paletteer_c(
    "pals::kovesi.isoluminant_cgo_80_c38",
    limits = c(0, 500),
    oob = scales::squish
  ) +
  scale_size_continuous(
    range = c(bts / 20, bts)
  ) +
  guides(
    size = "none",
    fill = guide_colourbar(
      title = "Population Density (in persons per sq. km.)",
      direction = "horizontal"
    )
  ) +
  labs(
    title = plot_title,
    subtitle = plot_subtitle,
    caption = plot_caption
  ) +
  ggthemes::theme_map(
    base_size = bts,
    base_family = "body_font"
  ) +
  theme(
    
    # Overall
    plot.margin = margin(10,-25,10,-25, "mm"),
    plot.title.position = "plot",
    text = element_text(
      colour = text_col,
      family = "body_font",
      lineheight = 0.35
    ),
    # Legend
    legend.position = "inside",
    legend.position.inside = c(0.5, 0),
    legend.justification = c(0.5, 0.5),
    legend.direction = "horizontal",
    legend.title.position = "top",
    legend.title = element_text(
      margin = margin(0,0,3,0, "mm"),
      size = 1.5 * bts,
      hjust = 0.5
    ),
    legend.text = element_text(
      margin = margin(2,0,0,0, "mm"),
      size = 1.2 * bts
    ),
    legend.key.height = unit(5, "mm"),
    legend.key.width = unit(60, "mm"),
    legend.background = element_rect(
      fill = "transparent",
      colour = "transparent"
    ),
    
    # Labels
    plot.title = element_text(
      family = "title_font",
      size = 2.5 * bts,
      hjust = 0.5,
      margin = margin(20,0,0,0, "mm"),
      colour = text_hil
    ),
    plot.subtitle = element_text(
      margin = margin(15,0,-10,0, "mm"),
      hjust = 0.5,
      lineheight = 0.25,
      size = 1.7 * bts
    ),
    plot.caption = element_textbox(
      margin = margin(50,0,10,0, "mm"),
      family = "caption_font",
      hjust = 0.5,
      size = 0.8 * bts,
      colour = text_hil
    )
  )

ggsave(
  filename = here::here("data_vizs", 
                        "tidy_cia_factbook.png"),
  plot = g,
  width = 600, 
  height = 600,
  units = "mm",
  bg = "white"
)

Add-on maps, insets and annotations

Compiling Plots with {patchwork}(Pedersen 2024)

Code
g_full <- g +
  
  # Add inset to the plot
  inset_element(
    p = g_month, 
    left = 0, 
    right = 0.2,
    bottom = 0,
    top = 0.5, 
    align_to = "panel"
  ) +
  
  # Basix Plot Annotations
  plot_annotation(
    theme = theme(
      plot.background = element_rect(
        fill = "transparent", 
        colour = "transparent", 
        linewidth = 0
      ),
      panel.background = element_rect(
        fill = "transparent", 
        colour = "transparent", 
        linewidth = 0
      )
    )
  )


ggsave(
  filename = here::here("data_vizs", 
                        "tidy_cia_factbook.png"),
  plot = g_full,
  width = 400, 
  height = 400,
  units = "mm",
  bg = "#99b3cc"
)

Savings the graphics

Code
# Saving a thumbnail

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

Session Info

Code
# Data Import and Wrangling Tools
library(tidyverse)            # All things tidy
library(here)                 # Root Directory Management

# 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(patchwork)            # Combining plots
library(ggmap)                # To get background map tiles

sessioninfo::session_info()$packages |> 
  as_tibble() |> 
  select(package, 
         version = loadedversion, 
         date, source) |> 
  arrange(package) |> 
  filter(package %in% .packages()) |> 
  janitor::clean_names(
    case = "title"
  ) |> 
  gt::gt() |> 
  gt::opt_interactive(
    use_search = TRUE
  ) |> 
  gtExtras::gt_theme_espn()
Table 1: R Packages and their versions used in the creation of this page and graphics

References

Kahle, David, and Hadley Wickham. 2013. “Ggmap: Spatial Visualization with Ggplot2” 5. https://journal.r-project.org/archive/2013-1/kahle-wickham.pdf.
Pedersen, Thomas Lin. 2024. “Patchwork: The Composer of Plots.” https://CRAN.R-project.org/package=patchwork.