19.5 Steps
The plot that gets rendered from a ggplot object is actually a side effect of evaluating the ggplot object:
ggplot object
function (x, newpage = is.null(vp), vp = NULL, ...)
{
set_last_plot(x)
if (newpage)
grid.newpage()
grDevices::recordGraphics(requireNamespace("ggplot2", quietly = TRUE),
list(), getNamespace("ggplot2"))
data <- ggplot_build(x)
gtable <- ggplot_gtable(data)
if (is.null(vp)) {
grid.draw(gtable)
}
else {
if (is.character(vp))
seekViewport(vp)
else pushViewport(vp)
grid.draw(gtable)
upViewport()
}
if (isTRUE(getOption("BrailleR.VI")) && rlang::is_installed("BrailleR")) {
print(asNamespace("BrailleR")$VI(x))
}
invisible(x)
}
<bytecode: 0x55a50675de40>
<environment: namespace:ggplot2>
The above code can be simplified to this:
ggprint <- function(x) {
data <- ggplot_build(x)
gtable <- ggplot_gtable(data)
grid::grid.newpage()
grid::grid.draw(gtable)
return(invisible(x)) #< hence "side effect"
}
ggprint(p)
Roughly put, you first start out as the ggplot object, which then gets passed to ggplot_build()
, result of which in turn gets passed to ggplot_gtable()
and finally drawn with {grid}
library(grid)
grid.newpage() # Clear display
p %>%
ggplot_build() %>% # 1. data for each layer is prepared for drawing
ggplot_gtable() %>% # 2. drawing-ready data is turned into graphical elements
grid.draw() # 3. graphical elements are converted to an image
At each step, you get closer to the low-level information you need to draw the actual plot
[1] "32 kB"
[1] "102 kB"
[1] "685 kB"
# the rendered plot
ggsave(
filename = tempfile(fileext = ".png"),
plot = ggplot_gtable(ggplot_build(p)),
# File size depends on format, dimension, resolution, etc.
) %>% file.size() %>% {scales::label_bytes()(.)}
[1] "243 kB"
The rest of the chapter focuses what happens in this pipeline - the ggplot_build()
step and the ggplot_gtable()
step.