Deep dive: themes

Lecture 09

Dr. Benjamin Soltoff

Cornell University
INFO 3312/5312 - Spring 2024

February 20, 2024

Announcements

Announcements

  • Homework 3 due tomorrow
  • Feedback for project 1 proposals posted as issue on GitHub

Agenda for today

  • Visualization critique
  • Alternative themes
  • theme() components
  • Using custom fonts
  • Develop a custom theme

Visualization critique

Planned Parenthood bad

Planned Parenthood not as bad(?)

Planned Parenthood does more than abortions

Themes

Is that gray background okay?

It adds contrast! Some people just don’t like it 🤷

Like this!

library(ggthemes)

ggplot(penguins, aes(
  x = bill_depth_mm,
  y = bill_length_mm,
  color = species
)) +
  geom_point(size = 2) +
  theme_tufte()

And this!

library(ggthemes)

ggplot(penguins, aes(
  x = bill_depth_mm,
  y = bill_length_mm,
  color = species
)) +
  geom_point(size = 2) +
  theme_solarized()

Or this!

library(ggthemes)

ggplot(penguins, aes(
  x = bill_depth_mm,
  y = bill_length_mm,
  color = species
)) +
  geom_point(size = 2) +
  scale_color_economist() +
  theme_economist()

And even this!

library(ggpomological)

ggplot(penguins, aes(
  x = bill_depth_mm,
  y = bill_length_mm,
  color = species
)) +
  geom_point(size = 2) +
  scale_color_pomological() +
  theme_pomological_fancy()

The anatomy of a ggplot() theme

Theme system

Theme elements

Each element in the plot can be targeted

  • Plot title = plot.title
  • Grid lines = panel.grid
  • Legend background = legend.background

Use special functions to manipulate specific elements

  • Text-based things = element_text()
  • Rectangular things (backgrounds) = element_rect()
  • Line-based things (axis lines, grid lines) = element_line()
  • Disable element completely = element_blank()

How to learn theme()

  • The theme() function has 94 possible arguments
  • You can get hyper-specific with things like axis.ticks.length.x.bottom
  • The only way to learn how to use theme() is to use it and tinker with it

gapminder

library(gapminder)
gapminder
# A tibble: 1,704 × 6
   country     continent  year lifeExp      pop gdpPercap
   <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
 1 Afghanistan Asia       1952    28.8  8425333      779.
 2 Afghanistan Asia       1957    30.3  9240934      821.
 3 Afghanistan Asia       1962    32.0 10267083      853.
 4 Afghanistan Asia       1967    34.0 11537966      836.
 5 Afghanistan Asia       1972    36.1 13079460      740.
 6 Afghanistan Asia       1977    38.4 14880372      786.
 7 Afghanistan Asia       1982    39.9 12881816      978.
 8 Afghanistan Asia       1987    40.8 13867957      852.
 9 Afghanistan Asia       1992    41.7 16317921      649.
10 Afghanistan Asia       1997    41.8 22227415      635.
# ℹ 1,694 more rows

Basic plot

gapminder_filtered <- gapminder |>
  filter(year > 2000)

base_plot <- ggplot(
  data = gapminder_filtered,
  mapping = aes(
    x = gdpPercap, y = lifeExp,
    color = continent, size = pop
  )
) +
  geom_point() +
  # Use dollars, and get rid of the cents part (i.e. $300 instead of $300.00)
  scale_x_log10(labels = label_dollar(scale_cut = cut_short_scale())) +
  # Format with commas
  scale_size_continuous(labels = label_comma()) +
  # Use dark 3
  scale_color_discrete_qualitative(palette = "Dark 3") +
  labs(
    x = "GDP per capita", y = "Life expectancy",
    color = "Continent", size = "Population",
    title = "Here's a cool title",
    subtitle = "And here's a neat subtitle",
    caption = "Source: The Gapminder Project"
  ) +
  facet_wrap(facets = vars(year))

base_plot

Change the theme

base_plot +
  theme_minimal()

Create a custom theme

# change base font
my_pretty_theme <- theme_minimal(base_family = "Roboto Condensed", base_size = 14) +
  theme(
    # Remove minor grid lines
    panel.grid.minor = element_blank(),
    # Bold, bigger title
    plot.title = element_text(face = "bold", size = rel(1.7)),
    # Plain, slightly bigger subtitle that is grey
    plot.subtitle = element_text(face = "plain", size = rel(1.3), color = "grey70"),
    # Italic, smaller, grey caption that is left-aligned
    plot.caption = element_text(
      face = "italic", size = rel(0.7),
      color = "grey70", hjust = 0
    ),
    # Bold legend titles
    legend.title = element_text(face = "bold"),
    # Bold, slightly larger facet titles that are left-aligned for the sake of repetition
    strip.text = element_text(face = "bold", size = rel(1.1), hjust = 0),
    # Bold axis titles
    axis.title = element_text(face = "bold"),
    # Add some space above the x-axis title and make it left-aligned
    axis.title.x = element_text(margin = margin(t = 10), hjust = 0),
    # Add some space to the right of the y-axis title and make it top-aligned
    axis.title.y = element_text(margin = margin(r = 10), hjust = 1),
    # Add a light grey background to the facet titles, with no borders
    strip.background = element_rect(fill = "grey90", color = NA),
    # Add a thin grey border around all the plots to tie in the facet titles
    panel.border = element_rect(color = "grey90", fill = NA)
  )

Applied to existing plot

base_plot +
  my_pretty_theme

Applied to another plot

library(palmerpenguins)

ggplot(
  data = drop_na(penguins, sex),
  mapping = aes(x = bill_length_mm, y = body_mass_g, color = str_to_title(sex))
) +
  geom_point(size = 3, alpha = 0.5) +
  scale_color_discrete_qualitative(palette = "Dark 3") +
  scale_y_continuous(labels = label_comma()) +
  facet_wrap(vars(species)) +
  labs(
    x = "Bill length (mm)", y = "Body mass (g)", color = "Sex",
    title = "Gentoo penguins are the largest",
    subtitle = "But females are typically smaller than males",
    caption = "Here's a caption"
  ) +
  my_pretty_theme

A note on custom fonts

Custom fonts in ggplot2

  • Rendering text and custom fonts has been historically difficult in R (and many other programming languages)
  • Requires unifying the graphics device, operating system, text rendering, and R
  • Several approaches exist with ggplot2 to simplify this process
    • extrafont and showfont
    • ragg

ragg

  • ragg is a package that provides a consistent way to render fonts across different devices
  • Install fonts directly on system and use ragg as the graphics device
  • Many great uses for this workflow! But it requires the ability to directly install fonts on the device…

Ensure graphs are rendered using ragg

  • ggsave() automatically uses ragg as of 3.3.4
  • In Quarto, set the dev chunk option
knitr:
  opts_chunk:
    dev: ragg_png

Application exercise

ae-07

  • Go to the course GitHub org and find your ae-07 (repo name will be suffixed with your NetID).
  • Clone the repo in RStudio Workbench, open the Quarto document in the repo, and follow along and complete the exercises.
  • Render, commit, and push your edits by the AE deadline – end of tomorrow.

Wrap up

Wrap up

  • ggplot2 uses theming to control the visual appearance of charts
  • Use custom themes to apply consistent styles across multiple plots

Fondue for two