Radar Charts of Species Categories by National Park
Comparison of species distributions across U.S. national parks
#TidyTuesday
Author
Steven Ponce
Published
October 7, 2024
Steps to Create this Graphic
1. Load Packages & Setup
Code
## 1. LOAD PACKAGES & SETUP ----pacman::p_load( tidyverse, # Easily Install and Load the 'Tidyverse' ggtext, # Improved Text Rendering Support for 'ggplot2' showtext, # Using Fonts More Easily in R Graphs janitor, # Simple Tools for Examining and Cleaning Dirty Data skimr, # Compact and Flexible Summaries of Data scales, # Scale Functions for Visualization lubridate, # Make Dealing with Dates a Little Easier glue, # Interpreted String Literals fmsb, # Functions for Medical Statistics Book with some Demographic Data purrr, # Functional Programming Tools patchwork, # The Composer of Plots grid, # The Grid Graphics Package cowplot, # Streamlined Plot Theme and Plot Annotations for 'ggplot2' png, # Read and write PNG images here # A Simpler Way to Find Your Files) ### |- figure size ---- camcorder::gg_record(dir = here::here("temp_plots"),device ="png",width =10,height =10,units ="in",dpi =320)### |- resolution ----showtext_opts(dpi =320, regular.wt =300, bold.wt =800)
# Prepare data for radar plotsradar_data <- species_data |>count(park_name, category_name) |>pivot_wider(names_from = category_name,values_from = n,values_fill =0 )
5. Visualization Parameters
Code
### |- plot aesthetics ----bkg_col <- colorspace::lighten('#f7f5e9', 0.05) title_col <-"gray20"subtitle_col <-"gray20"caption_col <-"gray30"text_col <-"gray20"col_palette <- paletteer::paletteer_d("ButterflyColors::fountainea_ryphea")[c(1)] ### |- titles and caption ----# iconstt <-str_glue("#TidyTuesday: { 2024 } Week { 41 } • Source: NPSpecies - The National Park Service biodiversity database<br>")li <-str_glue("<span style='font-family:fa6-brands'></span>")gh <-str_glue("<span style='font-family:fa6-brands'></span>")mn <-str_glue("<span style='font-family:fa6-brands'></span>")# texttitle_text <-str_glue("Radar Charts of Species Categories by National Park")subtitle_text <-str_glue("Comparison of species distributions across U.S. national parks")caption_text <-str_glue("{tt} {li} stevenponce • {mn} @sponce1(graphic.social) {gh} poncest • #rstats #ggplot2")### |- fonts ----font_add("fa6-brands", "fonts/6.4.2/Font Awesome 6 Brands-Regular-400.otf")font_add_google("Oswald", regular.wt =400, family ="title")font_add_google("Merriweather Sans", regular.wt =400, family ="subtitle")font_add_google("Merriweather Sans", regular.wt =400, family ="text")font_add_google("Noto Sans", regular.wt =400, family ="caption")showtext_auto(enable =TRUE)### |- plot theme ----theme_set(theme_minimal(base_size =14, base_family ="text")) theme_update(plot.title.position ="plot",plot.caption.position ="plot",legend.position ='plot',plot.background =element_rect(fill = bkg_col, color = bkg_col),panel.background =element_rect(fill = bkg_col, color = bkg_col),plot.margin =margin(t =10, r =20, b =10, l =20),axis.title.x =element_text(margin =margin(10, 0, 0, 0), size =rel(1.1), color = text_col, family ="text", face ="bold", hjust =0.5),axis.title.y =element_blank(), axis.text.y =element_blank(),axis.text.x =element_text(color = text_col, family ="text", size =rel(0.9)),axis.ticks.x =element_line(color = text_col), )### |- plot function ----# Function to create radar chart and save as PNGcreate_and_save_radar_plot <-function(data, park_name) {# Define maximum and minimum values for the radar chart max_values <-rep(max(data), ncol(data)) min_values <-rep(0, ncol(data))# Combine the max, min, and park data to create the radar chart data frame plot_data <-as.data.frame(rbind(max_values, min_values, data))colnames(plot_data) <-names(data)rownames(plot_data) <-c("Max", "Min", park_name)# Define the file path to save the radar chart temp_path <-here("2024/Week_41/")if (!dir.exists(temp_path)) {dir.create(temp_path, recursive =TRUE) } file_path <-file.path(temp_path, paste0("radar_plot_", gsub(" ", "_", park_name), ".png"))# Close any open deviceswhile (!is.null(dev.list())) dev.off()# Create and save the radar chart as a PNGpng(filename = file_path, width =400, height =400) fmsb::radarchart(plot_data,axistype =1, # Axis type configurationtitle = park_name, # Title for the radar chartpcol = col_palette, # Line color for the polygonpfcol = scales::alpha(col_palette, 0.25), # Fill color for the polygon with transparencyplty =1, # Line type for the polygoncglcol = bkg_col, # Color of the grid linescglty =1, # Type of the grid linescglwd =0.8, # Width of the grid linesaxislabcol = bkg_col, # Color of the axis labelscex.axis =1.2, # Increase axis text sizecex.main =1.5# Increase title text size )dev.off()return(file_path)}
6. Plot
Code
### |- individual plots ----# Generate and save radar plots for each parkshowtext_auto(enable =FALSE)radar_plot_files <- radar_data |>split(radar_data$park_name) |>map_chr(~ { park_name <- .x$park_name[1] # Extract park name park_data <- .x |>select(-park_name) # Remove park name column from datacreate_and_save_radar_plot(park_data, park_name) # Create and save radar plot })# Load each saved radar plot as a raster image and convert to ggplotradar_plots <-map(radar_plot_files, ~ { img <-readPNG(.x) # Read the saved PNG fileggdraw() +draw_image(img) # Convert the image to a ggplot object })### |- combined plots ----showtext_auto(enable =TRUE)combined_plot <-wrap_plots(radar_plots, ncol =4) +plot_annotation(# Labstitle = title_text,subtitle = title_text,caption = caption_text,# Themetheme =theme(plot.title =element_text(size =rel(1.7),family ="title",face ="bold",color = title_col,lineheight =1.1,margin =margin(t =5, b =5) ),plot.subtitle =element_text(size =rel(1),family ="subtitle",color = subtitle_col,lineheight =1.1,margin =margin(t =5, b =5) ),plot.caption =element_markdown(size =rel(0.65),family ="caption",color = caption_col,lineheight =1.1,hjust =0.5,halign =1,margin =margin(t =5, b =5) ) ) )combined_plot
7. Save
Code
### |- plot image ---- library(ggplotify)# Convert patchwork plot to grob # There was some issues between cowplot and ggsaveplot_grob <-as.grob(combined_plot)# Save the plot again# Activate showtext manuallyshowtext_begin()# Save the plot as PNGpng(filename = here::here("data_visualizations/TidyTuesday/2024/tt_2024_41.png"),width =10, height =10, units ="in", res =320)grid.draw(plot_grob)dev.off()# Deactivate showtextshowtext_end()### |- plot thumbnail---- magick::image_read(here::here("data_visualizations/TidyTuesday/2024/tt_2024_41.png")) |> magick::image_resize(geometry ="400") |> magick::image_write(here::here("data_visualizations/TidyTuesday/2024/thumbnails/tt_2024_41.png"))
8. Session Info
Code
info <-capture.output(sessioninfo::session_info())# Remove lines that contain "[1]" and "[2]" (the file paths)filtered_info <-grep("\\[1\\]|\\[2\\]", info, value =TRUE, invert =TRUE)cat(filtered_info, sep ="\n")
─ Session info ───────────────────────────────────────────────────────────────
setting value
version R version 4.4.1 (2024-06-14 ucrt)
os Windows 10 x64 (build 19045)
system x86_64, mingw32
ui RTerm
language (EN)
collate English_United States.utf8
ctype English_United States.utf8
tz America/New_York
date 2024-10-07
pandoc 3.2 @ C:/Program Files/RStudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
─ Packages ───────────────────────────────────────────────────────────────────
! package * version date (UTC) lib source
P cli 3.6.3 2024-06-21 [?] RSPM (R 4.4.0)
P digest 0.6.37 2024-08-19 [?] RSPM (R 4.4.0)
P evaluate 0.24.0 2024-06-10 [?] RSPM (R 4.4.0)
P fastmap 1.2.0 2024-05-15 [?] RSPM (R 4.4.0)
P htmltools 0.5.8.1 2024-04-04 [?] RSPM (R 4.4.0)
P htmlwidgets 1.6.4 2023-12-06 [?] CRAN (R 4.4.0)
P jsonlite 1.8.8 2023-12-04 [?] RSPM (R 4.4.0)
P knitr 1.48 2024-07-07 [?] RSPM (R 4.4.0)
P rlang 1.1.4 2024-06-04 [?] RSPM (R 4.4.0)
P rmarkdown 2.28 2024-08-17 [?] RSPM (R 4.4.0)
P sessioninfo 1.2.2 2021-12-06 [?] RSPM (R 4.4.0)
P xfun 0.47 2024-08-17 [?] RSPM (R 4.4.0)
P yaml 2.3.10 2024-07-26 [?] RSPM (R 4.4.0)
P ── Loaded and on-disk path mismatch.
──────────────────────────────────────────────────────────────────────────────