0

I'm trying to find a nice layout for my panelplot in R. I have five subplots and want a matrix with 2 columns and 3 rows. The first subplot is supposed to be centered in row 1, the remaining four subplots go into the second and third row. I want every subplot to have the same size.

library(mgcv)
library(ggplot2)
library(grid)
theme_set(theme_bw())

p1 <- ggplot(ChickWeight, aes(x=Time, y=weight, colour=Diet, group=Chick)) +
geom_line() +
ggtitle("Growth curve for individual chicks")

p2 <- ggplot(ChickWeight, aes(x=Time, y=weight, colour=Diet, group=Chick)) +
geom_line() +
ggtitle("Growth curve for individual chicks")

p3 <- ggplot(ChickWeight, aes(x=Time, y=weight, colour=Diet, group=Chick)) +
geom_line() +
ggtitle("Growth curve for individual chicks")

p5 <- ggplot(ChickWeight, aes(x=Time, y=weight, colour=Diet, group=Chick)) +
geom_line() +
ggtitle("Growth curve for individual chicks")

p6 <- ggplot(ChickWeight, aes(x=Time, y=weight, colour=Diet, group=Chick)) +
geom_line() +
ggtitle("Growth curve for individual chicks")

p4 <- plot.new()

# Define multiplot function
multiplot <- function(..., plotlist = NULL, file, cols = 1, layout = NULL) {
  require(grid)

  plots <- c(list(...), plotlist)

  numPlots = length(plots)

  if (is.null(layout)) {
    layout <- matrix(seq(1, cols * ceiling(numPlots/cols)),
                ncol = cols, nrow = ceiling(numPlots/cols))
  }

  if (numPlots == 1) {
    print(plots[[1]])

  } else {
    grid.newpage()
    pushViewport(viewport(layout = grid.layout(nrow(layout),  ncol(layout))))

    for (i in 1:numPlots) {
      matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))

      print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
                                  layout.pos.col = matchidx$col))
    }
  }
}

pdf("test.pdf")
# # Plot multiplot
multiplot(p1, p2, p3, p4, p5, p6, cols = 2)

For simplicity, I didn't print the complete plot commands.

pogibas
  • 27,303
  • 19
  • 84
  • 117
scriptgirl_3000
  • 161
  • 3
  • 16
  • It would be easier to help you if you provided a minimal [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example). Since we can't copy/paste this code to run it, it's not easy to test possible solutions to your problem. Remove parts that aren't directly related to your layout question. – MrFlick Jan 04 '18 at 16:14
  • Yes, sorry, my mistake! – scriptgirl_3000 Jan 04 '18 at 16:35
  • Suggested dupes: [Combined plot of ggplot2 (Not in a single Plot), using par() or layout() function?](https://stackoverflow.com/q/9490482/903061) and [Creating arbitrary panes in ggplot2](https://stackoverflow.com/q/7993722/903061). – Gregor Thomas Jan 04 '18 at 16:45
  • Ok, I used the layout function. However, it'll either put the first plot in the upper left corner (list(p1, 1, 1)), or it'll stretch the subplot in the first row so it's double the size of the other ones (list(p1, 1, 1:2)). I want every subplot to be the same size though and the first one centered – scriptgirl_3000 Jan 04 '18 at 17:17

2 Answers2

2

One way to arrange multiple plots is with multipanelfigure package.

Create example plots:

library(ggplot2)
plots <- list()
for(i in 1:5) {
    plots[[i]] <- ggplot() + ggtitle(paste("My plot:", i))
}

Create panel for plots:

library(multipanelfigure)
figure <- multi_panel_figure(columns = 4, rows = 3, panel_label_type = "none")

We use function multi_panel_figure() with specified number of columns and rows. You needed only 2 columns, but as you want to center one plot we will use 4 columns (center will be columns 2 & 3).

Add plots on panel:

figure %<>%
    fill_panel(plots[[1]], column = 2:3, row = 1) %<>%
    fill_panel(plots[[2]], column = 1:2, row = 2) %<>%
    fill_panel(plots[[3]], column = 3:4, row = 2) %<>%
    fill_panel(plots[[4]], column = 1:2, row = 3) %<>%
    fill_panel(plots[[5]], column = 3:4, row = 3)

Result:

enter image description here

pogibas
  • 27,303
  • 19
  • 84
  • 117
  • 1
    Nice answer, might be worth adding to [this question](https://stackoverflow.com/q/9490482/903061) and [this one](https://stackoverflow.com/q/7993722/903061). – Gregor Thomas Jan 04 '18 at 16:44
  • Thanks, it gives me the error Error in library(multipanelfigure) : there is no package called ‘multipanelfigure’ though? – scriptgirl_3000 Jan 04 '18 at 16:55
  • @scriptgirl_3000 You have to install it :-) Use `install.packages("multipanelfigure")` – pogibas Jan 04 '18 at 16:56
  • @scriptgirl_3000 also see the link I added ("Vignettes"), this package can do many cool things – pogibas Jan 04 '18 at 16:57
  • Ugh, ok thanks. What a stupid question :-) Hm. I can't seem to install it though (Error in install.packages("multipanelfigure") : unable to install packages) – scriptgirl_3000 Jan 04 '18 at 17:02
  • @scriptgirl_3000 is there any way I can improve my answer so you would accept it? – pogibas Feb 02 '18 at 20:37
0

Your solution did not work for me because I couldn't install multipanelfigure, however this worked (if anyone has similar problems). It's basically the same what PoGibas did, but without the multipanelpackage:

[...]
pushViewport(viewport(layout = grid.layout(3, 4)))
vplayout <- function(x, y) viewport(layout.pos.row = x, layout.pos.col = y)
print(p1, vp = vplayout(1, 2:3))
print(p2, vp = vplayout(2, 1:2))
print(p3, vp = vplayout(2, 3:4))
print(p4, vp = vplayout(3, 1:2))
print(p5, vp = vplayout(3, 3:4))
scriptgirl_3000
  • 161
  • 3
  • 16