---
title: "Arranging plots in a grid"
author: "Claus O. Wilke"
date: "`r Sys.Date()`"
output:
  rmarkdown::html_vignette:
    fig_width: 4
vignette: >
  %\VignetteIndexEntry{Arranging plots in a grid}
  %\VignetteEngine{knitr::rmarkdown}
  %\usepackage[utf8]{inputenc}
---

# Basic use of `plot_grid()`

The `plot_grid()` function provides a simple interface for arranging plots into a grid and adding labels to them:
```{r, message=FALSE, fig.width=6.8, fig.height=2.55}
require(cowplot)
theme_set(theme_cowplot(font_size=12)) # reduce default font size
plot.mpg <- ggplot(mpg, aes(x = cty, y = hwy, colour = factor(cyl))) + 
  geom_point(size=2.5)
plot.diamonds <- ggplot(diamonds, aes(clarity, fill = cut)) + geom_bar() +
  theme(axis.text.x = element_text(angle=70, vjust=0.5))
plot_grid(plot.mpg, plot.diamonds, labels = c('A', 'B'))
```

If you specify the labels as `labels="AUTO"` or `labels="auto"` then labels will be auto-generated in upper or lower case, respectively:
```{r, message=FALSE, fig.width=6.8, fig.height=2.55}
plot_grid(plot.mpg, plot.diamonds, labels = "AUTO")
```

```{r, message=FALSE, fig.width=6.8, fig.height=2.55}
plot_grid(plot.mpg, plot.diamonds, labels = "auto")
```

By default, the plots are not aligned, but in many cases they can be aligned via the `align` option:
```{r, message=FALSE, fig.width=6.8, fig.height=2.55}
plot_grid(plot.mpg, plot.diamonds, labels = "AUTO", align = 'h')
```

```{r, message=FALSE, fig.width=3.9, fig.height=5.1}
plot_grid(plot.mpg, plot.diamonds, labels = "AUTO", ncol = 1, align = 'v')
```

For more complex combinations of plots that don't have the same number of visual elements, alignment becomes more tricky. In those cases, you also have to specify the margin along which you want to align, via the `axis` option. For example, to align a faceted and a non-faceted plot such that the left axes are aligned, we can use the following:
```{r, message=FALSE, fig.width=5, fig.height=5}
plot.iris <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) + 
  geom_point() + facet_grid(. ~ Species) + stat_smooth(method = "lm") +
  background_grid(major = 'y', minor = "none") + # add thin horizontal lines 
  panel_border() # and a border around each panel
plot_grid(plot.iris, plot.mpg, labels = "AUTO", ncol = 1, 
          align = 'v', axis = 'l') # aligning vertically along the left axis
```


# Supported plot formats

The function `plot_grid()` can handle several different plot formats, including the classes `ggplot` (created by the `ggplot` function), `gtable` (created from `ggplot` or from other grid graphics objects such as `grob` and `gTree` objects) and, if the package **gridGraphics** is installed, `recordedplot` (returned by `recordPlot()`).  Since the code to create a `recordedPlot` object would ordinarily create an unwanted plot or file, a function creating a `graphics` based plot (`plot`, `image`, ...) can be passed as well.

For example, the following creates a `recordedPlot` object by recording a previous plot (`plot(sqrt)`):
```{r, message=FALSE, results="hold", collapse=TRUE}
par(xpd = NA, # switch off clipping, necessary to always see axis labels
    bg = "transparent", # switch off background to avoid obscuring adjacent plots
    oma = c(2, 2, 0, 0), # move plot to the right and up
    mgp = c(2, 1, 0) # move axis labels closer to axis
  ) 
plot(sqrt) # plot the square root function
recordedplot <- recordPlot() # record the previous plot
```

Next we define a function that creates a plot:
```{r, message=FALSE}
plotfunc <- function() image(volcano) # define the function
plotfunc() # call the function to make the plot
```

And finally a plot (a circle) drawn directly with grid:
```{r, message=FALSE}
gcircle <- grid::circleGrob()
ggdraw(gcircle)
```

Now we combine all these plots with `plot_grid()`:
```{r, message=FALSE, fig.width=7, fig.height=5}
plot_grid(plot.mpg, recordedplot, plotfunc, gcircle, labels = "AUTO", hjust = 0, vjust = 1,
          scale = c(1., 1., 0.9, 0.9))
```
Note that the various alignment functions of `plot_grid()` only work with plots generated by `ggplot`, not with any of the other supported plot types.

# Fine-tuning the plot appearance

You can adjust the label size via the `label_size` option. Default is 14, so larger values will make the labels larger and smaller values will make them smaller:
```{r, message=FALSE, fig.width=6.8, fig.height=2.55}
plot_grid(plot.mpg, plot.diamonds, labels = "AUTO", align = 'h', label_size = 12)
```

You can also adjust the font family, font face, and color of the labels:
```{r, message=FALSE, fig.width=6.8, fig.height=2.55}
plot_grid(plot.mpg, plot.diamonds, labels = "AUTO", align = 'h', label_fontfamily = "serif",
          label_fontface = "plain", label_colour = "blue")
```


Labels can be moved via the `label_x` and `label_y` arguments, and justified via the `hjust` and `vjust` arguments. For example, to place labels into the bottom left corner, you can write:
```{r, message=FALSE, fig.width=6.8, fig.height=2.55}
plot_grid(plot.mpg, plot.diamonds, labels = "AUTO", align = 'h', label_size = 12,
          label_x = 0, label_y = 0, hjust = -0.5, vjust = -0.5 )
```

It is possible to adjust individual labels one by one by passing vectors of adjustment values to the options `label_x`, `label_y`, `hjust`, and `vjust` (example not shown). 

You can also adjust the relative widths and heights of rows and columns:
```{r, message=FALSE, fig.width=6.8, fig.height=2.55}
plot_grid(plot.mpg, plot.diamonds, labels = "AUTO", align = 'h', rel_widths = c(1, 1.3))
```


# Nested plot grids

If you want to generate a plot arrangement that is not a simple grid, you may insert one `plot_grid()` plot into another:
```{r, message=FALSE, fig.width=7.65, fig.height=5.1}
bottom_row <- plot_grid(plot.mpg, plot.diamonds, labels = c('B', 'C'), align = 'h', rel_widths = c(1, 1.3))
plot_grid(plot.iris, bottom_row, labels = c('A', ''), ncol = 1, rel_heights = c(1, 1.2))
```

(Notice how we used `rel_heights` to make to bottom row higher than the top row. Also, we can't auto-generate the labels in this case.)
Alignment is a bit tricky in this case. However, it can be achieved using the `align_plots()` function. The trick is to first align the top-row plot (`plot.iris`) and the first botton-row plot (`plot.mpg`) vertically along the left axis, using the `align_plots()` function. Then these aligned plots can be passed to `plot_grid()`. Note that this vertical alignment does not interfere with the horizontal alignment of the bottom row.

```{r, message=FALSE, fig.width=7.65, fig.height=5.1}
# first align the top-row plot (plot.iris) with the left-most plot of the
# bottom row (plot.mpg)
plots <- align_plots(plot.mpg, plot.iris, align = 'v', axis = 'l')
# then build the bottom row
bottom_row <- plot_grid(plots[[1]], plot.diamonds, 
                        labels = c('B', 'C'), align = 'h', rel_widths = c(1, 1.3))
# then combine with the top row for final plot
plot_grid(plots[[2]], bottom_row, labels = c('A', ''), ncol = 1, rel_heights = c(1, 1.2))
```
