如何在 R 中的网格上的特定位置排列图?

How to arrange plots in specific positions on a grid in R?

我正在尝试使用特定坐标将多个图(不同大小)绘制到网格上。为此,我正在使用 treemap 包创建一个树状图来获取坐标,然后使用这些坐标,我试图放置我的个人地块。希望我下面的例子能更好地解释我的问题。

首先,我创建了一些条形图,然后创建了一个树状图,如下所示:

library(ggplot2)
library(treemap)
#create data
df <- data.frame(var1 = c("A", "B", "C"),
             var2 = runif(3),
             var3 = runif(3),
             var4 = runif(3),
             size = c(10, 5, 3),
             labels = c(1:3))
# Basic barplot
p1 <- ggplot(data=df, aes(x=var1, y=var2)) +
   geom_bar(stat="identity")
p2 <- ggplot(data=df, aes(x=var1, y=var3)) +
   geom_bar(stat="identity")
p3 <- ggplot(data=df, aes(x=var1, y=var4)) +
  geom_bar(stat="identity")

#create treemap
tm <- treemap(df,
       index = "labels",
       vSize = "size",
       palette = "Set2")

如果我们看一下树图对象 tm,我们可以看到它提供了如下所示树图的坐标,其中 x0y0wh是坐标。

> tm$tm
  labels vSize vColor stdErr vColorValue level        x0    y0         w     h   color
1      1    10      1     10          NA     1 0.0000000 0.000 0.5555556 1.000 #66C2A5
2      2     5      1      5          NA     1 0.5555556 0.375 0.4444444 0.625 #FC8D62
3      3     3      1      3          NA     1 0.5555556 0.000 0.4444444 0.375 #8DA0CB

所以,我想做的是将我的三个条形图 p1p2p3 放入树图中,这样 p1 就会位于树状图的 1 位置.... p2 将位于 2 位置等...

为清楚起见,我想要的结果如下所示:

关于我如何做到这一点有什么建议吗?我尝试使用 patchwork 包,但 运行 涉及绘图重叠的问题......但我愿意接受使用任何包的建议(例如 gridExtra 或只是 ggplot

编辑 稍微澄清一下,根据彼得在下面给出的关于 patchwork 包的答案,我无法手动输入坐标作为绘图布局(我最初使用 area 中的函数 patchwork 并将树图的坐标输入 area 函数)。但是,正如下面评论中提到的,如果我有很多条形图,并且树状图的大小和形状发生变化,那么我就无法手动输入布局值。我正在尝试找到一种自动化流程的方法

patchwork 似乎工作正常:

library(patchwork)
library(ggplot2)


design <- "
  11122
  11122
  11133
"
p1 + p2 + p3 + plot_layout(design = design)

reprex package (v2.0.1)

于 2021-11-28 创建

这需要一些算法,并不完美,但应该是使用 patchwork 更复杂的布局选项的开始。有几个技巧可以解决:

  • treemap 根据视口缩放其尺寸,这意味着它计算的位置取决于观察者,例如RStudio 的绘图窗格。相反,这不是绝对必要的,但您可能应该决定纵横比以确保框的位置是您想要的。
  • 您需要将小数位和大小转换为整数,不是简单地乘以某个数字并四舍五入,而是找到它们的小数当量的分母并乘以它。例如,第一个框的宽度为 0.55555,即 5/9;为了得到整数,我们需要知道这个盒子应该是 5 个单位宽,总共 9 个单位。取最大宽高是任意的;关键是要得到一个不等于 1.0 的值。
  • 从不同的维度中加减 1 不是最好的方法,但却是一种足够简单的方法来获得例如一个盒子从 1 到 5,下一个盒子从 6 到 9。
  • 地块的顺序不正确,但大小是...还没弄明白为什么,但为了尝试诊断这个问题,我为每个地块添加了标签。
library(ggplot2)
library(treemap)
library(dplyr)

asp <- 1.25
tm <- treemap(df, index = "labels", vSize = "size", palette = "Set2", sortID = "labels",
              aspRatio = asp)
denoms <- tm$tm %>%
  tidyr::pivot_longer(w:h, names_to = "direction") %>%
  filter(value < 1) %>%
  group_by(direction) %>%
  slice_max(value, n = 1) %>%
  mutate(denom = MASS::fractions(value) %>%
           stringr::str_extract("\d+$") %>%
           as.numeric()) %>%
  select(direction, denom) %>%
  tibble::deframe()
denoms
#> h w 
#> 8 9
areas <- tm$tm %>%
  mutate(across(c(x0, w), ~. * denoms[["w"]]),
         across(c(y0, h), ~. * denoms[["h"]]),
         top = y0 + 1,
         left = x0 + 1,
         bottom = top + h - 1,
         right = left + w - 1) %>%
  select(top:right) %>%
  purrr::pmap(function(top, left, bottom, right) patchwork::area(top, left, bottom, right)) %>%
  purrr::reduce(c)

patchwork::wrap_plots(p1, p2, p3, design = areas)