在具有多个构面变量的图中,ggplot2对“外部”变量重复构面标签,而不是在“内部”变量的所有级别上都具有单个跨越构面带。我有一些代码一直在使用,这些代码使用gtable_add_grob包中的gtable用单个跨度小平面条覆盖重复的外部小平面标签。

不幸的是,由于小平面条的grob结构发生了变化,因此该代码不再与ggplot2 2.2.0一起使用。具体而言,在ggplot2的早期版本中,每行构面标签都有自己的一组grob。但是,在2.2.0版中,构面标签的每个垂直堆栈看起来都是单个grob。这破坏了我的代码,我不确定如何修复它。

这是一个具体的例子,取自an SO question I answered a few months ago

# Data
df = structure(list(location = structure(c(1L, 1L, 1L, 1L, 1L, 1L,
    1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 1L,
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
    2L, 2L), .Label = c("SF", "SS"), class = "factor"), species = structure(c(1L,
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
    1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
    2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("AGR", "LKA"), class = "factor"),
        position = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L,
        2L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L,
        1L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L,
        2L), .Label = c("top", "bottom"), class = "factor"), density = c(0.41,
        0.41, 0.43, 0.33, 0.35, 0.43, 0.34, 0.46, 0.32, 0.32, 0.4,
        0.4, 0.45, 0.34, 0.39, 0.39, 0.31, 0.38, 0.48, 0.3, 0.42,
        0.34, 0.35, 0.4, 0.38, 0.42, 0.36, 0.34, 0.46, 0.38, 0.36,
        0.39, 0.38, 0.39, 0.39, 0.39, 0.36, 0.39, 0.51, 0.38)), .Names = c("location",
    "species", "position", "density"), row.names = c(NA, -40L), class = "data.frame")

# Begin with a regular ggplot with three facet levels
p=ggplot(df, aes("", density)) +
  geom_boxplot(width=0.7, position=position_dodge(0.7)) +
  theme_bw() +
  facet_grid(. ~ species + location +  position) +
  theme(panel.margin=unit(0,"lines"),
        strip.background=element_rect(color="grey30", fill="grey90"),
        panel.border=element_rect(color="grey90"),
        axis.ticks.x=element_blank()) +
  labs(x="")


我们从具有三个层面的图开始。

r - 寻求由ggplot 2.2.0破坏的gtable_add_grob代码的解决方法-LMLPHP

现在,我们将使用跨接条覆盖最上面的两个小平面条,以免出现重复的条标签:

pg = ggplotGrob(p)

# Add spanning strip labels for species
pos = c(4,11)
for (i in 1:2) {
  pg <- gtable_add_grob(pg,
                        list(rectGrob(gp=gpar(col="grey50", fill="grey90")),
                             textGrob(unique(densityAGRLKA$species)[i],
                                      gp=gpar(cex=0.8))), t=3,l=pos[i],b=3,r=pos[i]+7,
                        name=c("a","b"))
}

# Add spanning strip labels for location
pos=c(4,7,11,15)
for (i in 1:4) {
    pg = gtable_add_grob(pg,
                         list(rectGrob(gp = gpar(col="grey50", fill="grey90")),
                              textGrob(rep(unique(densityAGRLKA$location),2)[i],
                                       gp=gpar(cex=0.8))), t=4,l=pos[i],b=4,r=pos[i]+3,
                         name = c("c","d"))
}

grid.draw(pg)


这是ggplot2 2.1.0的示意图:

r - 寻求由ggplot 2.2.0破坏的gtable_add_grob代码的解决方法-LMLPHP

但是,如果我使用ggplot2 2.2.0尝试相同的代码,则可以得到原始图,而对标签条没有任何更改。查看原始图p的grob结构可以说明为什么会发生这种情况。我已经在问题底部的grob表中进行了粘贴。为了节省空间,我仅包括与构面带相关的行。

查看cells列,请注意在该图的2.1.0版本中,每行中的前两个数字分别为3、4或5,指示该图钉相对于图中其他图钉的垂直位置。在上面的代码中,将tlgtable_add_grob参数设置为3或4的值,因为这些是我想用扩展条覆盖的小平面条行。

现在,查看该图的2.2.0版本中的cells列:请注意,前两个数字始终为6。还要注意,这些分面条仅包含8个grob,而不是版本2.1.0中的24个。在版本2.2.0中,似乎三个刻面标签的每个堆栈现在都是单个grob,而不是三个单独的grob。因此,即使我将t中的bgtable_add_grob参数更改为6,也将覆盖所有三个方面的条带。这是一个例子:

pg = ggplotGrob(p)

# Add spanning strip labels for species
pos = c(4,11)
for (i in 1:2) {
  pg <- gtable_add_grob(pg,
                        list(rectGrob(gp=gpar(col="grey50", fill="grey90")),
                             textGrob(unique(densityAGRLKA$species)[i],
                                      gp=gpar(cex=0.8))), t=6,l=pos[i],b=6,r=pos[i]+7,
                        name=c("a","b"))
}


r - 寻求由ggplot 2.2.0破坏的gtable_add_grob代码的解决方法-LMLPHP

因此,在进行了非常漫长的介绍之后,这是我的问题:如何使用ggplot2 2.2.0版创建跨接小平面条,看起来像我使用ggplot2 2.1.0版使用gtable_add_grob创建的小平面条?我希望有一个简单的调整,但如果需要进行大手术,那也可以。

ggplot 2.1.0

pg



TableGrob (9 x 19) "layout": 45 grobs
    z         cells       name                                   grob
2   1 ( 3- 3, 4- 4)  strip-top   absoluteGrob[strip.absoluteGrob.147]
3   2 ( 4- 4, 4- 4)  strip-top   absoluteGrob[strip.absoluteGrob.195]
4   3 ( 5- 5, 4- 4)  strip-top   absoluteGrob[strip.absoluteGrob.243]
5   4 ( 3- 3, 6- 6)  strip-top   absoluteGrob[strip.absoluteGrob.153]
6   5 ( 4- 4, 6- 6)  strip-top   absoluteGrob[strip.absoluteGrob.201]
7   6 ( 5- 5, 6- 6)  strip-top   absoluteGrob[strip.absoluteGrob.249]
8   7 ( 3- 3, 8- 8)  strip-top   absoluteGrob[strip.absoluteGrob.159]
9   8 ( 4- 4, 8- 8)  strip-top   absoluteGrob[strip.absoluteGrob.207]
10  9 ( 5- 5, 8- 8)  strip-top   absoluteGrob[strip.absoluteGrob.255]
11 10 ( 3- 3,10-10)  strip-top   absoluteGrob[strip.absoluteGrob.165]
12 11 ( 4- 4,10-10)  strip-top   absoluteGrob[strip.absoluteGrob.213]
13 12 ( 5- 5,10-10)  strip-top   absoluteGrob[strip.absoluteGrob.261]
14 13 ( 3- 3,12-12)  strip-top   absoluteGrob[strip.absoluteGrob.171]
15 14 ( 4- 4,12-12)  strip-top   absoluteGrob[strip.absoluteGrob.219]
16 15 ( 5- 5,12-12)  strip-top   absoluteGrob[strip.absoluteGrob.267]
17 16 ( 3- 3,14-14)  strip-top   absoluteGrob[strip.absoluteGrob.177]
18 17 ( 4- 4,14-14)  strip-top   absoluteGrob[strip.absoluteGrob.225]
19 18 ( 5- 5,14-14)  strip-top   absoluteGrob[strip.absoluteGrob.273]
20 19 ( 3- 3,16-16)  strip-top   absoluteGrob[strip.absoluteGrob.183]
21 20 ( 4- 4,16-16)  strip-top   absoluteGrob[strip.absoluteGrob.231]
22 21 ( 5- 5,16-16)  strip-top   absoluteGrob[strip.absoluteGrob.279]
23 22 ( 3- 3,18-18)  strip-top   absoluteGrob[strip.absoluteGrob.189]
24 23 ( 4- 4,18-18)  strip-top   absoluteGrob[strip.absoluteGrob.237]
25 24 ( 5- 5,18-18)  strip-top   absoluteGrob[strip.absoluteGrob.285]



ggplot2 2.2.0

pg



TableGrob (11 x 21) "layout": 42 grobs
    z         cells       name                                    grob
28  2 ( 6- 6, 4- 4)  strip-t-1                           gtable[strip]
29  2 ( 6- 6, 6- 6)  strip-t-2                           gtable[strip]
30  2 ( 6- 6, 8- 8)  strip-t-3                           gtable[strip]
31  2 ( 6- 6,10-10)  strip-t-4                           gtable[strip]
32  2 ( 6- 6,12-12)  strip-t-5                           gtable[strip]
33  2 ( 6- 6,14-14)  strip-t-6                           gtable[strip]
34  2 ( 6- 6,16-16)  strip-t-7                           gtable[strip]
35  2 ( 6- 6,18-18)  strip-t-8                           gtable[strip]

最佳答案

确实,ggplot2 v2.2.0逐列构造复杂的条带,每列单个grob。可以通过提取一个条带,然后检查其结构来检查。使用您的情节:

library(ggplot2)
library(gtable)
library(grid)

# Your data
df = structure(list(location = structure(c(1L, 1L, 1L, 1L, 1L, 1L,
 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 1L,
 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
 2L, 2L), .Label = c("SF", "SS"), class = "factor"), species = structure(c(1L,
 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("AGR", "LKA"), class = "factor"),
    position = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L,
    2L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L,
    1L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L,
    2L), .Label = c("top", "bottom"), class = "factor"), density = c(0.41,
    0.41, 0.43, 0.33, 0.35, 0.43, 0.34, 0.46, 0.32, 0.32, 0.4,
    0.4, 0.45, 0.34, 0.39, 0.39, 0.31, 0.38, 0.48, 0.3, 0.42,
    0.34, 0.35, 0.4, 0.38, 0.42, 0.36, 0.34, 0.46, 0.38, 0.36,
    0.39, 0.38, 0.39, 0.39, 0.39, 0.36, 0.39, 0.51, 0.38)), .Names = c("location",
   "species", "position", "density"), row.names = c(NA, -40L), class = "data.frame")

# Your ggplot with three facet levels
p=ggplot(df, aes("", density)) +
  geom_boxplot(width=0.7, position=position_dodge(0.7)) +
  theme_bw() +
  facet_grid(. ~ species + location +  position) +
  theme(panel.spacing=unit(0,"lines"),
     strip.background=element_rect(color="grey30", fill="grey90"),
     panel.border=element_rect(color="grey90"),
     axis.ticks.x=element_blank()) +
  labs(x="")

# Get the ggplot grob
pg = ggplotGrob(p)

# Get the left most strip
index = which(pg$layout$name == "strip-t-1")
strip1 = pg$grobs[[index]]

# Draw the strip
grid.newpage()
grid.draw(strip1)

# Examine its layout
strip1$layout
gtable_show_layout(strip1)


一种获得外部条带标签“跨越”内部标签的粗略方法是从头开始构建条带:

# Get the strips, as a list, from the original plot
strip = list()
for(i in 1:8) {
   index = which(pg$layout$name == paste0("strip-t-",i))
   strip[[i]] = pg$grobs[[index]]
}

# Construct gtable to contain the new strip
newStrip  = gtable(widths = unit(rep(1, 8), "null"), heights = strip[[1]]$heights)

## Populate the gtable
# Top row
for(i in 1:2) {
   newStrip = gtable_add_grob(newStrip, strip[[4*i-3]][1],
           t = 1, l = 4*i-3, r = 4*i)
}

# Middle row
for(i in 1:4){
   newStrip = gtable_add_grob(newStrip, strip[[2*i-1]][2],
         t = 2, l = 2*i-1, r = 2*i)
}

# Bottom row
for(i in 1:8) {
   newStrip = gtable_add_grob(newStrip, strip[[i]][3],
       t = 3, l = i)
}

# Put the strip into the plot
# (It could be better to remove the original strip.
# In this case, with a coloured background, it doesn't matter)
pgNew = gtable_add_grob(pg, newStrip, t = 7, l = 5, r = 19)

# Draw the plot
grid.newpage()
grid.draw(pgNew)


或使用矢量化的gtable_add_grob(请参见注释):

pg = ggplotGrob(p)

# Get a list of strips from the original plot
strip = lapply(grep("strip-t", pg$layout$name), function(x) {pg$grobs[[x]]})

# Construct gtable to contain the new strip
newStrip  = gtable(widths = unit(rep(1, 8), "null"), heights = strip[[1]]$heights)

## Populate the gtable
# Top row
cols = seq(1, by = 4, length.out = 2)
newStrip = gtable_add_grob(newStrip, lapply(strip[cols], `[`, 1), t = 1, l = cols, r = cols + 3)

# Middle row
cols = seq(1, by = 2, length.out = 4)
newStrip = gtable_add_grob(newStrip, lapply(strip[cols], `[`, 2), t = 2, l = cols, r = cols + 1)

# Bottom row
newStrip = gtable_add_grob(newStrip, lapply(strip, `[`, 3), t = 3, l = 1:8)

# Put the strip into the plot
pgNew = gtable_add_grob(pg, newStrip, t = 7, l = 5, r = 19)

# Draw the plot
grid.newpage()
grid.draw(pgNew)


r - 寻求由ggplot 2.2.0破坏的gtable_add_grob代码的解决方法-LMLPHP

10-08 15:44