Graphic Design with ggplot2

How to Create Engaging and
Complex Visualizations in R

Cédric Scherer // rstudio::conf // July 2022

Welcome!

Conversation Starters

  • What’s your name?
  • Where do you feel home?
  • When did you use R for the first time?
  • What’s your favorite animal / plant / color / typeface?
  • Whom would you like to meet during the rstudio::conf?
  • Which R package are you looking forward to try?

Announcements

WiFi

  • Username: conf22
  • Password: together!

Course Materials

Announcements

  • gender neutral bathrooms by the National Harbor rooms
  • meditation room is located at National Harbor 9, open 8am-5pm, Monday-Thursday
  • there is also has a dedicated room behind the reception
  • lactation room is located at Potomac Dressing Room, open 8am-5pm, Monday-Thursday.
  • participants with red lanyards wish to be not photographed, please note everyone’s lanyard colors before taking a photo
  • The Code of Conduct and COVID policies can be found at rstudio.com/conference/2022/2022-conf-code-of-conduct,
    please review them carefully

Communication Strategy


  • Green sticky note — I am done with the exercise

  • Pink sticky note — I need help or support

  • You can ask questions / comment at any time during the course.
  • Please avoid questions during the breaks to give us a chance to recover and reflect.
  • Team up with your neighbors for exercises — and lunch!
  • We will collect feedback twice during the day (more later).

Introduction

The ggplot2 hex logo.


{ggplot2} is a system for declaratively creating graphics,
based on “The Grammar of Graphics” (Wilkinson, 2005).

You provide the data, tell {ggplot2} how to map variables to aesthetics,
what graphical primitives to use, and it takes care of the details.

Advantages of {ggplot2}

  • consistent underlying “grammar of graphics” (Wilkinson 2005)
  • very flexible, layered plot specification
  • theme system for polishing plot appearance
  • lots of additional functionality thanks to extensions
  • active and helpful community
Allison Horsts monster illustration of explorative plotting with ggplot2.

Illustration by Allison Horst

A collection of the versatility of ggplot2 to create basic graphs. All of them use the default grey ggplot2 theme.

ggplot2 Examples featured on ggplot2.tidyverse.org

Allison Horsts monster illustration of building  data masterpiece ith ggplot2 featuring a little Picasso monster :)

Illustration by Allison Horst

The {ggplot2} Showcase

A multi-plot panel of various data visualizations created by the BBC teams.

Collection of Graphics from the BBC R Cookbook

A colorful and annotated scatterplot and a custom raincloud plot showing various bill measures of Palmer penguins.

Contribution to #TidyTuesday Week 2020/31

The raincloud chart showing the distributions of normalized speech rates (dark pink) and information rates (dark lime green) across language families.

My reinterpreted The Economist graphic

A circular tree showing the German winner parties for each district & state of the 2019 European Parliament Election.

“European Elections” by Torsten Sprenger

Two circular hierarchical bar plots showing the carbon footprint 2018 for food consumption and CO2 per continent and country.

Contribution to #TidyTuesday Week 2020/08

A facet of shots and goals of the Bundesliga football clubs in the season 2019/20.

Contribution to the #SWDchallenge “Small Multiples”

A facet of trees over time with less and less leaves as time passes by; each leave represents one billion treees.

Contribution to the #TidyTuesday Week 2021/15 x #30DayChartChallenge 2021 by Jake Kaupp

A grid map using moon charts for all 297 electoral districts which show the share of the wnning party in second votesc during the German election in 2021.

Moon Charts as a Tile Grid Map showing the 2nd Vote Results from the German Election 2021

A gridded map of Europe showing horizontal stacked bars of energy production per country over time (each bar represents share among one year from 2016 to 2018).

#TidyTuesday Contribution by Jack Davison

A spatial map of cheetah movement and their hotspot behaviour in Namibia.

Our Winning Contribution to the BES MoveMap Contest

A spatial map of income and inequality shown with a bivariate color palette; alpine regions have a hillshading effect.

Bivariate Choropleth x Hillshade Map by Timo Gossenbacher

A set of small multiples using pixelated encodings of certain elements in Bob Ross' paintings.

Pixel Art by Georgios Karamanis

Two artworks by Thomas Pedersen, completely generated in R with ggplot2 (and pure magic).

Generative Art by Thomas Lin Pedersen

A Motivational Example

## scatter plot of plot bikes$count versus bikes$count
ggplot(bikes, aes(temp_feel, count)) +
  geom_point(size = 2.2)

ggplot(bikes, aes(temp_feel, count)) +
  ## colored, semi-transparent points
  geom_point(
    aes(color = season),
    size = 2.2, alpha = .55
  )

ggplot(bikes, aes(temp_feel, count)) +
  geom_point(
    aes(color = season),
    size = 2.2, alpha = .55
  ) +
  ## add a linear fitting for each time of the day
  geom_smooth(
    aes(group = day_night),
    method = "lm", color = "black"
  )

ggplot(bikes, aes(temp_feel, count)) +
  geom_point(
    aes(color = season),
    size = 2.2, alpha = .55
  ) +
  geom_smooth(
    aes(group = day_night),
    method = "lm", color = "black"
  ) +
  ## create small multiples of time of day versus workday
  facet_grid(day_night ~ is_workday)

ggplot(bikes, aes(temp_feel, count)) +
  geom_point(
    aes(color = season),
    size = 2.2, alpha = .55
  ) +
  geom_smooth(
    aes(group = day_night),
    method = "lm", color = "black"
  ) +
  ## create free-ranging, proportionally sized small multiples
  facet_grid(
    day_night ~ is_workday,
    scales = "free_y", space = "free_y"
  )

ggplot(bikes, aes(temp_feel, count)) +
  geom_point(
    aes(color = season),
    size = 2.2, alpha = .55
  ) +
  geom_smooth(
    aes(group = day_night),
    method = "lm", color = "black"
  ) +
  facet_grid(
    day_night ~ is_workday,
    scales = "free_y", space = "free_y"
  ) +
  ## add labels + titles
  labs(
    x = "Feels-Like Temperature", y = NULL,
    caption = "Data: TfL (Transport for London), Jan 2015 — Dec 2016",
    title = "Reported bike rents versus feels-like temperature in London per time of day, period, and season."
  )

ggplot(bikes, aes(temp_feel, count)) +
  geom_point(
    aes(color = season),
    size = 2.2, alpha = .55
  ) +
  geom_smooth(
    aes(group = day_night),
    method = "lm", color = "black"
  ) +
  facet_grid(
    day_night ~ is_workday,
    scales = "free_y", space = "free_y"
  ) +
  ## add custom colors + legend styling
  scale_color_manual(
    values = c("#3c89d9", "#1ec99b", "#F7B01B", "#a26e7c"), name = "Season:",
    guide = guide_legend(override.aes = list(size = 5))
  ) +
  labs(
    x = "Feels-Like Temperature", y = NULL,
    caption = "Data: TfL (Transport for London), Jan 2015 — Dec 2016",
    title = "Reported bike rents versus feels-like temperature in London per time of day, period, and season."
  ) +
  ## use different theme and typeface
  theme_light(base_size = 18, base_family = "Cabinet Grotesk")

## coding for facet strip text
codes <- c(
  workday = "Workday",
  weekend_or_holiday = "Weekend or Holiday"
)

ggplot(bikes, aes(temp_feel, count)) +
  ## format seasons
  geom_point(
    aes(color = forcats::fct_relabel(season, stringr::str_to_title)),
    size = 2.2, alpha = .55
  ) +
  geom_smooth(
    aes(group = day_night),
    method = "lm", color = "black"
  ) +
  ## format facet strip text
  facet_grid(
    day_night ~ is_workday,
    scales = "free_y", space = "free_y",
    labeller = labeller(
      day_night = stringr::str_to_title,
      is_workday = codes
    )
  ) +
  ## customize x axis
  scale_x_continuous(
    expand = c(.02, .02),
    breaks = 0:6*5, labels = function(x) paste0(x, "°C")
  ) +
  ## customize y axis
  scale_y_continuous(
    expand = c(.1, .1), limits = c(0, NA),
    breaks = 0:5*10000, labels = scales::comma_format()
  ) +
  scale_color_manual(
    values = c("#3c89d9", "#1ec99b", "#F7B01B", "#a26e7c"), name = NULL,
    guide = guide_legend(override.aes = list(size = 5))
  ) +
  labs(
    x = "Feels-Like Temperature", y = NULL,
    caption = "Data: TfL (Transport for London), Jan 2015 — Dec 2016",
    title = "Reported bike rents versus feels-like temperature in London per time of day, period, and season."
  ) +
  theme_light(
    base_size = 18, base_family = "Cabinet Grotesk"
  ) +
  ## theme adjustments
  theme(
    plot.title.position = "plot",
    plot.caption.position = "plot",
    plot.title = element_text(face = "bold"),
    strip.text = element_text(face = "bold"),
    legend.position = "top"
  )

codes <- c(
  workday = "Workday",
  weekend_or_holiday = "Weekend or Holiday"
)

ggplot(bikes, aes(temp_feel, count)) +
  ## point outline
  geom_point(
    color = "black", fill = "white",
    shape = 21, size = 2.8
  ) +
  ## opaque point background
  geom_point(
    color = "white", size = 2.2
  ) +
  ## colored, semi-transparent points
  geom_point(
    aes(color = forcats::fct_relabel(season, stringr::str_to_title)),
    size = 2.2, alpha = .55
  ) +
  geom_smooth(
    aes(group = day_night), method = "lm", color = "black"
  ) +
  facet_grid(
    day_night ~ is_workday,
    scales = "free_y", space = "free_y",
    labeller = labeller(
      day_night = stringr::str_to_title,
      is_workday = codes
    )
  ) +
  scale_x_continuous(
    expand = c(.02, .02),
    breaks = 0:6*5, labels = function(x) paste0(x, "°C")
  ) +
  scale_y_continuous(
    expand = c(.1, .1), limits = c(0, NA),
    breaks = 0:5*10000, labels = scales::comma_format()
  ) +
  scale_color_manual(
    values = c("#3c89d9", "#1ec99b", "#F7B01B", "#a26e7c"), name = NULL,
    guide = guide_legend(override.aes = list(size = 5))
  ) +
  labs(
    x = "Feels-Like Temperature", y = NULL,
    caption = "Data: TfL (Transport for London), Jan 2015 — Dec 2016",
    title = "Reported bike rents versus feels-like temperature in London per time of day, period, and season."
  ) +
  theme_light(
    base_size = 18, base_family = "Cabinet Grotesk"
  ) +
  ## more theme adjustments
  theme(
    plot.title.position = "plot",
    plot.caption.position = "plot",
    plot.title = element_text(face = "bold", size = rel(1.3)),
    axis.text = element_text(family = "Tabular"),
    axis.title.x = element_text(hjust = 0, color = "grey30", margin = margin(t = 12)),
    strip.text = element_text(face = "bold" , size = rel(1.15)),
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank(),
    panel.spacing = unit(1.2, "lines"),
    legend.position = "top",
    legend.text = element_text(size = rel(1)),
    ## for fitting my slide background
    legend.key = element_rect(color = "#f8f8f8", fill = "#f8f8f8"),
    legend.background = element_rect(color = "#f8f8f8", fill = "#f8f8f8"),
    plot.background = element_rect(color = "#f8f8f8", fill = "#f8f8f8")
  )