thomasp85 / patchwork

The Composer of ggplots
https://patchwork.data-imaginist.com
Other
2.45k stars 160 forks source link

Gap between axis label and text if adjacent plot has vertical axis text #285

Closed kotliary closed 1 week ago

kotliary commented 2 years ago

Please check the following code. Is there a way to remove this gap ignoring the other plots?

library(tidyverse)

df1 = data.frame(Group = factor(1:10), Value = runif(10))
df2 = data.frame(Group = factor(1:10), Long_label_A = runif(10), Long_label_B = runif(10), Long_label_C = runif(10)) %>% 
  gather(Label, X, -Group)

p1 = ggplot(df1, aes(Value, Group)) + 
  geom_col(orientation = "y", position = "identity")

p2 = ggplot(df2, aes(Label, Group, fill = X)) + 
  geom_tile() +
  ylab("") +
  theme_void() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))

library(patchwork)

p1 + p2 + plot_layout(nrow = 1, widths = c(0.9, 0.1))

Created on 2021-12-01 by the reprex package (v2.0.0)

kotliary commented 2 years ago

It's the same issue as reported in #272 and #276.

Generalized commented 2 years ago

I have a similar issue, only horizontally. I found a quick and dirty workaround, maybe it will help someone, as the original positioning of the axis title looks ugly.

Original plot: obraz

and after the workaround:

final_plot[[1]] <- final_plot[[1]] + theme(axis.title.y = element_text(vjust = -50)) final_plot

obraz

kotliary commented 2 years ago

Good workaround. Thanks!

thomasp85 commented 1 year ago

@kotliary did the above solve your question or did you mean to expand the plot to fill out the white space?

kotliary commented 10 months ago

@thomasp85 sorry for missing your question. No, I don't want to expand the plot to fill the white space. I want to move the axis title closer to the axis. The workaround from @Generalized solved my issue, but the vjust value need to be adjusted manually. It would be nice if the position of axis title can be automatically adjusted by the patchwork.

Yunuuuu commented 1 month ago

I want to remove the gap between axis title and axis labels automatically. I tried to use following codes but it makes the axis position strange though it remove the gaps between the axis title and axis text. Could you help me to fix this?

library(tidyverse)
library(patchwork)

df1 <- data.frame(Group = factor(1:10), Value = runif(10))
df2 <- data.frame(Group = factor(1:10), Long_label_A = runif(10), Long_label_B = runif(10), Long_label_C = runif(10)) %>%
  gather(Label, X, -Group)

p1 <- ggplot(df1, aes(Value, Group)) +
  geom_col(orientation = "y", position = "identity")

p2 <- ggplot(df2, aes(Label, Group, fill = X)) +
  geom_tile() +
  ylab("") +
  theme_void() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))

gt <- patchwork::patchworkGrob(
  p1 + p2 + plot_layout(nrow = 1, widths = c(0.9, 0.1))
)
n_plots <- sub(
  "^.+-(\\d+)$", "\\1",
  grep("-\\d+$", gt$layout$name, value = TRUE)
)
n_plots <- unique(n_plots)
for (i in n_plots) {
  for (position in c("t", "l", "b", "r")) {
    lab_pattern <- switch(position,
      t = ,
      b = paste("xlab", position, i, sep = "-"),
      l = ,
      r = paste("ylab", position, i, sep = "-")
    )
    axis_pattern <- switch(position,
      t = ,
      b = paste("axis", position, i, sep = "-"),
      l = ,
      r = paste("axis", position, i, sep = "-")
    )
    # this grob contain both axis and axis title
    grob <- gtable::gtable_filter(
      gt, paste(lab_pattern, axis_pattern, sep = "|")
    )
    no_grobs <- vapply(.subset2(grob, "grobs"), inherits,
      logical(1L),
      what = "zeroGrob"
    )
    if (all(no_grobs)) next

    # integrate axis and lab grobs ------------------------------
    layout <- .subset2(gt, "layout")
    lab_index <- which(grepl(lab_pattern, .subset2(layout, "name")))
    axis_index <- which(grepl(axis_pattern, .subset2(layout, "name")))
    area <- layout[axis_index, , drop = FALSE]
    t <- .subset2(area, "t")
    l <- .subset2(area, "l")
    b <- .subset2(area, "b")
    r <- .subset2(area, "r")
    grob_axis_index <- which(grepl(axis_pattern, .subset2(grob$layout, "name")))
    gt$grobs[[axis_index]] <- ggplot2::zeroGrob()
    gt$grobs[[lab_index]] <- ggplot2::zeroGrob()
    if (position == "t") {
      grob$heights[grob_axis_index] <- grid::grobHeight(
        grob$grobs[[grob_axis_index]]
      )
    }
    if (position == "l") {
      grob$widths[grob_axis_index] <- grid::grobWidth(
        grob$grobs[[grob_axis_index]]
      )
    }
    if (position == "b") {
      grob$heights[grob_axis_index] <- grid::grobHeight(
        grob$grobs[[grob_axis_index]]
      )
    }
    if (position == "r") {
      grob$widths[grob_axis_index] <- grid::grobWidth(
        grob$grobs[[grob_axis_index]]
      )
    }
    gt$grobs[[axis_index]] <- grob
  }
}
grid::grid.newpage()
grid::grid.draw(gt)

image

thomasp85 commented 1 week ago

This is now fixable with free(..., type = "label")