2016-10-29 7 views
5

세 개의 그룹화 변수로 구성된 플롯을 작성하려는 상황이 발생했습니다. 이렇게하려면 facet_grid(f1 ~ f2 + f3)을 사용하면되지만 여기에서는 f2의 레이블이 중복 될 수 있으며 f2에 중첩 된 f3에 대해 패싯을 확장하는 것이 훨씬 좋습니다.ggplot2 스패닝 그룹의 중첩 된 패밀리

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) 
다시

MWE of nested facet plot

, 나는 그들이 너무 중복되지 않도록 F2의 레이블을 결합 찾고 있어요.

편집 : 이것은 새 그룹을 추가하는 대신 기존 그룹을 사용하여 패싯을 수정하는 방법을 묻는 점에서 다른 질문과 다릅니다.

답변

9

이에 대한 대답은 gridgtable 패키지 내에 있습니다. 음모에있는 모든 것은 특정 순서로 배치되어 있으며, 조금 파다 보면 모든 것이 어디에 있는지 알 수 있습니다.

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

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

이 작업의 궁극적 인 목표는 상단면 레이블을 오버레이하지만 트릭은 이러한 측면 모두 그리드 공간에서 같은 행에 존재한다는 것입니다. 그들은 테이블에서 테이블이다 (또한 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] 

첫 번째 스트립을 확대하는 경우를 중첩 된 구조를 볼 수있는 각 GROB 들어

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] 

을 우리는 플롯있어 순서 (Z) 그리드에서의 위치 (세포), 라벨 (나열 목적을 이름) 및 기하학 (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)] 

위치를 얻은 후에는 교체 테이블을 만들어야합니다. 우리는 목록의 행렬로 이것을 할 수 있습니다 (예, 이상합니다. 이 행렬은 두 개의 패싯과 그것들 사이의 간격 때문에 우리의 경우에 3 개의 열과 2 개의 행을 가져야합니다. 우리가 이후에 행렬의 데이터를 대체하는 것 때문에, 우리는 zeroGrob의 하나를 만들려고 :

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

Nested facet labels

+1

감사합니다. 필자는 플롯 오른쪽에 패싯 라벨이 생긴 경우 패싯 레이블을 수정하기 위해이 솔루션을 일반화하는 방법을 알아 내려고 노력했습니다.레이아웃이 플롯 함수'ggplot (cbind (df, df), aes (x = x, y = y)) + geom_point() + facet_grid()에 기반한 경우를 솔루션으로 수정하는 방법을 보여줄 수 있습니까? f1 + f2 ~ f3)'? 필자는 12 개의 패싯 행이 4와 2가 아닌 6 개의 바깥 쪽 레이블로 축소 된 경우를 일반화해야합니다 (필자가 제공 한 다시 작성 함수가 생성 할 때). 그게 도움이된다면 명확한 예를 제공해 주시면 기쁘게 생각합니다. 많은 감사합니다! – nickb