ggplot Wizardry Hands-On

A Step-by-Step tutorial as supplement to my talk “ggplot Wizardry: My Favorite Tricks and Secrets for Beautiful Plot in R” at OutlierConf 2021.

Cédric Scherer https://cedricscherer.com (Self-Employed Data Visualization Designer | IZW Berlin)
2021-02-09

Download the script here.

Preparation

Packages

Note that packages need to be installed first via install.packages("packagename").

library(tidyverse)   ## data science package collection (incl. the ggplot2 package)
library(systemfonts) ## use custom fonts (need to be installed on your OS)  
library(scico)       ## scico color palettes(http://www.fabiocrameri.ch/colourmaps.php) in R 
library(ggtext)      ## add improved text rendering to ggplot2
library(ggforce)     ## add missing functionality to ggplot2
library(ggdist)      ## add uncertainity visualizations to ggplot2
library(magick)      ## load images into R
library(patchwork)   ## combine outputs from ggplot2

Data

Data were collected and made available by Dr. Kristen Gorman and the Palmer Station, Antarctica LTER, a member of the Long Term Ecological Research Network.

The data is easily available as well as palmerpenguins package. The goal of palmerpenguins is to provide a great dataset for data exploration & visualization, as an alternative to iris.

allisonhorst.github.io/palmerpenguins

penguins <- 
  readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-07-28/penguins.csv') %>% 
  ## correct species name
  mutate(species = if_else(species == "Adelie", "Adélie", species)) %>% 
  ## remove missing observations
  filter(!is.na(bill_length_mm), !is.na(bill_depth_mm))

## if you like: nicely formatted table in report
penguins %>% 
  kableExtra::kbl() %>%
  kableExtra::kable_paper(full_width = TRUE) %>%
  kableExtra::kable_styling(bootstrap_options = c("striped", "condensed", "responsive")) %>%
  kableExtra::scroll_box(width = "700px", height = "500px")
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
Adélie Torgersen 39.1 18.7 181 3750 male 2007
Adélie Torgersen 39.5 17.4 186 3800 female 2007
Adélie Torgersen 40.3 18.0 195 3250 female 2007
Adélie Torgersen 36.7 19.3 193 3450 female 2007
Adélie Torgersen 39.3 20.6 190 3650 male 2007
Adélie Torgersen 38.9 17.8 181 3625 female 2007
Adélie Torgersen 39.2 19.6 195 4675 male 2007
Adélie Torgersen 34.1 18.1 193 3475 NA 2007
Adélie Torgersen 42.0 20.2 190 4250 NA 2007
Adélie Torgersen 37.8 17.1 186 3300 NA 2007
Adélie Torgersen 37.8 17.3 180 3700 NA 2007
Adélie Torgersen 41.1 17.6 182 3200 female 2007
Adélie Torgersen 38.6 21.2 191 3800 male 2007
Adélie Torgersen 34.6 21.1 198 4400 male 2007
Adélie Torgersen 36.6 17.8 185 3700 female 2007
Adélie Torgersen 38.7 19.0 195 3450 female 2007
Adélie Torgersen 42.5 20.7 197 4500 male 2007
Adélie Torgersen 34.4 18.4 184 3325 female 2007
Adélie Torgersen 46.0 21.5 194 4200 male 2007
Adélie Biscoe 37.8 18.3 174 3400 female 2007
Adélie Biscoe 37.7 18.7 180 3600 male 2007
Adélie Biscoe 35.9 19.2 189 3800 female 2007
Adélie Biscoe 38.2 18.1 185 3950 male 2007
Adélie Biscoe 38.8 17.2 180 3800 male 2007
Adélie Biscoe 35.3 18.9 187 3800 female 2007
Adélie Biscoe 40.6 18.6 183 3550 male 2007
Adélie Biscoe 40.5 17.9 187 3200 female 2007
Adélie Biscoe 37.9 18.6 172 3150 female 2007
Adélie Biscoe 40.5 18.9 180 3950 male 2007
Adélie Dream 39.5 16.7 178 3250 female 2007
Adélie Dream 37.2 18.1 178 3900 male 2007
Adélie Dream 39.5 17.8 188 3300 female 2007
Adélie Dream 40.9 18.9 184 3900 male 2007
Adélie Dream 36.4 17.0 195 3325 female 2007
Adélie Dream 39.2 21.1 196 4150 male 2007
Adélie Dream 38.8 20.0 190 3950 male 2007
Adélie Dream 42.2 18.5 180 3550 female 2007
Adélie Dream 37.6 19.3 181 3300 female 2007
Adélie Dream 39.8 19.1 184 4650 male 2007
Adélie Dream 36.5 18.0 182 3150 female 2007
Adélie Dream 40.8 18.4 195 3900 male 2007
Adélie Dream 36.0 18.5 186 3100 female 2007
Adélie Dream 44.1 19.7 196 4400 male 2007
Adélie Dream 37.0 16.9 185 3000 female 2007
Adélie Dream 39.6 18.8 190 4600 male 2007
Adélie Dream 41.1 19.0 182 3425 male 2007
Adélie Dream 37.5 18.9 179 2975 NA 2007
Adélie Dream 36.0 17.9 190 3450 female 2007
Adélie Dream 42.3 21.2 191 4150 male 2007
Adélie Biscoe 39.6 17.7 186 3500 female 2008
Adélie Biscoe 40.1 18.9 188 4300 male 2008
Adélie Biscoe 35.0 17.9 190 3450 female 2008
Adélie Biscoe 42.0 19.5 200 4050 male 2008
Adélie Biscoe 34.5 18.1 187 2900 female 2008
Adélie Biscoe 41.4 18.6 191 3700 male 2008
Adélie Biscoe 39.0 17.5 186 3550 female 2008
Adélie Biscoe 40.6 18.8 193 3800 male 2008
Adélie Biscoe 36.5 16.6 181 2850 female 2008
Adélie Biscoe 37.6 19.1 194 3750 male 2008
Adélie Biscoe 35.7 16.9 185 3150 female 2008
Adélie Biscoe 41.3 21.1 195 4400 male 2008
Adélie Biscoe 37.6 17.0 185 3600 female 2008
Adélie Biscoe 41.1 18.2 192 4050 male 2008
Adélie Biscoe 36.4 17.1 184 2850 female 2008
Adélie Biscoe 41.6 18.0 192 3950 male 2008
Adélie Biscoe 35.5 16.2 195 3350 female 2008
Adélie Biscoe 41.1 19.1 188 4100 male 2008
Adélie Torgersen 35.9 16.6 190 3050 female 2008
Adélie Torgersen 41.8 19.4 198 4450 male 2008
Adélie Torgersen 33.5 19.0 190 3600 female 2008
Adélie Torgersen 39.7 18.4 190 3900 male 2008
Adélie Torgersen 39.6 17.2 196 3550 female 2008
Adélie Torgersen 45.8 18.9 197 4150 male 2008
Adélie Torgersen 35.5 17.5 190 3700 female 2008
Adélie Torgersen 42.8 18.5 195 4250 male 2008
Adélie Torgersen 40.9 16.8 191 3700 female 2008
Adélie Torgersen 37.2 19.4 184 3900 male 2008
Adélie Torgersen 36.2 16.1 187 3550 female 2008
Adélie Torgersen 42.1 19.1 195 4000 male 2008
Adélie Torgersen 34.6 17.2 189 3200 female 2008
Adélie Torgersen 42.9 17.6 196 4700 male 2008
Adélie Torgersen 36.7 18.8 187 3800 female 2008
Adélie Torgersen 35.1 19.4 193 4200 male 2008
Adélie Dream 37.3 17.8 191 3350 female 2008
Adélie Dream 41.3 20.3 194 3550 male 2008
Adélie Dream 36.3 19.5 190 3800 male 2008
Adélie Dream 36.9 18.6 189 3500 female 2008
Adélie Dream 38.3 19.2 189 3950 male 2008
Adélie Dream 38.9 18.8 190 3600 female 2008
Adélie Dream 35.7 18.0 202 3550 female 2008
Adélie Dream 41.1 18.1 205 4300 male 2008
Adélie Dream 34.0 17.1 185 3400 female 2008
Adélie Dream 39.6 18.1 186 4450 male 2008
Adélie Dream 36.2 17.3 187 3300 female 2008
Adélie Dream 40.8 18.9 208 4300 male 2008
Adélie Dream 38.1 18.6 190 3700 female 2008
Adélie Dream 40.3 18.5 196 4350 male 2008
Adélie Dream 33.1 16.1 178 2900 female 2008
Adélie Dream 43.2 18.5 192 4100 male 2008
Adélie Biscoe 35.0 17.9 192 3725 female 2009
Adélie Biscoe 41.0 20.0 203 4725 male 2009
Adélie Biscoe 37.7 16.0 183 3075 female 2009
Adélie Biscoe 37.8 20.0 190 4250 male 2009
Adélie Biscoe 37.9 18.6 193 2925 female 2009
Adélie Biscoe 39.7 18.9 184 3550 male 2009
Adélie Biscoe 38.6 17.2 199 3750 female 2009
Adélie Biscoe 38.2 20.0 190 3900 male 2009
Adélie Biscoe 38.1 17.0 181 3175 female 2009
Adélie Biscoe 43.2 19.0 197 4775 male 2009
Adélie Biscoe 38.1 16.5 198 3825 female 2009
Adélie Biscoe 45.6 20.3 191 4600 male 2009
Adélie Biscoe 39.7 17.7 193 3200 female 2009
Adélie Biscoe 42.2 19.5 197 4275 male 2009
Adélie Biscoe 39.6 20.7 191 3900 female 2009
Adélie Biscoe 42.7 18.3 196 4075 male 2009
Adélie Torgersen 38.6 17.0 188 2900 female 2009
Adélie Torgersen 37.3 20.5 199 3775 male 2009
Adélie Torgersen 35.7 17.0 189 3350 female 2009
Adélie Torgersen 41.1 18.6 189 3325 male 2009
Adélie Torgersen 36.2 17.2 187 3150 female 2009
Adélie Torgersen 37.7 19.8 198 3500 male 2009
Adélie Torgersen 40.2 17.0 176 3450 female 2009
Adélie Torgersen 41.4 18.5 202 3875 male 2009
Adélie Torgersen 35.2 15.9 186 3050 female 2009
Adélie Torgersen 40.6 19.0 199 4000 male 2009
Adélie Torgersen 38.8 17.6 191 3275 female 2009
Adélie Torgersen 41.5 18.3 195 4300 male 2009
Adélie Torgersen 39.0 17.1 191 3050 female 2009
Adélie Torgersen 44.1 18.0 210 4000 male 2009
Adélie Torgersen 38.5 17.9 190 3325 female 2009
Adélie Torgersen 43.1 19.2 197 3500 male 2009
Adélie Dream 36.8 18.5 193 3500 female 2009
Adélie Dream 37.5 18.5 199 4475 male 2009
Adélie Dream 38.1 17.6 187 3425 female 2009
Adélie Dream 41.1 17.5 190 3900 male 2009
Adélie Dream 35.6 17.5 191 3175 female 2009
Adélie Dream 40.2 20.1 200 3975 male 2009
Adélie Dream 37.0 16.5 185 3400 female 2009
Adélie Dream 39.7 17.9 193 4250 male 2009
Adélie Dream 40.2 17.1 193 3400 female 2009
Adélie Dream 40.6 17.2 187 3475 male 2009
Adélie Dream 32.1 15.5 188 3050 female 2009
Adélie Dream 40.7 17.0 190 3725 male 2009
Adélie Dream 37.3 16.8 192 3000 female 2009
Adélie Dream 39.0 18.7 185 3650 male 2009
Adélie Dream 39.2 18.6 190 4250 male 2009
Adélie Dream 36.6 18.4 184 3475 female 2009
Adélie Dream 36.0 17.8 195 3450 female 2009
Adélie Dream 37.8 18.1 193 3750 male 2009
Adélie Dream 36.0 17.1 187 3700 female 2009
Adélie Dream 41.5 18.5 201 4000 male 2009
Gentoo Biscoe 46.1 13.2 211 4500 female 2007
Gentoo Biscoe 50.0 16.3 230 5700 male 2007
Gentoo Biscoe 48.7 14.1 210 4450 female 2007
Gentoo Biscoe 50.0 15.2 218 5700 male 2007
Gentoo Biscoe 47.6 14.5 215 5400 male 2007
Gentoo Biscoe 46.5 13.5 210 4550 female 2007
Gentoo Biscoe 45.4 14.6 211 4800 female 2007
Gentoo Biscoe 46.7 15.3 219 5200 male 2007
Gentoo Biscoe 43.3 13.4 209 4400 female 2007
Gentoo Biscoe 46.8 15.4 215 5150 male 2007
Gentoo Biscoe 40.9 13.7 214 4650 female 2007
Gentoo Biscoe 49.0 16.1 216 5550 male 2007
Gentoo Biscoe 45.5 13.7 214 4650 female 2007
Gentoo Biscoe 48.4 14.6 213 5850 male 2007
Gentoo Biscoe 45.8 14.6 210 4200 female 2007
Gentoo Biscoe 49.3 15.7 217 5850 male 2007
Gentoo Biscoe 42.0 13.5 210 4150 female 2007
Gentoo Biscoe 49.2 15.2 221 6300 male 2007
Gentoo Biscoe 46.2 14.5 209 4800 female 2007
Gentoo Biscoe 48.7 15.1 222 5350 male 2007
Gentoo Biscoe 50.2 14.3 218 5700 male 2007
Gentoo Biscoe 45.1 14.5 215 5000 female 2007
Gentoo Biscoe 46.5 14.5 213 4400 female 2007
Gentoo Biscoe 46.3 15.8 215 5050 male 2007
Gentoo Biscoe 42.9 13.1 215 5000 female 2007
Gentoo Biscoe 46.1 15.1 215 5100 male 2007
Gentoo Biscoe 44.5 14.3 216 4100 NA 2007
Gentoo Biscoe 47.8 15.0 215 5650 male 2007
Gentoo Biscoe 48.2 14.3 210 4600 female 2007
Gentoo Biscoe 50.0 15.3 220 5550 male 2007
Gentoo Biscoe 47.3 15.3 222 5250 male 2007
Gentoo Biscoe 42.8 14.2 209 4700 female 2007
Gentoo Biscoe 45.1 14.5 207 5050 female 2007
Gentoo Biscoe 59.6 17.0 230 6050 male 2007
Gentoo Biscoe 49.1 14.8 220 5150 female 2008
Gentoo Biscoe 48.4 16.3 220 5400 male 2008
Gentoo Biscoe 42.6 13.7 213 4950 female 2008
Gentoo Biscoe 44.4 17.3 219 5250 male 2008
Gentoo Biscoe 44.0 13.6 208 4350 female 2008
Gentoo Biscoe 48.7 15.7 208 5350 male 2008
Gentoo Biscoe 42.7 13.7 208 3950 female 2008
Gentoo Biscoe 49.6 16.0 225 5700 male 2008
Gentoo Biscoe 45.3 13.7 210 4300 female 2008
Gentoo Biscoe 49.6 15.0 216 4750 male 2008
Gentoo Biscoe 50.5 15.9 222 5550 male 2008
Gentoo Biscoe 43.6 13.9 217 4900 female 2008
Gentoo Biscoe 45.5 13.9 210 4200 female 2008
Gentoo Biscoe 50.5 15.9 225 5400 male 2008
Gentoo Biscoe 44.9 13.3 213 5100 female 2008
Gentoo Biscoe 45.2 15.8 215 5300 male 2008
Gentoo Biscoe 46.6 14.2 210 4850 female 2008
Gentoo Biscoe 48.5 14.1 220 5300 male 2008
Gentoo Biscoe 45.1 14.4 210 4400 female 2008
Gentoo Biscoe 50.1 15.0 225 5000 male 2008
Gentoo Biscoe 46.5 14.4 217 4900 female 2008
Gentoo Biscoe 45.0 15.4 220 5050 male 2008
Gentoo Biscoe 43.8 13.9 208 4300 female 2008
Gentoo Biscoe 45.5 15.0 220 5000 male 2008
Gentoo Biscoe 43.2 14.5 208 4450 female 2008
Gentoo Biscoe 50.4 15.3 224 5550 male 2008
Gentoo Biscoe 45.3 13.8 208 4200 female 2008
Gentoo Biscoe 46.2 14.9 221 5300 male 2008
Gentoo Biscoe 45.7 13.9 214 4400 female 2008
Gentoo Biscoe 54.3 15.7 231 5650 male 2008
Gentoo Biscoe 45.8 14.2 219 4700 female 2008
Gentoo Biscoe 49.8 16.8 230 5700 male 2008
Gentoo Biscoe 46.2 14.4 214 4650 NA 2008
Gentoo Biscoe 49.5 16.2 229 5800 male 2008
Gentoo Biscoe 43.5 14.2 220 4700 female 2008
Gentoo Biscoe 50.7 15.0 223 5550 male 2008
Gentoo Biscoe 47.7 15.0 216 4750 female 2008
Gentoo Biscoe 46.4 15.6 221 5000 male 2008
Gentoo Biscoe 48.2 15.6 221 5100 male 2008
Gentoo Biscoe 46.5 14.8 217 5200 female 2008
Gentoo Biscoe 46.4 15.0 216 4700 female 2008
Gentoo Biscoe 48.6 16.0 230 5800 male 2008
Gentoo Biscoe 47.5 14.2 209 4600 female 2008
Gentoo Biscoe 51.1 16.3 220 6000 male 2008
Gentoo Biscoe 45.2 13.8 215 4750 female 2008
Gentoo Biscoe 45.2 16.4 223 5950 male 2008
Gentoo Biscoe 49.1 14.5 212 4625 female 2009
Gentoo Biscoe 52.5 15.6 221 5450 male 2009
Gentoo Biscoe 47.4 14.6 212 4725 female 2009
Gentoo Biscoe 50.0 15.9 224 5350 male 2009
Gentoo Biscoe 44.9 13.8 212 4750 female 2009
Gentoo Biscoe 50.8 17.3 228 5600 male 2009
Gentoo Biscoe 43.4 14.4 218 4600 female 2009
Gentoo Biscoe 51.3 14.2 218 5300 male 2009
Gentoo Biscoe 47.5 14.0 212 4875 female 2009
Gentoo Biscoe 52.1 17.0 230 5550 male 2009
Gentoo Biscoe 47.5 15.0 218 4950 female 2009
Gentoo Biscoe 52.2 17.1 228 5400 male 2009
Gentoo Biscoe 45.5 14.5 212 4750 female 2009
Gentoo Biscoe 49.5 16.1 224 5650 male 2009
Gentoo Biscoe 44.5 14.7 214 4850 female 2009
Gentoo Biscoe 50.8 15.7 226 5200 male 2009
Gentoo Biscoe 49.4 15.8 216 4925 male 2009
Gentoo Biscoe 46.9 14.6 222 4875 female 2009
Gentoo Biscoe 48.4 14.4 203 4625 female 2009
Gentoo Biscoe 51.1 16.5 225 5250 male 2009
Gentoo Biscoe 48.5 15.0 219 4850 female 2009
Gentoo Biscoe 55.9 17.0 228 5600 male 2009
Gentoo Biscoe 47.2 15.5 215 4975 female 2009
Gentoo Biscoe 49.1 15.0 228 5500 male 2009
Gentoo Biscoe 47.3 13.8 216 4725 NA 2009
Gentoo Biscoe 46.8 16.1 215 5500 male 2009
Gentoo Biscoe 41.7 14.7 210 4700 female 2009
Gentoo Biscoe 53.4 15.8 219 5500 male 2009
Gentoo Biscoe 43.3 14.0 208 4575 female 2009
Gentoo Biscoe 48.1 15.1 209 5500 male 2009
Gentoo Biscoe 50.5 15.2 216 5000 female 2009
Gentoo Biscoe 49.8 15.9 229 5950 male 2009
Gentoo Biscoe 43.5 15.2 213 4650 female 2009
Gentoo Biscoe 51.5 16.3 230 5500 male 2009
Gentoo Biscoe 46.2 14.1 217 4375 female 2009
Gentoo Biscoe 55.1 16.0 230 5850 male 2009
Gentoo Biscoe 44.5 15.7 217 4875 NA 2009
Gentoo Biscoe 48.8 16.2 222 6000 male 2009
Gentoo Biscoe 47.2 13.7 214 4925 female 2009
Gentoo Biscoe 46.8 14.3 215 4850 female 2009
Gentoo Biscoe 50.4 15.7 222 5750 male 2009
Gentoo Biscoe 45.2 14.8 212 5200 female 2009
Gentoo Biscoe 49.9 16.1 213 5400 male 2009
Chinstrap Dream 46.5 17.9 192 3500 female 2007
Chinstrap Dream 50.0 19.5 196 3900 male 2007
Chinstrap Dream 51.3 19.2 193 3650 male 2007
Chinstrap Dream 45.4 18.7 188 3525 female 2007
Chinstrap Dream 52.7 19.8 197 3725 male 2007
Chinstrap Dream 45.2 17.8 198 3950 female 2007
Chinstrap Dream 46.1 18.2 178 3250 female 2007
Chinstrap Dream 51.3 18.2 197 3750 male 2007
Chinstrap Dream 46.0 18.9 195 4150 female 2007
Chinstrap Dream 51.3 19.9 198 3700 male 2007
Chinstrap Dream 46.6 17.8 193 3800 female 2007
Chinstrap Dream 51.7 20.3 194 3775 male 2007
Chinstrap Dream 47.0 17.3 185 3700 female 2007
Chinstrap Dream 52.0 18.1 201 4050 male 2007
Chinstrap Dream 45.9 17.1 190 3575 female 2007
Chinstrap Dream 50.5 19.6 201 4050 male 2007
Chinstrap Dream 50.3 20.0 197 3300 male 2007
Chinstrap Dream 58.0 17.8 181 3700 female 2007
Chinstrap Dream 46.4 18.6 190 3450 female 2007
Chinstrap Dream 49.2 18.2 195 4400 male 2007
Chinstrap Dream 42.4 17.3 181 3600 female 2007
Chinstrap Dream 48.5 17.5 191 3400 male 2007
Chinstrap Dream 43.2 16.6 187 2900 female 2007
Chinstrap Dream 50.6 19.4 193 3800 male 2007
Chinstrap Dream 46.7 17.9 195 3300 female 2007
Chinstrap Dream 52.0 19.0 197 4150 male 2007
Chinstrap Dream 50.5 18.4 200 3400 female 2008
Chinstrap Dream 49.5 19.0 200 3800 male 2008
Chinstrap Dream 46.4 17.8 191 3700 female 2008
Chinstrap Dream 52.8 20.0 205 4550 male 2008
Chinstrap Dream 40.9 16.6 187 3200 female 2008
Chinstrap Dream 54.2 20.8 201 4300 male 2008
Chinstrap Dream 42.5 16.7 187 3350 female 2008
Chinstrap Dream 51.0 18.8 203 4100 male 2008
Chinstrap Dream 49.7 18.6 195 3600 male 2008
Chinstrap Dream 47.5 16.8 199 3900 female 2008
Chinstrap Dream 47.6 18.3 195 3850 female 2008
Chinstrap Dream 52.0 20.7 210 4800 male 2008
Chinstrap Dream 46.9 16.6 192 2700 female 2008
Chinstrap Dream 53.5 19.9 205 4500 male 2008
Chinstrap Dream 49.0 19.5 210 3950 male 2008
Chinstrap Dream 46.2 17.5 187 3650 female 2008
Chinstrap Dream 50.9 19.1 196 3550 male 2008
Chinstrap Dream 45.5 17.0 196 3500 female 2008
Chinstrap Dream 50.9 17.9 196 3675 female 2009
Chinstrap Dream 50.8 18.5 201 4450 male 2009
Chinstrap Dream 50.1 17.9 190 3400 female 2009
Chinstrap Dream 49.0 19.6 212 4300 male 2009
Chinstrap Dream 51.5 18.7 187 3250 male 2009
Chinstrap Dream 49.8 17.3 198 3675 female 2009
Chinstrap Dream 48.1 16.4 199 3325 female 2009
Chinstrap Dream 51.4 19.0 201 3950 male 2009
Chinstrap Dream 45.7 17.3 193 3600 female 2009
Chinstrap Dream 50.7 19.7 203 4050 male 2009
Chinstrap Dream 42.5 17.3 187 3350 female 2009
Chinstrap Dream 52.2 18.8 197 3450 male 2009
Chinstrap Dream 45.2 16.6 191 3250 female 2009
Chinstrap Dream 49.3 19.9 203 4050 male 2009
Chinstrap Dream 50.2 18.8 202 3800 male 2009
Chinstrap Dream 45.6 19.4 194 3525 female 2009
Chinstrap Dream 51.9 19.5 206 3950 male 2009
Chinstrap Dream 46.8 16.5 189 3650 female 2009
Chinstrap Dream 45.7 17.0 195 3650 female 2009
Chinstrap Dream 55.8 19.8 207 4000 male 2009
Chinstrap Dream 43.5 18.1 202 3400 female 2009
Chinstrap Dream 49.6 18.2 193 3775 male 2009
Chinstrap Dream 50.8 19.0 210 4100 male 2009
Chinstrap Dream 50.2 18.7 198 3775 female 2009

A Basic ggplot

## simple plot: data + mappings + geometry
ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point(alpha = .6, size = 3.5)

ggsave("00_scatterplot_raw.pdf", width = 9, height = 8, device = cairo_pdf)


A Customized ggplot

## change global theme settings (for all following plots)
theme_set(theme_minimal(base_size = 12, base_family = "Open Sans"))

## modify plot elements globally (for all following plots)
theme_update(
  axis.ticks = element_line(color = "grey92"),
  axis.ticks.length = unit(.5, "lines"),
  panel.grid.minor = element_blank(),
  legend.title = element_text(size = 12),
  legend.text = element_text(color = "grey30"),
  plot.title = element_text(size = 18, face = "bold"),
  plot.subtitle = element_text(size = 12, color = "grey30"),
  plot.caption = element_text(size = 9, margin = margin(t = 15))
)
ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) + 
  ## custom axes scaling
  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5), limits = c(12.5, 22.5)) +
  ## custom colors
  scico::scale_color_scico(palette = "bamako", direction = -1) +
  ## custom labels
  labs(
    title = 'Bill Dimensions of Brush-Tailed Penguins (Pygoscelis)',
    subtitle = 'A scatter plot of bill depth versus bill length.',
    caption = 'Data: Gorman, Williams & Fraser (2014) PLoS ONE',
    x = 'Bill Length (mm)', 
    y = 'Bill Depth (mm)',
    color = 'Body mass (g)'
  )

ggsave("01_theme_color_labs.pdf", width = 9, height = 8, device = cairo_pdf)


{ggtext}

The ggtext package provides simple Markdown and HTML rendering for ggplot2. Under the hood, the package uses the gridtext package for the actual rendering, and consequently it is limited to the feature set provided by gridtext.
Support is provided for Markdown both in theme elements (plot titles, subtitles, captions, axis labels, legends, etc.) and in geoms (similar to geom_text()). In both cases, there are two alternatives, one for creating simple text labels and one for creating text boxes with word wrapping.

wilkelab.org/ggtext

element_markdown()

element_markdown() → formatted text elements, e.g. titles, caption, axis text, striptext

## assign plot to `g` - we can ad new things to this plot later
## (wrapped in parenthesis so it is assigned and plotted in one step)
(gt <- ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) + 
  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5), limits = c(12.5, 22.5)) +
  scico::scale_color_scico(palette = "bamako", direction = -1) +
  ## markdown formatting using asterisks
  labs(
    title = 'Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)',
    subtitle = 'A scatter plot of bill depth versus bill length.',
    caption = 'Data: Gorman, Williams & Fraser (2014) *PLoS ONE*',
    x = '**Bill Length** (mm)', 
    y = '**Bill Depth** (mm)',
    color = 'Body mass (g)'
  ) +
  ## render respective text elements
  theme(
    plot.title = ggtext::element_markdown(),
    plot.caption = ggtext::element_markdown(),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown()
  )
)
 
ggsave("02a_ggtext_element_markdown.pdf", width = 9, height = 8, device = cairo_pdf)

element_markdown() in combination with HTML

## use HTML syntax to change text color
gt_mar <- gt +
  labs(title = 'Bill Dimensions of Brush-Tailed Penguins <i style="color:#28A87D;">Pygoscelis</i>') +
  theme(plot.margin = margin(t = 25))

ggsave("02b_ggtext_element_markdown_color.pdf", width = 9, height = 8, device = cairo_pdf)

## use HTML syntax to change font and text size
gt_mar +
  labs(title = 'Bill Dimensions of Brush-Tailed Penguins <b style="font-size:32pt;font-family:blacksword;">Pygoscelis</b>')

ggsave("02c_ggtext_element_markdown_font.pdf", width = 9, height = 8, device = cairo_pdf)

## use HTML syntax to add images to text elements
gt_mar + 
  #labs(title = 'Bill Dimensions of Brush-Tailed Penguins <img src="https://researchgate.net/profile/Jean_Lightner/publication/274710342/figure/fig8/AS:614338578640906@1523481139381/Pygoscelis-papua-Source-Wikipedia-http-wwwenwikipediaorg.png"‚ width="100"/>') +
  ## title with missing quotation mark to make an erroneous pdf - 
  ## otherwise it throws an error because of RCurl on Windows OS
  labs(title = 'Bill Dimensions of Brush-Tailed Penguins <img src="https://researchgate.net/profile/Jean_Lightner/publication/274710342/figure/fig8/AS:614338578640906@1523481139381/Pygoscelis-papua-Source-Wikipedia-http-wwwenwikipediaorg.png‚ width="100"/>') +
    
ggsave("02d_ggtext_element_markdown_image.pdf", width = 9, height = 8, device = cairo_pdf)

element_textbox(), geom_richtext() and geom_textbox()

geom_richtext() → formatted text labels with 360° rotation

gt_rich <- ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point(aes(color = species), alpha = .6, size = 3.5) + 
  ## add text annotations for each species
  ggtext::geom_richtext(
    data = tibble(
      x = c(34, 56, 54), y = c(20, 18.5, 14.5),
      species = c("Adélie", "Chinstrap", "Gentoo"),
      lab = c("<b style='font-family:anton;font-size:24pt;'>Adélie</b><br><i style='color:darkgrey;'>P. adéliae</i>", 
              "<b style='font-family:anton;font-size:24pt;'>Chinstrap</b><br><i style='color:darkgrey;'>P. antarctica</i>", 
              "<b style='font-family:anton;font-size:24pt;'>Gentoo</b><br><i style='color:darkgrey;'>P. papua</i>"),
      angle = c(12, 20, 335)
    ),
    aes(x, y, label = lab, color = species, angle = angle), 
    size = 4, fill = NA, label.color = NA,
    lineheight = .3
  ) +
  scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
  scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5), limits = c(12.5, 22.5)) +
  rcartocolor::scale_color_carto_d(palette = "Bold", guide = "none") +
  labs(
    title = 'Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)',
    subtitle = 'A scatter plot of bill depth versus bill length.',
    caption = 'Data: Gorman, Williams & Fraser (2014) *PLoS ONE*',
    x = '**Bill Length** (mm)', 
    y = '**Bill Depth** (mm)',
    color = 'Body mass (g)'
  )

(gt_rich +
  theme(
    plot.title = ggtext::element_markdown(),
    plot.caption = ggtext::element_markdown(),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown(),
    plot.margin = margin(25, 6, 15, 6)
  )
)
  
ggsave("02e_ggtext_geom_richtext.pdf", width = 9, height = 8, device = cairo_pdf)

element_textbox() and element_textbox_simple() → formatted text boxes with word wrapping

(gt_box <- gt_rich +
  theme(
    ## turn title into filled textbox
    plot.title = ggtext::element_textbox_simple(
      color = "white", fill = "#28A87D",  size = 32, 
      padding = margin(8, 4, 8, 4), margin = margin(b = 5), lineheight= .9
    ),
    ## add round outline to caption
    plot.caption = ggtext::element_textbox_simple(
      width = NULL, linetype = 1, padding = margin(4, 8, 4, 8), 
      margin = margin(t = 15), r = grid::unit(8, "pt")
    ),
    axis.title.x = ggtext::element_markdown(),
    axis.title.y = ggtext::element_markdown(),
    plot.margin = margin(25, 6, 15, 6)
  )
)

ggsave("02f_ggtext_element_textbox.pdf", width = 9, height = 8, device = cairo_pdf)
knitr::include_graphics(here::here("img", "palmer", "02f_ggtext_element_textbox.png"))

geom_textbox() → formatted text boxes with word wrapping

gt_box +
  ## add textbox with long paragraphs
  ggtext::geom_textbox(
    data = tibble(x = 34, y = 13.7, label = "<span style='font-size:12pt;font-family:anton;'>Lorem Ipsum Dolor Sit Amet</span><br><br>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."),
    aes(x, y, label = label),
    size = 2.2, family = "Open Sans",
    fill = "cornsilk", box.color = "cornsilk3",
    width = unit(11, "lines")
  ) +
  coord_cartesian(clip = "off")

ggsave("02g_ggtext_geom_textbox.pdf", width = 9, height = 8, device = cairo_pdf)
knitr::include_graphics(here::here("img", "palmer", "02g_ggtext_geom_textbox.png"))

## use ggtext rendering for the following plots
theme_update(
  plot.title = ggtext::element_markdown(),
  plot.caption = ggtext::element_markdown(),
  axis.title.x = ggtext::element_markdown(),
  axis.title.y = ggtext::element_markdown()
)

{ggforce}

ggforce is a package aimed at providing missing functionality to ggplot2 through the extension system introduced with ggplot2 v2.0.0. Broadly speaking ggplot2 has been aimed primarily at explorative data visualization in order to investigate the data at hand, and less at providing utilities for composing custom plots a la D3.js. ggforce is mainly an attempt to address these “shortcoming” (design choices might be a better description). The goal is to provide a repository of geoms, stats, etc. that are as well documented and implemented as the official ones found in ggplot2.

ggforce.data-imaginist.com

## plot that we will annotate with gggforce afterwards
gf <- ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) + 
  scico::scale_color_scico(palette = "bamako", direction = -1) +
  coord_cartesian(xlim = c(25, 65), ylim = c(10, 25)) +
  rcartocolor::scale_fill_carto_d(palette = "Bold") +
  labs(
    title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
    subtitle = 'A scatter plot of bill depth versus bill length.',
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
    x = "**Bill Length** (mm)", 
    y = "**Bill Depth** (mm)",
    color = "Body mass (g)",
    fill = "Species"
  )
 
## ellipsoids for all groups
(gf +
  ggforce::geom_mark_ellipse(
    aes(fill = species, label = species), 
    alpha = .15, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)
)

ggsave("03a_ggforce_geom_mark_ellipsoid.pdf", width = 9, height = 8, device = cairo_pdf)
knitr::include_graphics(here::here("img", "palmer", "03a_ggforce_geom_mark_ellipsoid.png"))

## ellipsoids for specific subset
(gf +
  ggforce::geom_mark_ellipse(
    aes(fill = species, label = species, filter = species == 'Gentoo'), 
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) +
  coord_cartesian(xlim = c(25, 65), ylim = c(10, 25))
)
 
ggsave("03b_ggforce_geom_mark_filtered.pdf", width = 9, height = 8, device = cairo_pdf)

## circles
(gf +
  ggforce::geom_mark_circle(
    aes(fill = species, label = species, filter = species == 'Gentoo'), 
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)
)
 
ggsave("03c_ggforce_geom_mark_circle.pdf", width = 9, height = 8, device = cairo_pdf)

## rectangles
(gf +
  ggforce::geom_mark_rect(
    aes(fill = species, label = species, filter = species == 'Gentoo'), 
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) 
)
 
ggsave("03d_ggforce_geom_mark_rect.pdf", width = 9, height = 8, device = cairo_pdf)

## hull
(gf +
  ggforce::geom_mark_hull(
    aes(fill = species, label = species, filter = species == 'Gentoo'), 
    alpha = 0, show.legend = FALSE
  ) +
  geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)
)
 
ggsave("03e_ggforce_geom_mark_hull.pdf", width = 9, height = 8, device = cairo_pdf)


ggplot Tricks

(gg0 <- 
  ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
    ggforce::geom_mark_ellipse(
      aes(fill = species, label = species), 
      alpha = 0, show.legend = FALSE
    ) +
    geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) + 
    scale_x_continuous(breaks = seq(25, 65, by = 5), limits = c(25, 65)) +
    scale_y_continuous(breaks = seq(12, 24, by = 2), limits = c(12, 24)) +
    scico::scale_color_scico(palette = "bamako", direction = -1) +
    labs(
      title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
      subtitle = 'A scatter plot of bill depth versus bill length.',
      caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
      x = "Bill Length (mm)", 
      y = "Bill Depth (mm)",
      color = "Body mass (g)"
    )
)

ggsave("04_scatterplot_mod_start.pdf", width = 9, height = 8, device = cairo_pdf)

Left-Aligned Title

(gg1 <- gg0 + theme(plot.title.position = "plot"))

ggsave("05a_position_title.pdf", width = 9, height = 8, device = cairo_pdf)

Right-Aligned Caption

(gg1b <- gg1 +  theme(plot.caption.position = "plot"))

ggsave("05b_position_caption.pdf", width = 9, height = 8, device = cairo_pdf)

Legend Design

(gg2 <- gg1b + theme(legend.position = "top"))

ggsave("06a_legend_position.pdf", width = 9, height = 8, device = cairo_pdf)

(gg2b <- gg2 + 
  guides(color = guide_colorbar(title.position = "top", 
                                title.hjust = .5, 
                                barwidth = unit(20, "lines"), 
                                barheight = unit(.5, "lines"))))

ggsave("06b_legend_guide.pdf", width = 9, height = 8, device = cairo_pdf)

Limit Expansion

(gg3 <- gg2b + coord_cartesian(expand = FALSE))

ggsave("07_coord_expand.pdf", width = 9, height = 8, device = cairo_pdf)

Geeky Details: Clipping

(gg3b <- gg3 + coord_cartesian(expand = FALSE, clip = "off"))
  
ggsave("08_coord_offclip.pdf", width = 9, height = 8, device = cairo_pdf)

White Space

(gg4 <- gg3b + theme(plot.margin = margin(t = 25, r = 25, b = 10, l = 25))) # top, right, bottom, left

ggsave("09_theme_margin.pdf", width = 9, height = 8, device = cairo_pdf)

Add Images

## read PNG file from web
png <- magick::image_read("https://raw.githubusercontent.com/allisonhorst/palmerpenguins/master/man/figures/culmen_depth.png"))
## turn image into `rasterGrob`
img <- grid::rasterGrob(png, interpolate = TRUE)

(gg5 <- gg4 +
  annotation_custom(img, ymin = 21.5, ymax = 30.5, xmin = 55, xmax = 65.5) +
    labs(caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE* &bull; Illustration: Allison Horst"))

ggsave("10_annotate_img.pdf", width = 9, height = 8, device = cairo_pdf)

{patchwork}

The goal of patchwork is to make it ridiculously simple to combine separate ggplots into the same graphic. As such it tries to solve the same problem as gridExtra::grid.arrange() and cowplot::plot_grid but using an API that incites exploration and iteration, and scales to arbitrily complex layouts.

patchwork.data-imaginist.com

## calculate bill ratio and summary stats
df_peng_stats <- 
  penguins %>% 
  mutate(bill_ratio = bill_length_mm / bill_depth_mm) %>% 
  filter(!is.na(bill_ratio)) %>% 
  group_by(species) %>% 
  mutate(
    n = n(),
    median = median(bill_ratio),
    max = max(bill_ratio)
  ) %>% 
  ungroup() %>% 
  mutate(species_num = as.numeric(fct_rev(species))) 

## create a second chart with raincloud plots
p2 <- 
  ggplot(df_peng_stats, aes(bill_ratio, species_num, color = species)) +
  stat_summary(
    geom = "linerange",
    fun.min = function(x) -Inf,
    fun.max = function(x) median(x, na.rm = TRUE),
    linetype = "dotted",
    orientation = "y",
    size = .7
  ) +
  geom_point(
    aes(y = species_num - .15), 
    shape = "|",
    size = 5,
    alpha = .33
  ) +
  ggdist::stat_halfeye(
    aes(
      y = species_num,
      color = species,
      fill = after_scale(colorspace::lighten(color, .5))
    ),
    shape = 18,
    point_size = 3,
    interval_size = 1.8,
    adjust = .5,
    .width = c(0, 1)
  ) +
  geom_text(
    aes(x = median, label = format(round(median, 2), nsmall = 2)),
    stat = "unique",
    color = "white",
    family = "Open Sans",
    fontface = "bold",
    size = 3.4,
    nudge_y = .15
  ) +
  geom_text(
    aes(x = max, label = glue::glue("n = {n}")),
    stat = "unique",
    family = "Open Sans",
    fontface = "bold",
    size = 3.5,
    hjust = 0,
    nudge_x = .01,
    nudge_y = .02
  ) +
  coord_cartesian(clip = "off", expand = FALSE) +
  scale_x_continuous(
    limits = c(1.6, 3.8),
    breaks = seq(1.6, 3.8, by = .2)
  ) +
  scale_y_continuous(
    limits = c(.55, NA),
    breaks = 1:3,
    labels = c("Gentoo", "Chinstrap", "Adélie")
  ) +
  scale_color_manual(values = c("#3d6721", "#a86826", "#006c89"), guide = "none") +
  scale_fill_manual(values = c("#3d6721", "#a86826", "#006c89"), guide = "none") +
  labs(
    x = "Bill ratio",
    y = NULL,
    subtitle = "B. Raincloud plot showing the distribution of bill ratios, estimated as bill length divided by bill depth.",
    caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE* &bull; Illustration: Allison Horst"
  ) +
  theme(
    panel.grid.major.x = element_line(size = .35),
    panel.grid.major.y = element_blank(),
    axis.text.y = element_text(size = 13),
    axis.ticks.length = unit(0, "lines"),
    plot.title.position = 'plot',
    plot.subtitle = element_text(margin = margin(t = 5, b = 10)),
    plot.margin = margin(10, 25, 10, 25)
  )

ggsave("11_raincloud_plot.pdf", width = 9, height = 5.2, device = cairo_pdf)

## combine both plots
(gg5 + labs(caption = NULL, subtitle = "A. Scatter plot of bill depth versus bill length.")) / p2 +
  plot_layout(heights = c(1, .65))

ggsave("12_patchwork_panel.pdf", width = 9, height = 13.2, device = cairo_pdf)


Another Example for Clipping

## with clipping
(on <- mtcars %>% 
  rownames_to_column() %>% 
  ggplot(aes(mpg, fct_reorder(rowname, mpg))) + 
    geom_point(size = 4, shape = "diamond", color = "firebrick") + 
    geom_text(aes(label = rowname), nudge_x = .35, hjust = 0, family = "Open Sans", size = 3.3) +     
    theme_void(base_size = 8, base_family = "Open Sans") + 
    theme(axis.line.x = element_line(color = "grey40"), 
          axis.text.x = element_text(color = "grey40"), 
          axis.ticks.x = element_line(color = "grey40"), 
          axis.ticks.length.x = unit(.4, "lines"), 
          plot.margin = margin(10, 45, 10, 20))
) 

ggsave("13a_clip_on.pdf", width = 9, height = 7, device = cairo_pdf)

## without clipping
on + coord_cartesian(clip = "off")
  
ggsave("13b_clip_off.pdf", width = 9, height = 7, device = cairo_pdf)


Resources


Session Info
[1] "2021-02-09 09:17:07 CET"
R version 4.0.2 (2020-06-22)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19041)

Matrix products: default

locale:
[1] LC_COLLATE=German_Germany.1252  LC_CTYPE=German_Germany.1252   
[3] LC_MONETARY=German_Germany.1252 LC_NUMERIC=C                   
[5] LC_TIME=German_Germany.1252    
system code page: 65001

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods  
[7] base     

other attached packages:
 [1] patchwork_1.1.1   magick_2.6.0      ggdist_2.4.0     
 [4] ggforce_0.3.2     ggtext_0.1.1      scico_1.2.0.9000 
 [7] systemfonts_1.0.0 forcats_0.5.1     stringr_1.4.0    
[10] dplyr_1.0.4       purrr_0.3.4       readr_1.4.0      
[13] tidyr_1.1.2       tibble_3.0.6      ggplot2_3.3.3    
[16] tidyverse_1.3.0  

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.6           here_1.0.1           lubridate_1.7.9.2   
 [4] png_0.1-7            rprojroot_2.0.2      assertthat_0.2.1    
 [7] digest_0.6.27        R6_2.5.0             cellranger_1.1.0    
[10] backports_1.1.7      reprex_1.0.0         evaluate_0.14       
[13] highr_0.8            httr_1.4.2           pillar_1.4.7        
[16] rlang_0.4.10         curl_4.3             readxl_1.3.1        
[19] rstudioapi_0.13      rmarkdown_2.6        webshot_0.5.2       
[22] polyclip_1.10-0      munsell_0.5.0        gridtext_0.1.4      
[25] broom_0.7.4          compiler_4.0.2       modelr_0.1.8        
[28] xfun_0.20            pkgconfig_2.0.3      htmltools_0.5.1.1   
[31] downlit_0.2.1        tidyselect_1.1.0     viridisLite_0.3.0   
[34] fansi_0.4.2          crayon_1.4.0         dbplyr_2.0.0        
[37] withr_2.4.1          MASS_7.3-51.6        grid_4.0.2          
[40] distributional_0.2.2 jsonlite_1.7.2       gtable_0.3.0        
[43] lifecycle_0.2.0      DBI_1.1.1            magrittr_2.0.1      
[46] scales_1.1.1         cli_2.3.0            stringi_1.5.3       
[49] farver_2.0.3         fs_1.5.0             xml2_1.3.2          
[52] ellipsis_0.3.1       generics_0.1.0       vctrs_0.3.6         
[55] distill_1.2          kableExtra_1.3.1     tools_4.0.2         
[58] glue_1.4.2           tweenr_1.0.1         hms_1.0.0           
[61] yaml_2.2.1           colorspace_2.0-0     rvest_0.3.6         
[64] knitr_1.31           haven_2.3.1