Draw ggplots in the plot grid by column - plot_grid() function of the cowplot package

Viewed 400

I am using the plot_grid() function of the cowplot package to draw ggplots in a grid and would like to know if there is a way to draw plots by column instead of by row?

library(ggplot2)
library(cowplot)

df <- data.frame(
    x = c(3,1,5,5,1),
    y = c(2,4,6,4,2)
)

# Create plots: say two each of path plot and polygon plot 
p <- ggplot(df)
p1 <- p + geom_path(aes(x,y)) + ggtitle("Path 1")
p2 <- p + geom_polygon(aes(x,y)) + ggtitle("Polygon 1")
p3 <- p + geom_path(aes(y,x)) + ggtitle("Path 2")
p4 <- p + geom_polygon(aes(y,x)) + ggtitle("Polygon 2")

plots <- list(p1,p2,p3,p4)
plot_grid(plotlist=plots, ncol=2) # plots are drawn by row

I would like to have plots P1 and P2 in the first column and p3 and p4 in the second column, something like:

plots <- list(p1, p3, p2, p4) # plot sequence changed
plot_grid(plotlist=plots, ncol=2)

Actually I could have 4, 6, or 8 plots. The number of rows in the plot grid will vary but will always have 2 columns. In each case I would like to fill the plot grid by column (vertically) so my first 2, 3, or 4 plots, as the case maybe, appear over each other. I would like to avoid hardcode these different permutations if I can specify something like par(mfcol = c(n,2)).

2 Answers

As you have observed, plot_grid() draws plots by row. I don't believe there's any way to change that, so if you want to maintain using plot_grid() (which would be probably most convenient), then one approach could be to change the order of the items in your list of plots to match what you need for plot_grid(), given knowledge of the number of columns.

Here's a function I have written that does that. The basic idea is to:

  • create a list of indexes for number of items in your list (i.e. 1:length(your_list)),
  • put the index numbers into a matrix with the specified number of rows,
  • read back that matrix into another vector of indexes by column
  • reorder your list according to the newly ordered indexes

I've tried to build in a way to make this work even if the number of items in your list is not divisible by the intended number of columns (like a list of 8 items arranged in 3 columns).

reorder_by_col <- function(myData, col_num) {
  x <- 1:length(myData)   # create index vector
  length(x) <- prod(dim(matrix(x, ncol=col_num)))  # adds NAs as necessary
  temp_matrix <- matrix(x, ncol=col_num, byrow = FALSE)
  new_x <- unlist(split(temp_matrix, rep(1:ncol(temp_matrix), each=row(temp_matrix))))
  names(new_x) <- NULL # not sure if we need this, but it forces an unnamed vector
  return(myData[new_x])
}

This all was written with a little help from Google and specifically answers to questions posted here and here.

You can now see the difference without reordering:

plots <- list(p1,p2,p3,p4)
plot_grid(plotlist=plots, ncol=2)

enter image description here

... and with reordering using the new method:

newPlots <- reorder_by_col(myData=plots, col_num=2)
plot_grid(plotlist=newPlots, ncol=2)

enter image description here

The argument, byrow, has now been added to plot_grid.

In the case where you would like to have num_plots < nrow * ncol the remaining spots will be empty.

You can now call:

library(ggplot2)

df <- data.frame(
  x = 1:10, y1 = 1:10, y2 = (1:10)^2, y3 = (1:10)^3, y4 = (1:10)^4
)

p1 <- ggplot(df, aes(x, y1)) + geom_point()
p2 <- ggplot(df, aes(x, y2)) + geom_point()
p3 <- ggplot(df, aes(x, y3)) + geom_point()

cowplot::plot_grid(p1, p2, p3, byrow = FALSE)
Related