В поисках обходного пути для кода gtable_add_grob, сломанного ggplot 2.2.0

На графиках с несколькими переменными фасетов, ggplot2 повторяет метку фасета для «внешней» переменной, вместо того, чтобы иметь одну охватывающую полосу фасета на всех уровнях «внутренней» переменной. У меня есть код, который я использовал, чтобы покрыть повторяющиеся метки внешнего фасета одной охватывающей полосой фасета, используяgtable_add_grob отgtable пакет.

К сожалению, этот код больше не работает с ggplot2 2.2.0 из-за изменений в структуре grob полосок фасетов. В частности, в предыдущих версиях ggplot2 у каждого ряда меток фасетов был свой набор гробов. Тем не менее, в версии 2.2.0 похоже, что каждая вертикальная стопка меток фасетов представляет собой единый гроб. Это нарушает мой код, и я не уверен, как это исправить.

Вот конкретный пример, взятый изна такой вопрос я ответил несколько месяцев назад:

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

Мы начнем с сюжета, который имеет три уровня граней.

Теперь мы покроем две верхние фасеточные полосы связующими полосами, чтобы у нас не было повторяющихся полосовых меток:

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:

Однако, если я попробую тот же код с ggplot2 2.2.0, я вернусь к исходному графику без изменений меток полосы. Посмотрите на структуру Grob оригинального сюжетаp предполагает, почему это происходит. Я вставил в таблицы Гроба в нижней части этого вопроса. Чтобы сэкономить место, я включил только строки, связанные с полосками фасетов.

Глядя наcells Обратите внимание, что в версии графика 2.1.0 первые два числа в каждом ряду равны 3, 4 или 5, что указывает на вертикальное положение гроба относительно других гробов на графике. В приведенном выше кодеt а такжеl аргументыgtable_add_grob установлены значения 3 или 4, потому что это те ряды полос фасетов, которые я хотел покрыть связующими полосами.

Теперь посмотрим наcells столбец в версии графика 2.2.0: обратите внимание, что первые два числа всегда равны 6. Также обратите внимание, что полоски фасетов состоят только из 8 гробов вместо 24 в версии 2.1.0. В версии 2.2.0, кажется, что каждая пачка из трех фасетных меток теперь представляет собой один гроб вместо трех отдельных гробов. Так что даже если я изменюt а такжеb аргументы вgtable_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"))
}

Итак, после этого очень многословного вступления вот мой вопрос: как я могу создать покрывающие полосы фасетов с помощью ggplot2 версии 2.2.0, которые выглядят так же, как те, что я создал с помощьюgtable_add_grob с ggplot2 версии 2.1.0? Я надеюсь, что есть простая настройка, но если это требует серьезной операции, ну, это тоже хорошо.

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]

Ответы на вопрос(2)

Ваш ответ на вопрос