ggplot2生成组中的嵌套构面 [英] Nested facets in ggplot2 spanning groups

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

问题描述

我遇到了一种情况,我想创建一个由三个分组变量构成的情节。为此,我会简单地使用 facet_grid(f1〜f2 + f3),但问题在于f2的标签是多余的,并且会好很多让他们跨越f2嵌套的方面。



MWE:

 <$ c $ b $ library('tibble')
library('ggplot2')
df < - tribble(
〜x,〜y,〜f1,〜f2,〜f3,
0.5,0.5aaa
0.5,0.5baa
0.5,0.5a, b,a,
0.5,0.5,b,b,a,
0.5,0.5,a,a,b,
0.5,0.5b,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的标签,以便y不是多余的。

编辑:这与其他问题不同,它询问如何使用现有的分组来修改方面,而不是添加新方面。 gtable 包。一切都在一个特定的顺序,你可以找到一切,如果你挖一点。

  library( 'gtable')
library('grid')
library('magrittr')#为%>%我非常喜欢

#首先获取grob
z < - ggplotGrob(p)

此操作的最终目标是覆盖顶部但是诀窍是这两个方面都存在于网格空间的同一行上。它们是表格中的一个表格(查看名称为strip的行,也注意 zeroGrob ;这些将在稍后使用):

  z 
## TableGrob(13 x 14)layout:34 grobs
## z cells names grob
## 1 0(1-13,1-14)背景矩形[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 [带]
## 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]

。 (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 cells grob
## 1 1(1-1,1-1)strip绝对条[strip.absoluteGrob.451]
## 2 2(2-2,1-1)条绝对条[strip.absoluteGrob.475]

对于每个grob,我们都有一个对象,列出它的绘制顺序( z ),网格中的位置( cells ),一个实验室el(名称)和几何图形( grob )。

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

 #在主图中找到条带的位置
位置< - grep(strip-t ,z $ layout $ name)

#过滤掉条(trim = FALSE对于相对于主图的位置很重要)
strip < - gtable_filter(z, t,trim = FALSE)

#收集我们对主图的位置
top< - strip $ layout $ t [1]
l < - strip $ layout $ l [c(1,3)]
r < - strip $ layout $ r [c(2,4)]

一旦我们有了职位,我们需要创建一个替代表。我们可以用列表矩阵来做到这一点(是的,这很奇怪,只是滚动它)。这个矩阵需要在我们的例子中有三列和两行,因为这两个方面和它们之间的差距。因为我们稍后将会替换矩阵中的数据,所以我们将使用 zeroGrob s创建一个:



< pre $ p $ $ $ b $ mat mat [] < - list(zeroGrob())

#这些分面的分隔符的宽度为零
res< -gtable_matrix(toprow,mat,单位(c(1,0,1),null),单位(c (1,1),null))

掩码分两步创建,第一方面组,然后是第二方面。在第一部分中,我们使用前面记录的位置从原始图中获取适当的grob,并将其添加到替换矩阵 res 的顶部,跨越整个长度。

 #添加第一层
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))

#添加第二层)
pp< - gtable_add_grob(res,z $ grobs [[locations [3]]] $ grobs [[1]],1,1,1,3)%>%
gtable_add_grob( zz,t = top,l = 1 [2],b = top,r = r [2],name = c(add-strip))

#绘制
grid.newpage()
print(grid.draw(pp))


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)

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

Edit: 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.

解决方案

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) 

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]

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

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

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

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天全站免登陆