答案在grid 和gtable 包中。情节中的所有内容都按特定顺序排列,如果您稍微挖掘一下,您可以找到所有内容的位置。
library('gtable')
library('grid')
library('magrittr') # for the %>% that I love so well
# First get the grob
z <- ggplotGrob(p)
这个操作的最终目的是覆盖顶部的 facet 标签,但诀窍是这两个 facet 都存在于网格空间的同一行上。它们是表中的表(查看名称为“strip”的行,还要注意zeroGrob;这些稍后会有用):
z
## TableGrob (13 x 14) "layout": 34 grobs
## z cells name grob
## 1 0 ( 1-13, 1-14) background rect[plot.background..rect.522]
## 2 1 ( 7- 7, 4- 4) panel-1-1 gTree[panel-1.gTree.292]
...
## 20 3 ( 7- 7,12-12) axis-r-1 zeroGrob[NULL]
## 21 3 ( 9- 9,12-12) axis-r-2 zeroGrob[NULL]
## 22 2 ( 6- 6, 4- 4) strip-t-1 gtable[strip]
## 23 2 ( 6- 6, 6- 6) strip-t-2 gtable[strip]
## 24 2 ( 6- 6, 8- 8) strip-t-3 gtable[strip]
## 25 2 ( 6- 6,10-10) strip-t-4 gtable[strip]
## 26 2 ( 7- 7,11-11) strip-r-1 gtable[strip]
## 27 2 ( 9- 9,11-11) strip-r-2 gtable[strip]
...
## 32 8 ( 3- 3, 4-10) subtitle zeroGrob[plot.subtitle..zeroGrob.519]
## 33 9 ( 2- 2, 4-10) title zeroGrob[plot.title..zeroGrob.518]
## 34 10 (12-12, 4-10) caption zeroGrob[plot.caption..zeroGrob.520]
如果放大第一条,可以看到嵌套结构:
z$grob[[22]]
## TableGrob (2 x 1) "strip": 2 grobs
## z cells name grob
## 1 1 (1-1,1-1) strip absoluteGrob[strip.absoluteGrob.451]
## 2 2 (2-2,1-1) strip absoluteGrob[strip.absoluteGrob.475]
对于每个 grob,我们有一个对象列出了它的绘制顺序 (z)、网格中的位置 (cells)、标签 (name)和几何图形(grob)。
由于我们可以在 gtables 中创建 gtables,我们将使用它来绘制原始图。首先,我们需要在图中找到需要替换的位置。
# Find the location of the strips in the main plot
locations <- grep("strip-t", z$layout$name)
# Filter out the strips (trim = FALSE is important here for positions relative to the main plot)
strip <- gtable_filter(z, "strip-t", trim = FALSE)
# Gathering our positions for the main plot
top <- strip$layout$t[1]
l <- strip$layout$l[c(1, 3)]
r <- strip$layout$r[c(2, 4)]
一旦我们有了位置,我们需要创建一个替换表。我们可以使用列表矩阵来做到这一点(是的,这很奇怪。随它去吧)。在我们的例子中,这个矩阵需要有三列和两行,因为有两个方面和它们之间的间隙。由于我们稍后将替换矩阵中的数据,因此我们将使用zeroGrobs 创建一个:
mat <- matrix(vector("list", length = 6), nrow = 2)
mat[] <- list(zeroGrob())
# The separator for the facets has zero width
res <- gtable_matrix("toprow", mat, unit(c(1, 0, 1), "null"), unit(c(1, 1), "null"))
蒙版分两步创建,覆盖第一个构面组,然后覆盖第二个构面组。在第一部分中,我们使用之前记录的位置从原始图中获取适当的 grob,并将其添加到我们的替换矩阵 res 的顶部,跨越整个长度。然后,我们将该矩阵添加到绘图顶部。
# Adding the first layer
zz <- res %>%
gtable_add_grob(z$grobs[[locations[1]]]$grobs[[1]], 1, 1, 1, 3) %>%
gtable_add_grob(z, ., t = top, l = l[1], b = top, r = r[1], name = c("add-strip"))
# Adding the second layer (note the indices)
pp <- gtable_add_grob(res, z$grobs[[locations[3]]]$grobs[[1]], 1, 1, 1, 3) %>%
gtable_add_grob(zz, ., t = top, l = l[2], b = top, r = r[2], name = c("add-strip"))
# Plotting
grid.newpage()
print(grid.draw(pp))