0

I have an arrange of 16 plots (4x4). The last column of this arrange is the legend, that is common for each row. I add below a fake code to create something similar to what I have:

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$grp = c('D', 'E')

df3 <- data.frame(x = 1:12, y = (1:12)^2)
df3$grp = c('F', 'G', 'H','I')

df4 <- data.frame(x = 1:12, y = (1:12)^2)
df4$grp = c('J', 'K')

p1 <- ggplot(df1, aes(x, y, color=grp)) + geom_point()
leg1 <- get_legend(p1)
leg1 <- as_ggplot(leg1)
p1 = p1 + theme(legend.position = "none",axis.title.x =element_blank(),axis.title.y =element_blank())

p2 <- ggplot(df2, aes(x, y, color=grp)) + geom_point()
leg2 <- get_legend(p2)
leg2 <- as_ggplot(leg2)
p2 = p2 + theme(legend.position = "none",axis.title.x =element_blank(),axis.title.y =element_blank())

p3 <- ggplot(df3, aes(x, y, color=grp)) + geom_point()
leg3 <- get_legend(p3)
leg3 <- as_ggplot(leg3)
p3 = p3 + theme(legend.position = "none",axis.title.x =element_blank(),axis.title.y =element_blank())

p4 <- ggplot(df4, aes(x, y, color=grp)) + geom_point()
leg4 <- get_legend(p4)
leg4 <- as_ggplot(leg4)
p4 = p4 + theme(legend.position = "none",axis.title.x =element_blank(),axis.title.y =element_blank())

plot_grid(
  p1, p1, p1, leg1, 
  p2, p2, p2, leg2,
  p3, p3, p3, leg3,
  p4, p4, p4, leg4,
  ncol = 4, rel_widths=c(2,2,2,0.5),align = "hv"
)

enter image description here

All plots share the same units for Y and X-axis, so I want to create one label for the x-axe (X) and one label for the y-axe (y). Additionally, I also want to add a label for the three first columns (from left to right) of my arrange (1st col:Column1,2nd col:Column2,3rd col:Column3).

Does anyone know how to do it?

Dekike
  • 1,264
  • 6
  • 17

2 Answers2

1

You can use textGrob:

library(gridExtra)
library(grid)
plot <- plot_grid(
  p1, p1, p1, leg1, 
  p2, p2, p2, leg2,
  p3, p3, p3, leg3,
  p4, p4, p4, leg4,
  ncol = 4, rel_widths=c(2,2,2,0.5),align = "hv"
)

y.grob <- textGrob("Common Y", 
                   gp=gpar(fontface="bold", col="blue", fontsize=15), rot=90)

x.grob <- textGrob("Common X", 
                   gp=gpar(fontface="bold", col="blue", fontsize=15))

grid.arrange(arrangeGrob(plot, left = y.grob, bottom = x.grob))

Output:

enter image description here

DavideBrex
  • 2,374
  • 1
  • 10
  • 23
  • Thanks for your time @DavideBrex, and how could I add a label for each one of the three first columns of my arrange? And if it is possible, can I move `Common Y` and `Common X` from their original position? Sometimes `Common X` is not in the middle of the plots which share the same units for x due to presence of the column with the legends. Is there a way to move the text right/left (x-axe) or up/down(y-axe)? – Dekike May 25 '20 at 07:55
  • With a label for each of the three columns you mean another x label above the common x label? – DavideBrex May 25 '20 at 08:05
  • I mean to add a common label for the first row (let's say `common row1`), another one for the second row (`common row2`) and another for the third row (`common row3`). And if possible, at the top of the arrange. – Dekike May 25 '20 at 08:07
0

I found a solution using add_sub from cowplot package. However, I had to play with different parameters for a while to get what I wanted and I don't understand well why some parameters do what they do. So this solution is tricky and you need some time playing to get what you want unless you know well the function.

Here the code I used:

P <-plot_grid(
  p1, p1, p1, leg1, 
  p2, p2, p2, leg2,
  p3, p3, p3, leg3,
  p4, p4, p4, leg4,
  ncol = 4, rel_widths=c(2,2,2,0.5),align = "hv"
)  + theme(plot.margin = margin(55, 10, 30, 30)) # I added margins to the arrange


P1 <- add_sub(P, "x axis text", x=0.5, y=-0.5, vpadding = grid::unit(0, "lines"))
ggdraw(P1)
P2 <- add_sub(P1, "y axis text", x=-0.02, y=-23, vpadding = grid::unit(-5, "lines"), angle = 90)
ggdraw(P2)
P3 <- add_sub(P2, "row 1", x=0.17, y=45, vpadding = grid::unit(0, "lines"),vjust = 1)
ggdraw(P3)
P4 <- add_sub(P3, "row 2", x=0.47, y=46, vpadding = grid::unit(0, "lines"),vjust = 1)
ggdraw(P4)
P5 <- add_sub(P4, "row 3", x=0.81, y=-25.4, vpadding = grid::unit(-2, "lines"),vjust = 1)
ggdraw(P5)

Something strange and that took me sometime until I realized is that the plot in the environment doesn't look like the plot you save. Look at what I see in Rstudio when I run the above code: enter image description here

However, when I save the plot (without changing anything), I see this plot: enter image description here

Dekike
  • 1,264
  • 6
  • 17
  • Great that you found a solution. For your information, row1, row2 and row3 are called plot titles, not labels. – DavideBrex May 25 '20 at 10:27
  • Thanks DavideBrex!! Now that you have said that, I have realized that another option is to add a title to each plot separately before arranging them, right?. Sometimes when you focus too much you lose the broad-scale... – Dekike May 25 '20 at 10:30
  • Yes that could be another solution, even though I don't know how to then keep only three titles as you want and don't show the others. Yeah that can happen to everyone :-) – DavideBrex May 25 '20 at 10:39