This visualization combines the power of ggforce for drawing ellipses and smooth geometry with magick for image annotation and layout. Together, they enhance a standard ggplot2 chart to create a polished, publication-ready graphic using the palmerpenguins dataset.
#TidyTuesday
{ggforce}
Images
{magick}
Author
Aditya Dahiya
Published
April 16, 2025
About the Data
The penguins dataset is included in base R starting from version 4.5.0, and is available via the datasets package. It provides measurements of adult penguins across three species—Adélie, Chinstrap, and Gentoo—found on three islands in the Palmer Archipelago, Antarctica. Key variables include flipper length, body mass, bill dimensions, sex, and the year of observation. This dataset is a curated subset of a more extensive penguins_raw dataset, which also contains information on nesting behavior and blood isotope ratios. Originally used by Gorman et al. (2014) to explore sexual dimorphism in penguins, the dataset gained broader popularity through the palmerpenguins package as a user-friendly alternative to the classic iris dataset. Recent efforts by Kaye et al. (2025) have integrated this data directly into base R, along with reproducible scripts and documentation.
Figure 1: This graphic visualizes the variation in **bill length and depth** across three penguin species—Adélie, Chinstrap, and Gentoo—found in the Palmer Archipelago, Antarctica. Each point represents an individual penguin, with species distinguished by color. Translucent convex hulls, generated using `geom_mark_hull()` from the ggforce package, visually group individuals by species to highlight distinct morphological clusters. The visualization draws from the newly integrated penguins dataset in base R (v4.5.0), offering a clean and engaging way to explore species-level differences in bill dimensions. Penguin illustrations and minimalist typography enhance clarity while maintaining a playful yet informative tone.
How I made this graphic?
To create this visual, I began by loading the penguins dataset now available in base R from version 4.5.0 onwards. Using the tidyverse for data wrangling and ggplot2 for plotting, I mapped bill length and depth, with points styled by species using geom_point(). To highlight species clusters, I used geom_mark_hull() from the ggforce package, which draws translucent convex hulls around each species group. I customized fonts via showtext and google fonts, and embedded penguin illustrations using magick and ggimage. Final layout adjustments, such as adding a logo inset, were done using the patchwork package. The entire plot was saved with ggsave() from [ggplot2] and customized for visual clarity with theme_minimal() and extensive use of element_textbox() from ggtext.
Loading required libraries
Code
# Data Import and Wrangling Toolslibrary(tidyverse) # All things tidy# Final plot toolslibrary(scales) # Nice Scales for ggplot2library(fontawesome) # Icons display in ggplot2library(ggtext) # Markdown text support for ggplot2library(showtext) # Display fonts in ggplot2library(colorspace) # Lighten and Darken colourslibrary(magick) # Download images and edit themlibrary(ggimage) # Display images in ggplot2library(patchwork) # Composing Plotslibrary(ggforce) # for geom_mark_hull()penguins <- penguins |>as_tibble()
Visualization Parameters
Code
# Font for titlesfont_add_google("Yaldevi",family ="title_font") # Font for the captionfont_add_google("Barlow Condensed",family ="caption_font") # Font for plot textfont_add_google("Fira Code",family ="body_font") showtext_auto()# cols4all::c4a_gui()# Pick a colour paletter that is Colour-Blind friendly, fair and # has a good contrast ratio with whitemypal <- paletteer::paletteer_d("ltc::trio3")mypal <-c("#FF7502", "#C55CC9", "#0F6F74")# A base Colourbg_col <-"white"seecolor::print_color(bg_col)# Colour for highlighted texttext_hil <-"grey30"seecolor::print_color(text_hil)# Colour for the texttext_col <-"grey30"seecolor::print_color(text_col)line_col <-"grey30"# Define Base Text Sizebts <-90# Caption stuff for the plotsysfonts::font_add(family ="Font Awesome 6 Brands",regular = here::here("docs", "Font Awesome 6 Brands-Regular-400.otf"))github <-""github_username <-"aditya-dahiya"xtwitter <-""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:** {palmerpenguins}, base R", " | **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 <-"Penguin Bills in Focus"plot_subtitle <-"Using the famous base **R** dataset from **{palmerpenguins}**, to depict the variation in bill dimensions across different penguin species. Each species is visually encapsulated by a translucent convex hull—using ggforce's **geom_mark_hull()** — to emphasize distinct distribution patterns."|>str_wrap(90) |>str_replace_all("\\n", "<br>")
Exploratory Data Analysis and Wrangling
Code
# library(summarytools)# penguins |> # dfSummary() |> # view()# Get images to insertlibrary(magick)logo1 <-image_read("https://allisonhorst.github.io/palmerpenguins/reference/figures/lter_penguins.png") |>image_background("transparent")logo2 <-image_read("https://education.rstudio.com/blog/2020/07/palmerpenguins-cran/penguins_cran.png")
# Saving a thumbnaillibrary(magick)# Saving a thumbnail for the webpageimage_read(here::here("data_vizs", "tidy_palmerpenguins.png")) |>image_resize(geometry ="x400") |>image_write( here::here("data_vizs", "thumbnails", "tidy_palmerpenguins.png" ) )
Session Info
Code
# Data Import and Wrangling Toolslibrary(tidyverse) # All things tidy# Final plot toolslibrary(scales) # Nice Scales for ggplot2library(fontawesome) # Icons display in ggplot2library(ggtext) # Markdown text support for ggplot2library(showtext) # Display fonts in ggplot2library(colorspace) # Lighten and Darken colourslibrary(magick) # Download images and edit themlibrary(ggimage) # Display images in ggplot2library(patchwork) # Composing Plotslibrary(ggforce) # for geom_mark_hull()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