WHO’s Global Health Expenditure Database

WHO’s Global Health Expenditure Database Data, Insights and Analysis

Public Health
{gt}
Author

Aditya Dahiya

Published

August 14, 2024

The data originates from the Global Health Expenditure Database (GHED) managed by the World Health Organization (WHO). GHED offers a comprehensive and internationally comparable collection of health expenditure data, covering over 190 countries. This database is pivotal for understanding global health financing trends and is instrumental in supporting evidence-based policy-making, particularly in the pursuit of universal health coverage (UHC) and enhancing transparency within health systems. The data within GHED is meticulously structured following the System of Health Accounts 2011 (SHA 2011), ensuring uniformity in tracking health expenditures across different nations. This standardized system enables the systematic monitoring of resource flows through health systems, from funding sources to final consumption in various health care functions.

For further details on the data and methodology, explore the Global Health Expenditure Database and additional resources available through the WHO Global Health Observatory.

Basic Code to fetch data, and analyze it

Code
# Data Import and Wrangling Tools
library(tidyverse)            # All things tidy
# 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)           # To lighten and darken colours

rawdf1 <- readxl::read_xlsx(
  path = here::here("data", "GHED_data.xlsx"),
  sheet = "Data"
  )

codes_df <- readxl::read_xlsx(
  path = here::here("data", "GHED_data.xlsx"),
  sheet = "Codebook"
  )

Common Visualizations’ Parameters

Code
# Font for plot text
font_add_google("News Cycle",
  family = "body_font"
) 

showtext_auto()

text_hil <- "grey30"

# 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:** Global Health Expenditure Database, WHO  |  ",
  "**Code:** ", 
  social_caption_1, 
  " |  **Graphics:** ", 
  social_caption_2
  )

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

The Figure 1 shows the Current Health Expenditure as a percentage of country’s GDP in some Asian Countries, with a focus on India.

Code
# Font for plot text
font_add_google("News Cycle",
  family = "body_font"
) 

showtext_auto()

text_hil <- "grey30"

# 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:** Global Health Expenditure Database, WHO  |  ",
  "**Code:** ", 
  social_caption_1, 
  " |  **Graphics:** ", 
  social_caption_2
  )

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

selected_countries <- c(
  "IND", "CHN", "THA", "BGD", "PAK", "IDN", "LKA"
  )


df1 <- rawdf1 |> 
  filter(code %in% selected_countries) |> 
  select(
    country, code, year, income,
    che_gdp
  )

g <- df1 |> 
  ggplot(
    mapping = aes(
      x = year,
      y = che_gdp,
      colour = country,
      group = country,
      label = country,
      linewidth = code == "IND",
      alpha = code == "IND"
    )
  ) + 
  geom_line() +
  geom_point(
    mapping = aes(size = code == "IND"),
    pch = 21,
    fill = "white",
    alpha = 1
  ) +
  geom_text(
    data = df1 |> filter(year == 2021),
    mapping = aes(
      x = 2021.3
    ),
    hjust = 0,
    alpha = 0.95,
    family = "body_font",
    size = 18,
    fontface = "bold"
  ) +
  scale_x_continuous(expand = expansion(0)) +
  coord_fixed(
    clip = "off",
    ratio = 2.5
  ) +
  scale_linewidth_manual(values = c(0.5, 1.5)) +
  scale_alpha_manual(values = c(0.6, 0.9)) +
  paletteer::scale_colour_paletteer_d("MetBrewer::Austria") + 
  # scale_colour_manual(
  #   values = c("grey50", "darkorange")
  # ) +
  scale_size_manual(
    values = c(2, 6)
  ) +
  labs( 
    title = "Current Health Expenditure (CHE) as a % of Gross Domestic Product (GDP)",
    x = "Year",
    y = "Percentage"
  ) +
  theme_classic(
    base_family = "body_font",
    base_size = 40
  ) +
  theme(
    line = element_line(
      linetype = 1, 
      colour = "grey30",
      linewidth = 0.5
    ),
    text = element_text(
      colour = "grey30",
      margin = margin(0,0,0,0, "mm")
    ),
    axis.line = element_line(
      arrow = arrow(length = unit(5, "mm")),
      colour = "grey30"
    ),
    legend.position = "none",
    plot.margin = margin(5,30,5,5, "mm"),
    plot.title = element_text(
      size = 80,
      hjust = 0.5
    )
  )

ggsave(
  plot = g,
  filename = here::here("docs", "fig_who_ghed_1.png"),
  height = unit(19.05 / 3, "cm"),
  width = unit(33.867 / 3, "cm"),
  bg = "transparent"
)

library(magick)
# Saving a thumbnail for the webpage
image_read(here::here("docs", "fig_who_ghed_1.png")) |> 
  image_resize(geometry = "400") |> 
  image_write(here::here("projects", "who_ghed_thumbnail.png"))
Figure 1: Current Health Expenditure (as a percentage of GDP) in various Asian Countries (with a focus on India)

The Figure 2 shows the Domestic Government Health Expenditure as a percentage of GDP.

Code
selected_countries <- c(
  "IND", "CHN", "THA", "BGD", "PAK", "IDN", "LKA"
  )

df2 <- rawdf1 |> 
  filter(code %in% selected_countries) |> 
  select(
    "country",
    "code",
    "region",
    "income",
    "year",
    "gghed_gdp"
  )
  
g <- df2 |> 
  ggplot(
    mapping = aes(
      x = year,
      y = gghed_gdp,
      colour = country,
      group = country,
      label = country,
      linewidth = code == "IND",
      alpha = code == "IND"
    )
  ) + 
  geom_line() +
  geom_point(
    mapping = aes(size = code == "IND"),
    pch = 21,
    fill = "white",
    alpha = 1
  ) +
  geom_text(
    data = df2 |> filter(year == 2021),
    mapping = aes(
      x = 2021.3
    ),
    hjust = 0,
    alpha = 0.95,
    family = "body_font",
    size = 18,
    fontface = "bold"
  ) +
  scale_x_continuous(expand = expansion(0)) +
  scale_linewidth_manual(values = c(0.5, 1.5)) +
  scale_alpha_manual(values = c(0.6, 0.9)) +
  paletteer::scale_colour_paletteer_d("MetBrewer::Austria") + 
  coord_cartesian(
    clip = "off"
  ) +
  scale_size_manual(
    values = c(2, 6)
  ) +
  labs( 
    title = "Domestic General Government Health Expenditure (GGHE-D)\nas % Gross Domestic Product (GDP)",
    x = "Year",
    y = "Percentage",
    caption = plot_caption
  ) +
  theme_classic(
    base_family = "body_font",
    base_size = 40
  ) +
  theme(
    line = element_line(
      linetype = 1, 
      colour = "grey30",
      linewidth = 0.5
    ),
    text = element_text(
      colour = "grey30",
      margin = margin(0,0,0,0, "mm"),
      lineheight = 0.4
    ),
    axis.line = element_line(
      arrow = arrow(length = unit(5, "mm")),
      colour = "grey30"
    ),
    legend.position = "none",
    plot.margin = margin(5,30,5,5, "mm"),
    plot.title = element_text(
      size = 80,
      hjust = 0.5
    ),
    plot.caption = element_textbox(
      hjust = 0,
      margin = margin(0,0,0,0, "mm"),
      size = 15
    )
  )

ggsave(
  plot = g,
  filename = here::here("docs", "fig_who_ghed_2.png"),
  height = unit(19.05 / 3, "cm"),
  width = unit(33.867 / 3, "cm"),
  bg = "transparent"
)
Figure 2: Domestic General Government Health Expenditure (GGHE-D) as % Gross Domestic Product (GDP) for selected countries in Asia, with focus on India.

The Figure 3 compares the Components of Current Health Expenditure in 9 countries.

Code
selected_countries <- c(
  "BGD", "PAK", "LKA",
  "IND", "CHN", "IDN",  
  "THA", "USA", "GBR"
  )

strip_labels_df <- rawdf1 |> 
  filter(code %in% selected_countries) |> 
  distinct(country, code) |> 
  mutate(code = fct(code, levels = selected_countries)) |> 
  arrange(code) |> 
  mutate(
    country = if_else(
      code == "GBR",
      "United Kingdom (Britain)",
      country
    )
  )

strip_labels <- strip_labels_df$country
names(strip_labels) <- strip_labels_df$code

che_components <- names(rawdf1)[16:20]

ind_levels <- c(
  "ext_che", 
  "gghed_che", 
  "pvtd_che", "vpp_che" , 
  "oops_che"
  )

colour_labels <- codes_df |> 
  filter(`variable code` %in% ind_levels) |> 
  mutate(code = fct(`variable code`, levels = ind_levels)) |> 
  arrange(code) |> 
  pull(`variable name`)

mypal <- c(
  "#999999FF",
  "#39B185FF",
  "#F6EDBDFF", "#EDBB8AFF",
  "#FF3200FF"
)

bts = 60

g3 <- rawdf1 |> 
  
  # Data Wrangling
  select(country, code, year, all_of(che_components)) |>
  filter(
    code %in% selected_countries
  ) |> 
  mutate(
    pvtd_che = pvtd_che - oops_che - vpp_che,
    code = fct(code, levels = selected_countries)
  ) |> 
  pivot_longer(
    cols = all_of(che_components),
    names_to = "indicator",
    values_to = "value"
  ) |>
  mutate(
    indicator = fct(indicator, levels = ind_levels)
  ) |> 
  
  # Starting the Plot
  ggplot(
    mapping = aes(
      x = year, 
      y = value, 
      fill = indicator
    )
  ) +
  geom_area(
    position = "fill",
    colour = "transparent",
    linewidth = 0.3
  ) +
  
  # Scales and Coordinates
  scale_fill_manual(
    values = mypal,
    labels = str_wrap(colour_labels, 40)
  ) +
  scale_x_continuous(expand = expansion(0)) +
  scale_y_continuous(
    expand = expansion(0),
    labels = scales::label_percent()
  ) +
  coord_cartesian(clip = "off") +
  facet_wrap(~ code, labeller = as_labeller(strip_labels)) +
  
  # Labels and Themes
  labs(
    title = "The Current Health Expenditure, and its components (2000-2021)",
    subtitle = glue::glue(
      "The <b style = 'color:{mypal[5]}'>Out-of-pocket Payments</b> cause impoverishment, and still constitute a large share of health expenditure in developing economies.<br><b style = 'color:{mypal[2]}'>Government Health Expenditure</b> is the most equitable, and can resolve the issues associated with Out-of-Pocket Payments."
    ),
    caption = plot_caption,
    x = NULL,
    y = NULL,
    colour = NULL
  ) +
  theme_minimal(
    base_size = 2 * bts,
    base_family = "body_font" 
  ) +
  theme(
    text = element_text(
      colour = text_hil,
      lineheight = 0.3,
      margin = margin(0,0,0,0, "mm")
    ),
    panel.grid = element_blank(),
    legend.position = "right",
    plot.title.position = "plot",
    plot.title = element_text(
      size = 4 * bts,
      face = "bold",
      margin = margin(5,0,5,10, "mm")
    ),
    plot.subtitle = element_textbox(
      lineheight = 0.4,
      size = 2 * bts,
      margin = margin(5,0,10,10, "mm")
    ),
    plot.caption = element_textbox(
      hjust = 0,
      size = bts,
      margin = margin(5,0,-10, -5, "mm")
    ),
    strip.text = element_text(
      size = 2 * bts,
      face = "bold",
      colour = text_hil,
      margin = margin(0,0,5,0, "mm")
    ),
    strip.background = element_rect(
      fill = "transparent",
      colour = "transparent"
    ),
    panel.spacing.x = unit(20, "mm"),
    panel.spacing.y = unit(10, "mm"),
    legend.title = element_blank(),
    legend.key.spacing.y = unit(20, "mm"),
    legend.key.height = unit(40, "mm"),
    legend.key.width = unit(40, "mm"),
    legend.text = element_text(
      size = 1.5 * bts,
      margin = margin(0,0,0,5, "mm")
    ),
    axis.ticks.length = unit(0, "mm"),
    axis.text = element_text(
      margin = margin(0,0,0,0, "mm"),
      size = bts * 1.2
    ),
    legend.margin = margin(0,0,0,0, "mm")
  )

ggsave(
  plot = g3,
  filename = here::here("docs", "fig_who_ghed_3.png"),
  height = unit(19.05, "cm"),
  width = unit(33.867, "cm"),
  bg = "transparent"
)
Figure 3: The Components in Current Health expenditure, in selected 9 countries, to show importance of Govt. Health Expenditure in reducing Out-of-Pocket Payments
Code
selected_countries <- c(
  "BGD", "PAK", "LKA",
  "IND", "CHN", "IDN",  
  "THA", "USA", "GBR"
  )

misdf <- rawdf1  |> 
  summarise(across(everything(), ~ mean(!is.na(.)))) |> 
  pivot_longer(
    everything(), 
    names_to = "column", 
    values_to = "percentage_non_missing"
  ) |> 
  arrange(desc(percentage_non_missing)) |> 
  filter(percentage_non_missing > 0.5) |> 
  left_join(
    codes_df |> select(`variable code`, `variable name`),
    by = join_by(column == `variable code`)
  )

dflabels <- misdf |> 
  filter(column %in% c("hf1_che", "hf3_che")) |> 
  janitor::clean_names()

g <- rawdf1 |> 
  # filter(code %in% selected_countries) |> 
  select(
    country, year, income, 
    hf1_che, hf3_che
  ) |> 
  # filter(year == 2000) |> 
  ggplot(
    mapping = aes(
      x = hf1_che,
      y = hf3_che,
      colour = income
    )
  ) +
  geom_point(
    size = 1.2,
    alpha = 0.9
  ) +
  annotate(
    geom = "text",
    label = "Year: {frame_time}",
    x = 80,
    y = 100,
    hjust = 1, 
    vjut = 1
  ) +
  scale_y_continuous(
    limits = c(0, 100)
  ) +
  scale_x_continuous(
    limits = c(0, 100)
  ) +
  labs(
    x = dflabels$variable_name[1],
    y = dflabels$variable_name[2],
    colour = "Income Levels"
  ) +
  coord_fixed(
    clip = "off"
  ) +
  theme_minimal() +
  theme(
    legend.position = c(1, 0.7),
    legend.justification = c(1,1)
  )

library(gganimate)

g_anim <- g +
  transition_time(year) +
  ease_aes("linear")

animate(
  plot = g_anim, 
  fps = 5,
  duration = 10
)