Shifting Health Burdens: The Fall of Infectious Diseases

A donut chart, with an inset pie chart on the main causes of DALYs, coloured by different categories, and different causes within each category distinguished by opacity. Labels show percentage contribution and the names of causes.

Our World in Data
Public Health
A4 Size Viz
{donutsk}
Author

Aditya Dahiya

Published

August 5, 2024

The dataset from Our World in Data provides comprehensive information on Disability Adjusted Life Years (DALYs) for various health conditions, including communicable, maternal, neonatal, nutritional diseases, injuries, and non-communicable diseases (NCDs). The data is sourced from the IHME’s Global Burden of Disease (GBD) study, which offers a detailed assessment of global health trends, encompassing death and DALY counts and rates for 371 diseases and injuries. The dataset, which spans from 1990 to 2021, was last updated on May 20, 2024, with the next update expected in May 2028. Detailed data can be retrieved from the Global Burden of Disease’s results tool here.

Figure 1: This graphic features four donut charts displaying the proportion of total global Disability Adjusted Life Years (DALYs) attributed to five major cause categories in the years 1990, 2000, 2010, and 2020. Each chart illustrates the evolving distribution of health burdens over time, with different sections representing distinct categories of diseases and conditions.

How I made these graphics?

Getting the data

Code
# Data Import and Wrangling Tools
library(tidyverse)            # All things tidy
library(owidR)                # Get data from Our World in R

# Final plot tools
library(scales)               # Nice Scales for ggplot2
library(fontawesome)          # Icons display in ggplot2
library(ggtext)               # Markdown text support
library(showtext)             # Display fonts in ggplot2
library(colorspace)           # To lighten and darken colours
library(patchwork)            # Combining plots

library(donutsk)              # Pie & Donut Charts with labels

# search1 <- owidR::owid_search("burden of disease")

df1 <- owid("burden-of-disease-by-cause")

# popdf <- owid("population-with-un-projections")

Visualization Parameters

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

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

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

showtext_auto()

# Colour Palette
mypal <- c("grey40", "#FC1414FF", "grey60", "grey50", "grey30")
# Background Colour
bg_col <- "white"
text_col <- "grey20"
text_hil <- "grey30"

# Base Text Size
bts <- 80

plot_title <- "Global Health Progress :\nDrop in Infectious Disease DALYs"

plot_subtitle <- str_wrap("There is a significant global decrease in the share of infectious diseases in total DALYs, dropping from 30.6% in 1990 to 19.3% in 2020. Notably, enteric infections have seen the largest decline, falling from 8.4% to 2.8% over the same period, reflecting improvements in global health and sanitation.", 65)
str_view(plot_subtitle)

# 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_caption <- paste0(
  "**Data:** IHME - Global Burden of Disease (GBD) Study  |  ",
  "**Code:** ", 
  social_caption_1, 
  " |  **Graphics:** ", 
  social_caption_2
  )
rm(github, github_username, xtwitter, 
   xtwitter_username, social_caption_1, social_caption_2)

Data Wrangling

Code
df2 <- df1 |> 
  as_tibble() |> 
  pivot_longer(
    cols = -c(year, entity, code),
    names_to = "indicator",
    values_to = "value"
  ) |> 
  mutate(
    indicator = str_remove(
      indicator,
      "Total number of DALYs from "
    ),
    indicator = str_remove(
      indicator,
      "\n"
    )
  ) |>
  mutate(
    indicator = str_to_title(
      indicator
    ),
    indicator = str_replace(
      indicator,
      "Hiv/Aids",
      "HIV / AIDS"
    ),
    indicator = str_replace_all(
      indicator,
      "And",
      "and"
    )
  )

plotdf <- df2 |> 
  # filter(year %in% c(1990, 2000, 2010, 2020)) |> 
  filter(entity == "World") |> 
  mutate(
    indicator = fct(indicator),
    indicator_group = fct_collapse(
      indicator,
    "Lifestyle Disorders" = c("Cardiovascular Diseases", 
                              "Diabetes and Kidney Diseases", 
                              "Digestive Diseases", "Neoplasms", 
                              "Chronic Respiratory Diseases"),
    "Infectious Diseases" = c("Other Infectious Diseases", 
                              "Neglected Tropical Diseases and Malaria", 
                              "Enteric Infections", 
                              "HIV / AIDS and Sexually Transmitted Infections", 
                              "Respiratory Infections and Tuberculosis"),
    "Violence and Injuries" = c("Transport Injuries", 
                                "Self-Harm", 
                                "Interpersonal Violence",
                                "Unintentional Injuries", 
                                "Conflict and Terrorism", 
                                "Exposure To Forces Of Nature"),
    "Mental Health Disorders" = c("Neurological Disorders",
                                  "Mental Disorders", 
                                  "Substance Use Disorders"),
    "Others" = c("Musculoskeletal Disorders", 
                 "Maternal Disorders", 
                 "Nutritional Deficiencies", 
                 "Neonatal Disorders", 
                 "Skin and Subcutaneous Diseases", 
                 "Other Non-Communicable Diseases")
  )) |> 
  select(entity, year, indicator_group, indicator, value) |> 
  group_by(year) |> 
  donutsk::packing(value = value, level = indicator_group) |> 
  group_by(year) |> 
  mutate(perc_outer = 100 * value / sum(value)) |> 
  group_by(year, indicator_group) |> 
  mutate(perc_inner = sum(perc_outer)) |> 
  ungroup() |> 
  mutate(
    highlight_int = (indicator_group == "Infectious Diseases"),
    highlight_ext = (indicator_group == "Infectious Diseases")
  )

labelsdf <- plotdf |> 
  group_by(year) |> 
  distinct(indicator_group, perc_inner) |> 
  mutate(
    ymax = cumsum(perc_inner),
    ymin = ymax - perc_inner,
    x_var = case_when(
      indicator_group == "Violence and Injuries" ~ 1.4,
      indicator_group == "Mental Health Disorders" ~ 1.4,
      .default = 1.3
    )
  ) |> 
  select(-perc_inner) |> 
  pivot_longer(
    cols = c(ymax, ymin),
    values_to = "y_var",
    names_to = NULL
  ) |> 
  mutate(
    y_var = y_var / 100
  )

Visualization

Code
bts = 40

g <- plotdf |>
  filter(year %in% c(1990, 2000, 2010, 2020)) |> 
  ggplot(
    mapping = aes(
      value = value,
      fill = indicator_group
    )
  ) +

  # Internal donut represents major categories of causes of DALYs
  geom_donut_int(
    mapping = aes(
     highlight = highlight_ext
    ),
    r_int = 0, 
    col = bg_col, 
    linewidth = 0.5,
    hl_shift = 0.4,
    hl_col = "#980000FF"
  ) +
  
  # External donut represents detailed individual causes
  geom_donut_ext(
    mapping = aes(
      opacity = indicator,
      highlight = highlight_ext
    ), 
    col = bg_col, 
    linewidth = 0.3, 
    show.legend = F,
    hl_shift = 0.2,
    hl_col = "#980000FF"
  ) +
  
  # Text annotations for internal donut
  geom_text_int(
    mapping = aes(
      label = paste0(
        str_wrap(as.character(indicator_group), 15),
        "\n",
        round(perc_inner, 1),
        " %"
        )
      ),
    size = bts / 4,
    lineheight = 0.25,
    colour = "white",
    hjust = 0.5,
    r = 0.65,
    show.legend = F,
    family = "body_font",
    fontface = "bold"
  ) +
  
  # Label annotations for internal donut
  geom_text_ext(
    mapping = aes(
      colour = indicator_group, 
      label = paste0(
        str_wrap(indicator, 15), " (",
        round(perc_outer, 1), 
        " %)"
        ),
      size = highlight_ext
      ),
    
    hjust = "outward",
    vjust = "outward",
    layout = circle(thinner = TRUE), 
    show.legend = F,
    lineheight = 0.25,
    family = "caption_font"
  ) +
  scale_size_manual(
    values = c(bts/6, bts/4)
  ) +
  # Link label annotations to outer donut chart
  geom_pin(
    mapping = aes(colour = indicator_group),
    size = 1, 
    linewidth = .25, 
    show.legend = F, 
    cut = 0, 
    layout = circle(thinner = TRUE), 
    r = 1.75
  ) +
  
  facet_wrap(~ year, ncol = 2, nrow = 2, dir = "h") +
  
  # Scales and Coordinates
  scale_colour_manual(values = mypal) +
  scale_fill_manual(values = mypal) +
  
  coord_radial(
    theta = "y", 
    expand = F, 
    clip = "off"
    ) +
  xlim(0, 3) +
  
  # Labels and Themes
  labs(
    title = plot_title,
    caption = plot_caption,
    subtitle = plot_subtitle
  ) +
  
  theme_void(
    base_family = "body_font",
    base_size = bts
  ) +
  theme(
    legend.position = "none", 
    plot.title.position = "plot",
    plot.title = element_text(
      colour = text_hil,
      family = "title_font",
      size = 6 * bts,
      hjust = 0.5,
      margin = margin(10,0,5,0, "mm"),
      lineheight = 0.3
    ),
    plot.subtitle = element_text(
      colour = text_hil,
      family = "title_font",
      size = 2.5 * bts,
      hjust = 0,
      margin = margin(0,0,0,10, "mm"),
      lineheight = 0.3
    ),
    plot.caption = element_textbox(
      colour = text_hil,
      family = "caption_font",
      hjust = 0.5,
      margin = margin(-10,0,0,0, "mm")
    ),
    strip.text = element_text(
      size = 5 * bts,
      colour = text_hil, 
      family = "title_font",
      margin = margin(10,0,-30,0, "mm"),
      face = "bold"
    ),
    plot.margin = margin(10,-15,5,-15, "mm"),
    panel.spacing.x = unit(-70, "mm"),
    panel.spacing.y = unit(-20, "mm"),
    panel.border = element_blank(),
    panel.background = element_rect(
      fill = "transparent",
      colour = "transparent"
    )
  )

Add insets and QR Code

Code
# QR Code for the plot
url_graphics <- paste0(
  "https://aditya-dahiya.github.io/projects_presentations/projects/",
  # The file name of the current .qmd file
  "owid_daly_causes_donut_highlight",
  ".qmd"
)
# remotes::install_github('coolbutuseless/ggqr')
# library(ggqr)
plot_qr <- ggplot(
  data = NULL, 
  aes(x = 0, y = 0, label = url_graphics)
  ) + 
  ggqr::geom_qr(
    colour = text_hil, 
    fill = bg_col,
    size = 1.5
    ) +
  # labs(caption = "Scan for the Interactive Version") +
  coord_fixed() +
  theme_void() +
  theme(plot.background = element_rect(
    fill = "transparent", 
    colour = "transparent"
    )
  )

plot_data <- ggplot() +
  annotate(
    geom = "text",
    x = 0, y = 0,
    label = str_wrap("About the Data: The dataset, derived from the Global Burden of Disease study and processed by Our World in Data, encompasses global health data from 1990 to 2020. It provides detailed information on the share of different disease categories in total Disability Adjusted Life Years (DALYs), allowing for analysis of trends and changes in global health burdens.", 50),
    family = "caption_font",
    colour = text_hil,
    lineheight = 0.3, 
    size = bts / 4,
    hjust = 1,
    vjust = 1
  ) +
  theme_void()

g_full <- g +
  inset_element(
    p = plot_qr,
    left = 0.88, right = 0.98,
    top = 1.18, bottom = 1,
    align_to = "panel",
    clip = FALSE
  ) +
  inset_element(
    p = plot_data,
    left = 0.75, right = 1.2,
    top = 1.1, bottom = 0.95,
    align_to = "panel",
    clip = FALSE
  ) +
  plot_annotation(
    theme = theme(
      plot.background = element_rect(
        fill = "transparent", colour = "transparent"
      ),
      panel.background = element_rect(
        fill = "transparent", colour = "transparent"
      )
    )
  )

Save a thumbnail

Code
ggsave(
  filename = here::here("data_vizs", "a4_owid_daly_causes_donut_highlight.png"),
  plot = g_full,
  height = 297 * 2,
  width = 210 * 2,
  units = "mm",
  bg = bg_col
)

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

Attempt 2: for a Powerpoint slide (landscape layout) shown in Figure 2

Code
bts = 40

plot_title <- "Global Health Progress: Drop in Infectious Disease DALYs"

plot_subtitle <- str_wrap("There is a significant global decrease in the share of infectious diseases in total DALYs, dropping from 30.6% in 1990 to 19.3% in 2020. Notably, enteric infections have seen the largest decline, falling from 8.4% to 2.8% over the same period, reflecting improvements in global health and sanitation.", 120)
str_view(plot_subtitle)

g <- plotdf |>
  filter(year %in% c(1990, 2000, 2010, 2020)) |> 
  ggplot(
    mapping = aes(
      value = value,
      fill = indicator_group
    )
  ) +

  # Internal donut represents major categories of causes of DALYs
  geom_donut_int(
    mapping = aes(
     highlight = highlight_ext
    ),
    r_int = 0, 
    col = bg_col, 
    linewidth = 0.5,
    hl_shift = 0.4,
    hl_col = "#980000FF"
  ) +
  
  # External donut represents detailed individual causes
  geom_donut_ext(
    mapping = aes(
      opacity = indicator,
      highlight = highlight_ext
    ), 
    col = bg_col, 
    linewidth = 0.3, 
    show.legend = F,
    hl_shift = 0.2,
    hl_col = "#980000FF"
  ) +
  
  # Text annotations for internal donut
  geom_text_int(
    mapping = aes(
      label = paste0(
        str_wrap(as.character(indicator_group), 15),
        "\n",
        round(perc_inner, 1),
        " %"
        )
      ),
    size = bts / 3,
    lineheight = 0.25,
    colour = "white",
    hjust = 0.5,
    r = 0.65,
    show.legend = F,
    family = "body_font",
    fontface = "bold"
  ) +
  
  # Label annotations for internal donut
  geom_text_ext(
    mapping = aes(
      colour = indicator_group, 
      label = paste0(
        str_wrap(indicator, 15), " (",
        round(perc_outer, 1), 
        " %)"
        ),
      size = highlight_ext
      ),
    
    hjust = "outward",
    vjust = "outward",
    layout = circle(thinner = TRUE), 
    show.legend = F,
    lineheight = 0.25,
    family = "caption_font"
  ) +
  scale_size_manual(
    values = c(bts/5, bts/3)
  ) +
  # Link label annotations to outer donut chart
  geom_pin(
    mapping = aes(colour = indicator_group),
    size = 1, 
    linewidth = .25, 
    show.legend = F, 
    cut = 0, 
    layout = circle(thinner = TRUE), 
    r = 1.75
  ) +
  
  facet_wrap(~ year, ncol = 4, nrow = 1, dir = "h") +
  
  # Scales and Coordinates
  scale_colour_manual(values = mypal) +
  scale_fill_manual(values = mypal) +
  
  coord_radial(
    theta = "y", 
    expand = F, 
    clip = "off"
    ) +
  xlim(0, 3) +
  
  # Labels and Themes
  labs(
    title = plot_title,
    caption = plot_caption,
    subtitle = plot_subtitle
  ) +
  
  theme_void(
    base_family = "body_font",
    base_size = bts
  ) +
  theme(
    legend.position = "none", 
    plot.title.position = "plot",
    plot.title = element_text(
      colour = text_hil,
      family = "title_font",
      size = 7 * bts,
      hjust = 0.5,
      margin = margin(10,0,25,0, "mm"),
      lineheight = 0.3
    ),
    plot.subtitle = element_text(
      colour = text_hil,
      family = "title_font",
      size = 3.5 * bts,
      hjust = 0,
      margin = margin(0,0,0,50, "mm"),
      lineheight = 0.3
    ),
    plot.caption = element_textbox(
      colour = text_hil,
      family = "caption_font",
      hjust = 0.5,
      size = bts * 2,
      margin = margin(-10,0,0,0, "mm")
    ),
    strip.text = element_text(
      size = 5 * bts,
      colour = text_hil, 
      family = "title_font",
      margin = margin(10,0,-10,0, "mm"),
      face = "bold"
    ),
    plot.margin = margin(10,-25,5,-25, "mm"),
    panel.spacing.x = unit(-70, "mm"),
    panel.spacing.y = unit(-20, "mm"),
    panel.border = element_blank(),
    panel.background = element_rect(
      fill = "transparent",
      colour = "transparent"
    )
  )


ggsave(
  filename = here::here("data_vizs", "ppt_owid_daly_causes_donut_highlight.png"),
  plot = g,
  height = unit(19.05, "cm"),
  width = unit(33.867, "cm"),
  bg = bg_col
)
Figure 2: The declining share of infectious etiologies in glabal DALYs, as shown in a donut chart with infections highlighted in red.