2

I have arranged 16 plots (4x4) using plot_grid from cowplot package. I would like to align last column of my arrange to get all the legends to be symmetrical vertically. I have read this but I don't get what I want. I don't know why it doesn't work.

arrange <- plot_grid(P.ADelay.5m,P.ADelay.15m,P.ADelay.25m,P.ADelay.35m + theme(legend.justification = c(0,1)),
                     P.SW.5m,P.SW.15m,P.SW.25m,P.SW.35m + theme(legend.justification = c(0,1)),
                     P.Method.5m,P.Method.15m,P.Method.25m,P.Method.35m + theme(legend.justification = c(0,1)),
                     P.Period.5m,P.Period.15m,P.Period.25m,P.Period.35m + theme(legend.justification = c(0,1)),
                     P.Statistic.5m,P.Statistic.15m,P.Statistic.25m,P.Statistic.35m + theme(legend.justification = c(0,1)),
                     ncol=4, nrow = 5, align = "v" )

arrange

enter image description here

I share this fake example in which I followed the same procedure:

library(ggplot2)
library(cowplot)
library(ggpubr)
theme_set(theme_cowplot())

df1 <- data.frame(x = 1:12, y = (1:12)^2)
df1$grp = c('A', 'B', 'C')

df2 <- data.frame(x = 1:12, y = (1:12)^2)
df2$Statistic = c('none', 'Mean')

df3 <- data.frame(x = 1:12, y = (1:12)^2)
df3$Methodology = c('FFFFFF', 'GGGGGGGGG', 'HH','IIIII')

df4 <- data.frame(x = 1:12, y = (1:12)^2)
df4$Depth = c('15m', '1000m')

p1.a <- ggplot(df1, aes(x, y, color=grp)) + geom_point()  + theme(legend.position = "none")
p1.b  <- ggplot(df1, aes(x, y, color=grp)) + geom_point()

p2.a <- ggplot(df2, aes(x, y, color=Statistic)) + geom_point()  + theme(legend.position = "none")
p2.b  <- ggplot(df2, aes(x, y, color=Statistic)) + geom_point()

p3.a <- ggplot(df3, aes(x, y, color=Methodology)) + geom_point()  + theme(legend.position = "none")
p3.b  <- ggplot(df3, aes(x, y, color=Methodology)) + geom_point()

p4.a <- ggplot(df4, aes(x, y, color=Depth)) + geom_point()  + theme(legend.position = "none")
p4.b  <- ggplot(df4, aes(x, y, color=Depth)) + geom_point()

plot_grid(
  p1.a, p1.a, p1.a, p1.b + theme(legend.justification = c(0,1)),
  p2.a, p2.a, p2.a, p2.b + theme(legend.justification = c(0,1)),
  p3.a, p3.a, p3.a, p3.b + theme(legend.justification = c(0,1)),
  p4.a, p4.a, p4.a, p4.b + theme(legend.justification = c(0,1)),
  ncol = 4,align = "hv"
)

of I get the message "Warning message: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned."

How should I do to align legends?

Dekike
  • 1,264
  • 6
  • 17
  • You probably need `axis = 'lr'` or `axis = 'tblr'` in your `plot_grid()` call – Tung May 25 '20 at 14:54
  • You are right, using either `axis = 'lr'` or `axis = 'tblr'` I get the legends to be aligned. However, the space among columns increase sharply!!! If it is not one thing, it is another!! If I removed the `v` in `align="hv"`, then, the legends lose their alignment. If I remove either `axis = 'lr'` or `axis = 'tblr'`, I also lose the alignment. However, as I already told you, the alignment that I get is rare if I keep `axis = 'lr'`/`axis = 'tblr'` and `align="hv"`. Do you know why? It is just to know it. I am gonna try your other proposal now. – Dekike May 25 '20 at 15:17

2 Answers2

2

You can use the patchwork package. I find it a lot faster than cowplot.

library(ggplot2)
library(cowplot)
#> 
#> ********************************************************
#> Note: As of version 1.0.0, cowplot does not change the
#>   default ggplot2 theme anymore. To recover the previous
#>   behavior, execute:
#>   theme_set(theme_cowplot())
#> ********************************************************
theme_set(theme_cowplot())

df1 <- data.frame(x = 1:12, y = (1:12)^2)
df1$grp = c('A', 'B', 'C')

df2 <- data.frame(x = 1:12, y = (1:12)^2)
df2$Statistic = c('none', 'Mean')

df3 <- data.frame(x = 1:12, y = (1:12)^2)
df3$Methodology = c('FFFFFF', 'GGGGGGGGG', 'HH','IIIII')

df4 <- data.frame(x = 1:12, y = (1:12)^2)
df4$Depth = c('15m', '1000m')

p1.a <- ggplot(df1, aes(x, y, color=grp)) + geom_point()  + theme(legend.position = "none")
p1.b  <- ggplot(df1, aes(x, y, color=grp)) + geom_point() + theme(legend.justification = c(0,1)) 

p2.a <- ggplot(df2, aes(x, y, color=Statistic)) + geom_point()  + theme(legend.position = "none")
p2.b  <- ggplot(df2, aes(x, y, color=Statistic)) + geom_point() + theme(legend.justification = c(0,1))

p3.a <- ggplot(df3, aes(x, y, color=Methodology)) + geom_point()  + theme(legend.position = "none")
p3.b  <- ggplot(df3, aes(x, y, color=Methodology)) + geom_point() + theme(legend.justification = c(0,1))

p4.a <- ggplot(df4, aes(x, y, color=Depth)) + geom_point()  + theme(legend.position = "none")
p4.b  <- ggplot(df4, aes(x, y, color=Depth)) + geom_point() + theme(legend.justification = c(0,1))


library(patchwork)
#> 
#> Attaching package: 'patchwork'
#> The following object is masked from 'package:cowplot':
#> 
#>     align_plots

# define plot layout 4 x 4
layout <- "
ABCD
EFGH
IJKL
MNOP
"

p1.a + p1.a + p1.a + p1.b +
p2.a + p2.a + p2.a + p2.b +
p3.a + p3.a + p3.a + p3.b +
p4.a + p4.a + p4.a + p4.b +
  plot_layout(design = layout)

Created on 2020-05-25 by the reprex package (v0.3.0)

Tung
  • 26,371
  • 7
  • 91
  • 115
  • Thanks @Tung, can you tell me how `patchwork` works? I mean, I see you wrote `layout <- " ABCD EFGH IJKL MNOP "'' Is this for indicating the order of the plots? Thanks in advance! – Dekike May 25 '20 at 14:57
  • Yes, it tells where to put each individual plot in that matrix. You can replace `ABCD` with `AABB` or `AAAA` to see how the plot would change – Tung May 25 '20 at 15:05
  • This looks nicer than other alternatives I have used. However, the alignment is not perfect. I have updated the post and I have added a picture with my actual arrange of plots using your proposal (`patchwork package`). Do you know why the alignment is not perfect? – Dekike May 25 '20 at 15:31
  • You have to play around with the way you setup your plot legends. I don't think `patchwork` can do anything better – Tung May 25 '20 at 17:56
2

There are probably multiple ways to handle this, but one option is to place the legends in their own column of the grid:

p1.a <- ggplot(df1, aes(x, y, color=grp)) + geom_point() + theme(legend.justification = c(0,0.8))
p1.leg  <- as_ggplot(get_legend(p1.a))
p1.a <- p1.a + theme(legend.position = "none")

p2.a <- ggplot(df2, aes(x, y, color=Statistic)) + geom_point() + theme(legend.justification = c(0,0.8))
p2.leg  <- as_ggplot(get_legend(p2.a))
p2.a <- p2.a + theme(legend.position = "none")

p3.a <- ggplot(df3, aes(x, y, color=Methodology)) + geom_point() + theme(legend.justification = c(0,0.8))
p3.leg  <- as_ggplot(get_legend(p3.a))
p3.a <- p3.a + theme(legend.position = "none")

p4.a <- ggplot(df4, aes(x, y, color=Depth)) + geom_point() + theme(legend.justification = c(0,0.8))
p4.leg  <- as_ggplot(get_legend(p4.a))
p4.a <- p4.a + theme(legend.position = "none")

plot_grid(
  p1.a, p1.a, p1.a, p1.a, p1.leg,
  p2.a, p2.a, p2.a, p2.a, p2.leg,
  p3.a, p3.a, p3.a, p3.a, p3.leg,
  p4.a, p4.a, p4.a, p4.a, p4.leg,
  ncol = 5, align = "hv"
)

enter image description here

dww
  • 30,425
  • 5
  • 68
  • 111
  • Thank you @dww for looking at this. I really appreciate it. Do you know if there is any way to leave only one `X` label in the X-axe and one `Y` label in the Y-axe and both centred, and also to add a name to each column? In this example, as in my real data, all plots share the same units for the x-axe and for the y-axe. What changes is that each row uses a different legend and each column is for a different variable. – Dekike May 26 '20 at 06:42
  • In this post (https://stackoverflow.com/questions/61997737/how-to-add-one-common-y-and-x-label-for-an-arrange-of-plots-and-also-a-label-for) I asked how to get it. In the end I found a solution by myself but it seems tricky. I ask you just in case there is a easier way. – Dekike May 26 '20 at 06:42