Tiptop
Tiptop

Reputation: 623

Merging two y-axes titles in patchwork

Any ideas as to how I can "merge" two identical y-axes titles into one, and then place this y-axis title in the middle between the plot? I have succeded in merging legends by using plot_layout(guides = "collect") but I cannot seem to find anything similar for axes. In this case I would merge the two axes titles called disp_disp_disp into one.

enter image description here

mtcars

library(ggplot2)
library(patchwork)

p1 <- ggplot(mtcars) + 
  geom_point(aes(mpg, disp)) + 
  labs(x = "mpg", y = "disp_disp_disp_disp_disp")

p2 <- ggplot(mtcars) + 
  geom_boxplot(aes(gear, disp, group = gear)) + 
  labs(x = "gear", y = "disp_disp_disp_disp_disp")

p3 <- ggplot(mtcars) + 
  geom_point(aes(hp, wt, colour = mpg)) + 
  ggtitle('Plot 3')

p1 / (p2 | p3)

Upvotes: 18

Views: 12654

Answers (4)

teunbrand
teunbrand

Reputation: 37953

Since patchwork 1.2.0, you can now collect identical titles in the same direction by using axis_titles = "collect". You have to be slightly wary of some hidden nesting {patchwork} does under the hood, so you might want to use the design argument too.

library(ggplot2)
library(patchwork)

p1 <- ggplot(mtcars) + 
  geom_point(aes(mpg, disp)) + 
  labs(x = "mpg", y = "disp_disp_disp_disp_disp")

p2 <- ggplot(mtcars) + 
  geom_boxplot(aes(gear, disp, group = gear)) + 
  labs(x = "gear", y = "disp_disp_disp_disp_disp")

p3 <- ggplot(mtcars) + 
  geom_point(aes(hp, wt, colour = mpg)) + 
  ggtitle('Plot 3')

p1 + p2 + p3 + plot_layout(axis_titles = "collect", design = "AA\nBC")

Created on 2024-01-08 with reprex v2.0.2

Upvotes: 9

Henry Holm
Henry Holm

Reputation: 545

Another way to do this with gridExtra.

library(ggplot2)
library(patchwork)
library(gridExtra)

p1 <- ggplot(mtcars) + 
  geom_point(aes(mpg, disp)) + 
  labs(x = "mpg") +
  theme(axis.title.y = element_blank())

p2 <- ggplot(mtcars) + 
  geom_boxplot(aes(gear, disp, group = gear)) + 
  labs(x = "gear") +
  theme(axis.title.y = element_blank())

p3 <- ggplot(mtcars) + 
  geom_point(aes(hp, wt, colour = mpg)) + 
  ggtitle('Plot 3')


grid.arrange(patchworkGrob(p1 / (p2 | p3)), left = "disp_disp_disp_disp_disp")

enter image description here

Upvotes: 5

Allan Cameron
Allan Cameron

Reputation: 173928

I guess it would be slightly easier to strip out the y axis title before the plot is built then draw it back on after it is plotted:

library(ggplot2)
library(patchwork)

p1 <- ggplot(mtcars) + 
  geom_point(aes(mpg, disp)) + 
  labs(x = "mpg", y = "disp_disp_disp_disp_disp")

p2 <- ggplot(mtcars) + 
  geom_boxplot(aes(gear, disp, group = gear)) + 
  labs(x = "gear", y = "disp_disp_disp_disp_disp")

p3 <- ggplot(mtcars) + 
  geom_point(aes(hp, wt, colour = mpg)) + 
  ggtitle('Plot 3')

ylab <- p1$labels$y
p1$labels$y <- p2$labels$y <- " "

p1 / (p2 | p3)
grid::grid.draw(grid::textGrob(ylab, x = 0.02, rot = 90))

enter image description here

Another option if you want to avoid getting your hands dirty with grobs altogether is to specify a text-only ggplot and add that as your axis text:

p4 <- ggplot(data.frame(l = p1$labels$y, x = 1, y = 1)) +
      geom_text(aes(x, y, label = l), angle = 90) + 
      theme_void() +
      coord_cartesian(clip = "off")

p1$labels$y <- p2$labels$y <- " "

p4 + (p1 / (p2 | p3)) + plot_layout(widths = c(1, 25))

enter image description here

This behaves a bit better on resizing too.

Upvotes: 20

teunbrand
teunbrand

Reputation: 37953

The only way I could think of is to hack this at the gtable level, but I'd also be excited to learn more convenient ways. Here is the gtable method:

library(ggplot2)
library(patchwork)
library(grid)

p1 <- ggplot(mtcars) + 
  geom_point(aes(mpg, disp)) + 
  labs(x = "mpg", y = "disp_disp_disp_disp_disp")

p2 <- ggplot(mtcars) + 
  geom_boxplot(aes(gear, disp, group = gear)) + 
  labs(x = "gear", y = "disp_disp_disp_disp_disp")

p3 <- ggplot(mtcars) + 
  geom_point(aes(hp, wt, colour = mpg)) + 
  ggtitle('Plot 3')

p123 <- p1 / (p2 | p3)

# Convert to gtable
gt <- patchworkGrob(p123)

# Stretching one y-axis title
is_yaxis_title <- which(gt$layout$name == "ylab-l")
# Find new bottom position based on gtable::gtable_show_layout(gt)
gt$layout$b[is_yaxis_title] <- gt$layout$b[is_yaxis_title] + 18

# Deleting other y-axis title in sub-patchwork
is_patchwork <- which(gt$layout$name == "patchwork-table")
pw <- gt$grobs[[is_patchwork]]
pw <- gtable::gtable_filter(pw, "ylab-l", invert = TRUE)

# Set background to transparent
pw$grobs[[which(pw$layout$name == "background")[1]]]$gp$fill <- NA

# Putting sub-patchwork back into main patchwork
gt$grobs[[is_patchwork]] <- pw

# Render
grid.newpage(); grid.draw(gt)

Created on 2020-12-14 by the reprex package (v0.3.0)

Upvotes: 6

Related Questions