Oxygen Dependency at the Summit: Top 8 Mountains

The Essential Role of Oxygen in Conquering Himalayan Giants: A closer look at the peaks where over half of climbers relied on supplemental oxygen to reach the summit.

#TidyTuesday
{ggpattern}
{magick}
Images
Author

Aditya Dahiya

Published

January 25, 2025

About the Data

The Himalayan Dataset is a rich repository documenting mountaineering expeditions in the Nepal Himalaya, sourced from the Himalayan Database. This database originates from the pioneering work of Elizabeth Hawley, a journalist who meticulously chronicled climbing history through records gathered from books, journals, and direct correspondence with climbers. Initially released as a CD-ROM booklet in 2004 by the American Alpine Club, it became an essential tool for the mountaineering community. The project was further institutionalized in 2017 by The Himalayan Database, a non-profit organization that launched Version 2, making the dataset freely available for download here.

This dataset provides comprehensive insights into Himalayan peaks, expeditions, and climbers, detailing variables such as geographic data, success rates, climbing routes, and the use of supplemental oxygen. This curated dataset is made available by Nicolas Foss, Ed.D., MS.

Figure 1: This horizontal bar chart displays the percentage of climbers who used supplemental oxygen while climbing eight Himalayan peaks where oxygen usage exceeded 50%. The x-axis represents the percentage of climbers using oxygen, while each bar corresponds to a specific peak, arranged from highest to lowest percentage. Mountain images within the bars visually represent each peak.

How I made this graphic?

Loading required libraries, data import & creating custom functions.

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

# 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(ggpattern)            # Image patterns in ggplot2 geoms
library(magick)               # Handling images
library(httr)                 # Downloading images from Google

exped_tidy <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/main/data/2025/2025-01-21/exped_tidy.csv') |>  janitor::clean_names()
  
peaks_tidy <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/main/data/2025/2025-01-21/peaks_tidy.csv') |>   janitor::clean_names()

Visualization Parameters

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

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

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

showtext_auto()

# A base Colour
bg_col <- "white"
seecolor::print_color(bg_col)

# Colour for highlighted text
text_hil <- "grey30"
seecolor::print_color(text_hil)

# Colour for the text
text_col <- "grey15"
seecolor::print_color(text_col)


# 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_caption <- paste0(
  "**Data:** Himalayan Database by Elizabeth Hawley", 
  " |  **Code:** ", 
  social_caption_1, 
  " |  **Graphics:** ", 
  social_caption_2
  )
rm(github, github_username, xtwitter, 
   xtwitter_username, social_caption_1, 
   social_caption_2)

# Add text to plot-------------------------------------------------
plot_title <- "Breathing Easy? Not on These Peaks!"

plot_subtitle <- "Everest leads the way as the peak with the highest percentage of climbers relying on supplemental oxygen. These eight towering giants demand Oxygen support from over half their climbers."

Exploratory Data Analysis and Wrangling

Code
plotdf <- exped_tidy |>
  group_by(peakid) |> 
  summarise(
    o2 = mean(o2used)
  ) |> 
  arrange(desc(o2)) |> 
  filter(o2 > 0.5) |> 
  left_join(
    peaks_tidy |> 
      select(peakid, pkname, location, heightm,
             region_factor)
  ) |> 
  mutate(id = row_number()) |> 
  relocate(id)

Get images of the mountains selected

Code
# Get a custom google search engine and API key
# Tutorial: https://developers.google.com/custom-search/v1/overview
# Tutorial 2: https://programmablesearchengine.google.com/

# From:https://developers.google.com/custom-search/v1/overview
# google_api_key <- "LOAD YOUR GOOGLE API KEY HERE"

# From: https://programmablesearchengine.google.com/controlpanel/all
# my_cx <- "GET YOUR CUSTOM SEARCH ENGINE ID HERE"

plotdf
# Load necessary packages
library(httr)
library(magick)

# Define function to download and save movie poster
download_icons <- function(i) {
  
  api_key <- google_api_key
  cx <- my_cx
  
  # Build the API request URL
  url <- paste0("https://www.googleapis.com/customsearch/v1?q=", 
                URLencode(paste0(plotdf$pkname[i], " mountain photo HD")), 
                "&cx=", cx, 
                "&searchType=image&key=", api_key)
  
  # Make the request
  response <- GET(url)
  result <- content(response, "parsed")
  
  # Get the URL of the first image result
  image_url <- result$items[[1]]$link
  
  im <- magick::image_read(image_url) |> 
    image_resize("x3000")
  
  # set background as white
  image_write(
    image = im,
    path = here::here("data_vizs",
                      paste0("temp_himalayas_", i,".png")),
    format = "png"
    )
}

for (i in 1:8) {
  download_icons(i)
}

The Base Plot

Code
g <- ggplot(
  data = plotdf,
    mapping = aes(
      x = o2, 
      y = reorder(peakid, o2)
    )
  ) +
  # geom_col() +
  geom_col_pattern(
    mapping = aes(
      pattern_filename = I(paste0("data_vizs/temp_himalayas_",
                                id, ".png"))
    ),
    pattern = "image",
    pattern_type = "tile",
    pattern_scale = -2,
    linewidth = 0.2,
    colour = text_col
  ) +
  geom_text(
    mapping = aes(
      x = -0.02,
      label = paste0(
        pkname,
        "\n(",
        heightm,
        " m)"
      )
    ),
    hjust = 1,
    vjust = 0.5, 
    lineheight = 0.3,
    colour = text_hil,
    family = "caption_font",
    size = bts / 2
  ) +
  geom_text(
    mapping = aes(
      label = paste0(round(100*o2, 1), " %")
    ),
    hjust = 0,
    vjust = 0.5, 
    nudge_x = 0.02,
    lineheight = 0.3,
    colour = text_hil,
    family = "caption_font",
    fontface = "bold",
    size = bts / 2
  ) +
  scale_x_continuous(
    labels = scales::label_percent(),
    expand = expansion(c(0.21, 0.1))
  ) +
  labs(
    title = plot_title,
    subtitle = str_wrap(plot_subtitle, 100),
    caption = plot_caption,
    x = "Percentage climbers that used Oxygen-support",
    y = NULL
  ) +
  coord_cartesian(clip = "off") +
  theme_minimal(
    base_family = "body_font",
    base_size = bts
  ) +
  theme(
    
    # Overall Plot
    plot.margin = margin(5,5,5,5, "mm"),
    plot.title.position = "plot",
    panel.grid = element_blank(),
    axis.ticks = element_blank(),
    axis.ticks.length = unit(0, "mm"),
    text = element_text(
      colour = text_col,
      margin = margin(0,0,0,0, "mm"),
      hjust = 0.5,
      vjust = 0.5,
      lineheight = 0.3
    ),
    
    # Axis Text
    axis.text = element_blank(),
    axis.title.y = element_blank(),
    axis.title.x = element_text(
      margin = margin(0,0,5,0, "mm")
    ),
    
    # Labels and Strip Text
    plot.title = element_text(
      colour = text_hil,
      margin = margin(5,0,5,0, "mm"),
      size = bts * 2.5,
      lineheight = 0.3,
      hjust = 0.5,
      family = "body_font"
    ),
    plot.subtitle = element_text(
      colour = text_hil,
      margin = margin(5,0,0,0, "mm"),
      size = bts * 0.9,
      hjust = 0.5,
      lineheight = 0.3,
      family = "body_font"
    ),
    plot.caption = element_textbox(
      family = "caption_font",
      margin = margin(0,0,5,0, "mm"),
      hjust = 0.5
    )
  )

ggsave(
  filename = here::here(
    "data_vizs",
    "tidy_himalayan_mountains.png"
  ),
  plot = g,
  width = 400,
  height = 500,
  units = "mm",
  bg = bg_col
)

Reduce filesize and Savings the thumbnail for the webpage

Code
# Saving a thumbnail

library(magick)
# Reducing Image Size - its 15 Mb plus
image_read(here::here("data_vizs", 
                      "tidy_himalayan_mountains.png")) |> 
  image_resize(geometry = "x2000") |> 
  image_write(
    here::here(
      "data_vizs", 
      "tidy_himalayan_mountains.png"
    )
  )

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

# Clean Up: Do no harm and leave the world an untouched place!
# Remove temporary image files
unlink(paste0("data_vizs/temp_himalayas_", 1:8, ".png"))

Session Info

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

# 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(ggpattern)            # Image patterns in ggplot2 geoms
library(magick)               # Handling images
library(httr)                 # Downloading images from Google

sessioninfo::session_info()$packages |> 
  as_tibble() |> 
  select(package, 
         version = loadedversion, 
         date, source) |> 
  arrange(package) |> 
  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