Saving & Composing Plots

So far, every plot has stayed inside your browser session. In real projects you’ll usually want to (a) save a plot to a file, and (b) sometimes combine several independent plots into one figure for a report, a slide, or a paper.

Saving a plot to disk

Note

This section uses {r} code cells rather than the interactive {webr-r} cells you’ve used so far, because writing files to disk is something you do in your own local R session, not inside a browser sandbox. Read through the code and run it yourself in RStudio to try it out.

Do: run the following, which saves a plot to a PNG file using base R’s graphics-device approach: open a device, draw the plot, then close the device.

p <- ggplot(mpg) +
  geom_point(aes(x = displ, y = hwy))

png("my_plot.png")
p
dev.off()

See: nothing appears in your plot pane or console. Instead, a new file called my_plot.png shows up in your working directory.

Predict: ggplot2 also provides a dedicated function for this, ggsave(). Given that p is a ggplot2 object, built entirely from ggplot()/geom_*(), what advantages do you expect a function written specifically for saving ggplot objects to have over the general png()/dev.off() approach above?

Explain: png(), pdf(), and jpeg() each redirect any subsequent plotting output to a file until dev.off() closes it again. This works for p, but it would work equally well for a base-R plot(), since it doesn’t know or care what kind of plot it’s drawing. Forgetting dev.off() is a common mistake: if you do, the file is left open and often looks empty or incomplete.

ggsave() is built specifically for ggplot2 objects, and trades that generality for convenience:

ggsave("my_plot.png", plot = p, width = 6, height = 4, units = "in", dpi = 300)

It also infers the file format directly from the extension you give it (.png, .pdf, .jpg, and more all work), and gives you direct arguments for width, height, and dpi.

Combining several plots into one figure

Faceting splits one plot into panels that all share the same variables and geometry. Sometimes, though, you have several genuinely different plots, different geometries, different variables, that you still want to display side-by-side.

Do: first, build three unrelated plots and save each one to its own object. As before, assigning a plot to a variable stores it silently without drawing it.

Do: now arrange all three saved plots into one figure with grid.arrange(), requesting two columns.

See: the three plots appear together in a 2-column layout, p1 and p2 side by side in the first row, and p3 alone in the second row, leaving an empty cell next to it. Each plot keeps its own axes, colours, and legend.

Predict: what do you expect to change if you set ncol = 3 instead of ncol = 2?

Explain: grid.arrange() places the plots into the grid row by row, left to right, top to bottom, based on the ncol (or nrow) you request. With ncol = 2, three plots don’t divide evenly into two columns, so the third plot starts a new row on its own, leaving a gap. With ncol = 3, all three fit on a single row. Unlike faceting, each panel here is a fully separate ggplot2 object. Different geometries, different variables, even different colour scales and legends, grid.arrange() is simply laying pre-built plots out next to each other, not splitting one plot’s data by a variable.

Note

The ggpubr package provides an alternative function, ggarrange(), with one extra convenience: setting common.legend = TRUE merges duplicate legends across plots into a single shared one. This is useful when, as here, several plots share the same colour mapping (class) and repeating the same legend three times wastes space.

Predict-and-check: layout order

Using the p1, p2, and p3 objects from above, predict what changes if you call grid.arrange(p1, p2, p3, ncol = 1) instead of ncol = 2. Then test it.

ncol (and nrow) control the layout grid, just like they did for facet_wrap().

grid.arrange(p1, p2, p3, ncol = 1)

With ncol = 1, all three plots are stacked into a single column instead of a 2-column grid. The same three plots, just laid out differently.

Back to top