title: "Arranging two or more plots in a grid" author: "Adapted from Claus O. Wilke by Alik Vodyanov" date: "2020-02-17" output: html_document: keep_md: true vignette: | %\VignetteIndexEntry{Arranging plots in a grid} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc}
There are several packages that can be used to place several plots on one figure. These include egg and patchwork. The particular function described here is my favourite, taken and adapted from cowplot package.
This vignette covers the function plot_grid()
, which can be used to create table-like layouts of plots ready for publication.
The plot_grid()
function provides a simple interface for arranging plots into a grid and adding labels to them.
library(ggplot2)
library(heor)
data(mtcars)
p1 <- ggplot(mtcars, aes(disp, mpg)) +
geom_point() +
heor_style_minimal()
p2 <- ggplot(mtcars, aes(qsec, mpg)) +
geom_point() +
heor_style_minimal()
plot_grid(p1, p2)
However, the basic method above only works if we are trying to combine plots with exactly the same elements and may not always work the way you would like with more complex plots. Therefore, something like faceted plot may not look as intended. Here we have a plot that looks ugly becuase the axis are not aligned and the faceted plot is too compressed compared to scatter plot.
p1 <- ggplot(mtcars, aes(disp, mpg)) +
geom_point() +
heor_style_minimal() +
theme(panel.border = element_rect(colour = "black", fill=NA))
p2 <- ggplot(mtcars, aes(factor(vs))) +
geom_bar() +
facet_wrap(~am) +
scale_y_continuous(expand = expand_scale(mult = c(0, 0.1))) +
heor_style_minimal() +
theme(strip.background = element_rect(fill = "gray80"),
panel.border = element_rect(colour = "black", fill=NA))
plot_grid(p1, p2, align = "h")
## Warning: Graphs cannot be horizontally aligned unless the axis parameter is
## set. Placing graphs unaligned.
Using additional arguments we can adjust the axis and relative size of the plots.
plot_grid(p1, p2, align = "h", axis="bt", rel_widths = c(1, 1.5))
In this example, we can align the plots vertically by specifying the alignment and number of columns.
library(dplyr)
city_mpg <- mpg %>%
group_by(class) %>%
summarize(
mean_mpg = mean(cty),
count = n())
p1 <- ggplot(city_mpg, aes(class, count)) +
geom_col() +
ylim(0, 65) +
coord_flip() +
heor_style()
p2 <- ggplot(city_mpg, aes(mean_mpg, count)) +
geom_point() +
heor_style()
plot_grid(p1, p2, ncol = 1)
plot_grid(p1, p2, ncol = 1, align = 'v')
Next, we can add labels to our plots.
plot_grid(p1, p2, ncol = 1, align = 'v', labels = "AUTO")
This function is case sensitive.
plot_grid(p1, p2, ncol = 1, align = 'v', labels = "auto")
It is also fairly customizable.
plot_grid(p1, p2, ncol = 1, align = 'v',
labels = c("One", "Two"),
label_fontfamily = "serif",
label_fontface = "plain",
label_colour = "blue")
The argument NULL can be used to indicate a missing plot in the grid. Note that missing plots will be labeled if automatic labeling is turned on.
# the second plot in the first row and the
# first plot in the second row are missing
plot_grid(
p1, NULL, NULL, p2,
labels = "AUTO", ncol = 2
)
In essence, everything we generate with plot_grid()
is just another ggplot object. Therefore, we can create more complex figure grids using this logic by simply nesting several plot_grids.
bottom_row <- plot_grid(p1, p2, labels = c('B', 'C'), label_size = 12, rel_widths = c(1.4, 1))
p3 <- ggplot(mtcars, aes(x = qsec, y = disp)) +
geom_point() +
facet_wrap(~gear) +
heor_style()
plot_grid(p3, bottom_row, labels = c('A', ''), label_size = 12, ncol = 1)
Alignment can be a bit tricky in this case. However, it can usually be achieved through an explicit call to align_plots()
. The trick is to first align the top-row plot (p3) and the first botton-row plot (p1) vertically along the left axis, using the align_plots()
function. These aligned plots can then be passed to plot_grid()
.
# first align the top-row plot (p3) with the left-most plot of the
# bottom row (p1)
plots <- align_plots(p3, p1, align = 'v', axis = 'l')
# then build the bottom row
bottom_row <- plot_grid(plots[[2]], p2, labels = c('B', 'C'), label_size = 12, rel_widths = c(1.4, 1))
# then combine with the top row for final plot
plot_grid(plots[[1]], bottom_row, labels = c('A', ''), label_size = 12, ncol = 1)
When we combine plots with plot_grid()
, we may want to add a title that spans the entire combined figure.
# make a plot grid consisting of two panels
p1 <- ggplot(mtcars, aes(x = disp, y = mpg)) +
geom_point(colour = "blue") +
heor_style()
p2 <- ggplot(mtcars, aes(x = hp, y = mpg)) +
geom_point(colour = "green") +
heor_style()
plot_row <- plot_grid(p1, p2)
# now add the title
title <- ggdraw() +
draw_label(
"Miles per gallon decline with displacement and horsepower",
fontface = 'bold',
x = 0,
hjust = 0
) +
theme(
# add margin on the left of the drawing canvas,
# so title is aligned with left edge of first plot
plot.margin = margin(0, 0, 0, 7)
)
plot_grid(
title, plot_row,
ncol = 1,
# rel_heights values control vertical title margins
rel_heights = c(0.1, 1)
)
Without rel_heights
argument in the end, both figures and title would be the same size.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.