2016-10-29 16 views
5

Tôi đã gặp phải một tình huống mà trong đó tôi muốn tạo một cốt truyện được tạo thành bởi ba biến nhóm. Để làm như vậy, tôi chỉ đơn giản là sử dụng facet_grid(f1 ~ f2 + f3), nhưng vấn đề ở đây là các nhãn cho f2 sẽ là thừa, và nó sẽ tốt hơn nhiều để có chúng span các facets cho f3 lồng nhau trong f2.Các khía cạnh lồng nhau trong các nhóm kéo dài 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

lần nữa, tôi đang tìm cách để kết hợp các nhãn cho f2 để họ không quá dư thừa.

Chỉnh sửa: Điều này khác với các câu hỏi khác ở chỗ nó hỏi cách sử dụng các nhóm hiện có để sửa đổi một khía cạnh thay vì thêm một khía cạnh mới.

Trả lời

9

Câu trả lời cho câu hỏi này nằm trong các gói gridgtable. Tất cả mọi thứ trong cốt truyện được đặt ra theo một thứ tự cụ thể và bạn có thể tìm thấy nơi mà tất cả mọi thứ là nếu bạn đào một chút.

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

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

Mục tiêu cuối cùng của thao tác này là che phủ nhãn trên cùng, nhưng mẹo là cả hai mặt này tồn tại trên cùng một hàng trong không gian lưới. Họ là một bảng trong một bảng (nhìn vào các hàng với cái tên "dải", cũng lưu ý các zeroGrob, chúng sẽ có ích sau):

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] 

Nếu bạn phóng to các dải đầu tiên, bạn có thể thấy cấu trúc lồng nhau:

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] 

Đối với mỗi grob, chúng tôi có một đối tượng liệt kê thứ tự mà nó vẽ (z), vị trí trong lưới (tế bào), một nhãn (tên) và hình học (grob).

Vì chúng tôi có thể tạo gtables trong gtables, chúng tôi sẽ sử dụng điều này để vẽ trên lô gốc của chúng tôi. Đầu tiên, chúng ta cần phải tìm các vị trí trong cốt truyện cần thay thế.

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

Khi chúng tôi có vị trí, chúng tôi cần tạo bảng thay thế. Chúng ta có thể làm điều này với một ma trận các danh sách (có, nó là lạ. Chỉ cần cuộn với nó). Ma trận này cần phải có ba cột và hai hàng trong trường hợp của chúng tôi vì hai khía cạnh và khoảng cách giữa chúng. Vì chúng ta chỉ là đi để thay thế dữ liệu trong ma trận sau, chúng ta sẽ tạo ra một với zeroGrob s:

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

Mặt nạ được tạo ra theo hai bước, bao gồm các nhóm khía cạnh đầu tiên và sau đó là thứ hai. Trong phần đầu tiên, chúng tôi đang sử dụng vị trí chúng tôi ghi lại trước đó để lấy grob thích hợp từ ô gốc và thêm nó lên trên ma trận thay thế res của chúng tôi, kéo dài toàn bộ chiều dài. Sau đó chúng tôi thêm ma trận đó vào đầu cốt truyện của chúng tôi.

# 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

Cảm ơn rất nhiều cho các giải pháp. Tôi đã đấu tranh để tìm cách làm thế nào để khái quát hóa giải pháp này để sửa đổi các nhãn khía cạnh nếu chúng xảy ra ở bên phải của cốt truyện.Bạn có thể chỉ ra cách người ta sửa đổi giải pháp của bạn thành bộ trường hợp bố trí dựa trên hàm lô ggplot (cbind (df, df), aes (x = x, y = y)) + geom_point() + facet_grid (f1 + f2 ~ f3) '? Tôi tiếp tục cần phải khái quát hóa một trường hợp với 12 hàng khía cạnh giảm xuống 6 nhãn bên ngoài bên phải thay vì 4 và 2 (như hàm viết lại mà tôi đã cung cấp sẽ tạo ra). Vui lòng cung cấp một ví dụ rõ ràng nếu điều đó có ích. Cảm ơn nhiều! – nickb

Các vấn đề liên quan