Chapter 19 Internals of ggplot2

Learning Objectives

  • What is the difference between user-facing code and internal code?
  • What is the distinction between ggplot_build() and ggplot_gtable()?
  • What the division of labor between {ggplot2} and {grid}?
  • What is the basic structure of/motivation for ggproto?
library(ggplot2)
library(ggtrace) # remotes::install_github("yjunechoe/ggtrace")
library(purrr)
library(dplyr)

19.0.0.1 Introduction (the existence of internals)

The user-facing code that defines a ggplot on the surface is not the same as the internal code that creates a ggplot under the hood. In this chapter, we’ll learn about how the internal code operates and develop some intuitions about thinking about the internals, starting with these two simple examples of mismatches between surface and underlying form:

19.0.0.2 Case 1: Order

You can change the order of some “layers” without change to the graphical output.

For example, scale_*() can be added anywhere and always ends up applying for the whole plot:

ggplot(mtcars, aes(mpg, hp, color = as.factor(am))) +
  scale_x_log10() + #< scale first
  geom_point() +
  geom_smooth()

ggplot(mtcars, aes(mpg, hp, color = as.factor(am))) +
  geom_point() +
  scale_x_log10() + #< scale middle
  geom_smooth()

Though the order of geom_*() and stat_*() matters for order of drawing:

ggplot(mtcars, aes(mpg, hp, color = as.factor(am))) +
  geom_point() +
  geom_smooth(fill = "black")

ggplot(mtcars, aes(mpg, hp, color = as.factor(am))) +
  geom_smooth(fill = "black") +
  geom_point()

19.0.0.3 Case 2: Modularity

We know that user-facing “layer” code that we add to a ggplot with + are stand-alone functions:

lm_smooth <- geom_smooth(method = "lm", formula = y ~ x)
lm_smooth
geom_smooth: na.rm = FALSE, orientation = NA, se = TRUE
stat_smooth: na.rm = FALSE, orientation = NA, se = TRUE, method = lm, formula = y ~ x
position_identity 

When we add this object to different ggplots, it materializes in different ways:

ggplot(mtcars, aes(mpg, hp)) +
  lm_smooth

ggplot(mtcars, aes(wt, disp)) +
  lm_smooth