ggplot2 跨组中的嵌套方面 [英] Nested facets in ggplot2 spanning groups

查看:23
本文介绍了ggplot2 跨组中的嵌套方面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一种情况,我想创建一个由三个分组变量分面的图.为此,我将简单地使用 facet_grid(f1 ~ f2 + f3),但这里的问题是 f2 的标签是多余的,让它们跨越多个方面会更好对于嵌套在 f2 中的 f3.

I encountered a situation in which I want to create a plot that was facetted by three grouping variables. To do so, I would simply use facet_grid(f1 ~ f2 + f3), but the issue here is that the labels for f2 would be redundant, and it would be much better to have them span the facets for f3 nested within f2.

MWE:

library('tibble')
library('ggplot2')
df <- tribble(
  ~x, ~y, ~f1, ~f2, ~f3,
  0.5, 0.5, "a", "a", "a",
  0.5, 0.5, "b", "a", "a",
  0.5, 0.5, "a", "b", "a",
  0.5, 0.5, "b", "b", "a",
  0.5, 0.5, "a", "a", "b",
  0.5, 0.5, "b", "a", "b",
  0.5, 0.5, "a", "b", "b",
  0.5, 0.5, "b", "b", "b"
)


p <- ggplot(df, aes(x = x, y = y)) +
  geom_point() +
  facet_grid(f1 ~ f2 + f3)

同样,我希望将 f2 的标签组合起来,这样它们就不会那么多余了.

Again, I'm looking to combine the labels for f2 so that they are not so redundant.

这与其他问题的不同之处在于,它询问如何使用现有分组来修改方面而不是添加新方面.

This is different from other questions in that it asks how to use the existing groupings to modify a facet as opposed to adding a new one.

推荐答案

解决方案就在 gridgtable 包中.情节中的所有内容都按特定顺序排列,如果您稍微挖掘一下,您就可以找到所有内容.

The answer to this lies within the grid and gtable packages. Everything in the plot is laid out in a particular order and you can find where everything is if you dig a little.

library('gtable')
library('grid')
library('magrittr') # for the %>% that I love so well

# First get the grob
z <- ggplotGrob(p) 

这个操作的最终目标是覆盖顶部的facet标签,但诀窍是这两个facet都存在于网格空间的同一行上.它们是表中的表(查看名称为strip"的行,还要注意 zeroGrob;这些稍后会很有用):

The ultimate goal of this operation is to overlay the top facet label, but the trick is that both of these facets exist on the same row in the grid space. They are a table within a table (look at the rows with the name "strip", also take note of the zeroGrob; these will be useful later):

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]

如果放大到第一个条带,您可以看到嵌套结构:

If you zoom in to the first strip, you can see the nested structure:

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)、网格中的位置 (单元格)、标签 (name) 和几何图形 (grob).

For each grob, we have an object that lists the order in which it's plotted (z), the position in the grid (cells), a label (name), and a geometry (grob).

由于我们可以在 gtables 中创建 gtables,我们将使用它来绘制原始图.首先,我们需要找到图中需要替换的位置.

Since we can create gtables within gtables, we are going to use this to plot over our original plot. First, we need to find the positions in the plot that need replacing.

# 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 创建一个:

Once we have the positions, we need to create a replacement table. We can do this with a matrix of lists (yes, it's weird. Just roll with it). This matrix needs to have three columns and two rows in our case because of the two facets and the gap between them. Since we are just going to replace data in the matrix later, we're going to create one with 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 的顶部,跨越整个长度.然后我们将该矩阵添加到我们的绘图之上.

The mask is created in two steps, covering the first facet group and then the second. In the first part, we are using the location we recorded earlier to grab the appropriate grob from the original plot and add it on top of our replacement matrix res, spanning the entire length. We then add that matrix on top of our plot.

# 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))

这篇关于ggplot2 跨组中的嵌套方面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆