grid.arrange 显示多个 facet_wrap 图 - 如何使面板宽度一致?

grid.arrange to display multiple facet_wrap plots - how do I make panel widths consistent?

我有一些数据分为 25 个类别和 6 个 parent 组,每个 parent 组中的类别数量不均匀(在 3 到 5 之间)。对于每个 parent 组,我使用 facet_wrap 根据类别创建单独的面板,然后使用 grid.arrange 一起显示 parent 组图。问题是,由于每个 parent 组中的类别数量不同,绘图宽度会自动调整大小。有没有办法手动设置绘图宽度或创建空面板以使宽度一致?

简单娱乐一下:

library(dplyr)
library(gridExtra)

x <- c(1, 2, 3, 4, 1, 2)
y <- c(3, 3, 3, 3, 3, 3)
category <- c("category a", "category b", "category c", "category d", "category e", "category f")
group <- c("group one", "group one", "group one", "group one", "group two", "group two")
df <- data.frame(x, y, category, group)

group_one <- df %>% filter(group=="group one")
g1 <- ggplot(group_one, aes(x=x, y=y)) +
  geom_point() +
  facet_wrap(~category, nrow=1) +
  labs(title="Group One")

group_two <- df %>% filter(group=="group two")
g2 <- ggplot(group_two, aes(x=x, y=y)) +
  geom_point() +
  facet_wrap(~category, nrow=1) +
  labs(title="Group Two")

grid.arrange(g1, g2)

Here's what the above code produces - note uneven panel widths. How do I make the Group Two panels the same width as the Group One panels, with empty space to the right?

如果有更简单的替代方法来根据组创建带有副标题的这种类型的情节安排,我很想听听!谢谢!

一种选择是使用 patchwork 包。对于您的示例代码,您可以执行

library(patchwork)

g1 / (g2 + plot_spacer()) 

作为一种更通用的方法,您可以

  1. 将您的地块放入列表中
  2. 制作一个包含每组类别数的向量
  3. 遍历绘图列表,为每个绘图添加一个间隔符,并使用 plot_layout 设置每个子图和间隔符的宽度,以便面板对齐。

注意:为了使示例更有趣,我添加了第三组。

编辑 要按组为点着色,您可以使用命名的颜色向量,它将颜色分配给组。这样您就可以将颜色分配给 geom_point 的颜色参数。在下面的代码中,我使用了默认的 ggplot2 颜色,但您可以根据需要设置颜色。

library(dplyr)
library(ggplot2)
library(forcats)
library(stringr)

x <- c(1, 2, 3, 4, 1, 2, 1:3)
y <- c(3, 3, 3, 3, 3, 3, 1:3)
category <- c("category a", "category b", "category c", "category d", "category e", "category f", "category d", "category e", "category f")
group <- c("group one", "group one", "group one", "group one", "group two", "group two", "group three", "group three", "group three")
df <- data.frame(x, y, category, group)

# Named vector of colors
colors <- scales::hue_pal()(length(unique(df$group)))
names(colors) <- unique(df$group)

p <- df %>% 
  # Set order of group
  mutate(group = forcats::fct_inorder(group)) %>% 
  split(.$group) %>% 
  purrr::imap(function(.data, .title) {
    ggplot(.data, aes(x=x, y=y)) +
      geom_point(color = colors[.title]) +
      facet_wrap(~category, nrow=1) +
      labs(title = stringr::str_to_title(.title))  
  })

# Make a vector containing number of categories per group
ncat <- df %>% 
  group_by(group) %>% 
  summarise(n = n_distinct(category)) %>% 
  tibble::deframe()
ncat_max <- max(ncat)

library(patchwork)

p <- purrr::imap(p, function(x, y) {
  ncat <- ncat[[y]]
  n_spacer <- ncat_max - ncat
  # Add spacer to each plot and set widths
  x + plot_spacer() + plot_layout(ncol = 2, widths = c(ncat, n_spacer))
})

wrap_plots(p, nrow = length(p))