Tôi đang cố gắng tạo một facet_multi_col()
hàm, tương tự như facet_col()
hàm trong ggforce
- cho phép bố trí một khía cạnh với một đối số không gian (không có sẵn trong facet_wrap()
) - nhưng qua nhiều cột. Như trong âm mưu cuối cùng bên dưới (được tạo bằng grid.arrange()
), tôi không muốn các khía cạnh nhất thiết phải căn chỉnh giữa các hàng vì độ cao trong mỗi khía cạnh sẽ thay đổi dựa trên một y
biến phân loại mà tôi muốn sử dụng.
Tôi thấy mình thoát khỏi chiều sâu của mình ggproto
khi đọc hướng dẫn mở rộng . Tôi nghĩ cách tiếp cận tốt nhất là truyền một ma trận bố cục để ra lệnh phá vỡ các cột cho các tập hợp con tương ứng của dữ liệu và xây dựng facet_col
trong ggforce để bao gồm một tham số không gian - xem phần cuối của câu hỏi.
Một minh họa nhanh về các lựa chọn không đạt yêu cầu của tôi
Không có khía cạnh
library(tidyverse)
library(gapminder)
global_tile <- ggplot(data = gapminder, mapping = aes(x = year, y = fct_rev(country), fill = lifeExp)) +
geom_tile()
global_tile
Tôi muốn phá vỡ cốt truyện của các châu lục. Tôi không muốn một con số dài như vậy.
facet_wrap ()
global_tile +
facet_wrap(facets = "continent", scales = "free")
facet_wrap()
không có đối số không gian có nghĩa là các ô có kích thước khác nhau ở mỗi lục địa, sử dụng coord_equal()
lỗi ném
facet_col () trong ggforce
library(ggforce)
global_tile +
facet_col(facets = "continent", scales = "free", space = "free", strip.position = "right") +
theme(strip.text.y = element_text(angle = 0))
Giống như các dải ở bên cạnh. space
đối số đặt tất cả các ô có cùng kích thước. Vẫn còn quá dài để phù hợp với một trang.
Grid.arrange () trong GridExtra
Thêm một cột cột vào dữ liệu cho vị trí của mỗi lục địa
d <- gapminder %>%
as_tibble() %>%
mutate(col = as.numeric(continent),
col = ifelse(test = continent == "Europe", yes = 2, no = col),
col = ifelse(test = continent == "Oceania", yes = 3, no = col))
head(d)
# # A tibble: 6 x 7
# country continent year lifeExp pop gdpPercap col
# <fct> <fct> <int> <dbl> <int> <dbl> <dbl>
# 1 Afghanistan Asia 1952 28.8 8425333 779. 3
# 2 Afghanistan Asia 1957 30.3 9240934 821. 3
# 3 Afghanistan Asia 1962 32.0 10267083 853. 3
# 4 Afghanistan Asia 1967 34.0 11537966 836. 3
# 5 Afghanistan Asia 1972 36.1 13079460 740. 3
# 6 Afghanistan Asia 1977 38.4 14880372 786. 3
tail(d)
# # A tibble: 6 x 7
# country continent year lifeExp pop gdpPercap col
# <fct> <fct> <int> <dbl> <int> <dbl> <dbl>
# 1 Zimbabwe Africa 1982 60.4 7636524 789. 1
# 2 Zimbabwe Africa 1987 62.4 9216418 706. 1
# 3 Zimbabwe Africa 1992 60.4 10704340 693. 1
# 4 Zimbabwe Africa 1997 46.8 11404948 792. 1
# 5 Zimbabwe Africa 2002 40.0 11926563 672. 1
# 6 Zimbabwe Africa 2007 43.5 12311143 470. 1
Sử dụng facet_col()
cho âm mưu cho mỗi cột
g <- list()
for(i in unique(d$col)){
g[[i]] <- d %>%
filter(col == i) %>%
ggplot(mapping = aes(x = year, y = fct_rev(country), fill = lifeExp)) +
geom_tile() +
facet_col(facets = "continent", scales = "free_y", space = "free", strip.position = "right") +
theme(strip.text.y = element_text(angle = 0)) +
# aviod legends in every column
guides(fill = FALSE) +
labs(x = "", y = "")
}
Tạo một huyền thoại bằng cách sử dụng get_legend()
trongcowplot
library(cowplot)
gg <- ggplot(data = d, mapping = aes(x = year, y = country, fill = lifeExp)) +
geom_tile()
leg <- get_legend(gg)
Tạo ma trận bố cục với độ cao dựa trên số lượng quốc gia trong mỗi cột.
m <-
d %>%
group_by(col) %>%
summarise(row = n_distinct(country)) %>%
rowwise() %>%
mutate(row = paste(1:row, collapse = ",")) %>%
separate_rows(row) %>%
mutate(row = as.numeric(row),
col = col,
p = col) %>%
xtabs(formula = p ~ row + col) %>%
cbind(max(d$col) + 1) %>%
ifelse(. == 0, NA, .)
head(m)
# 1 2 3
# 1 1 2 3 4
# 2 1 2 3 4
# 3 1 2 3 4
# 4 1 2 3 4
# 5 1 2 3 4
# 6 1 2 3 4
tail(m)
# 1 2 3
# 50 1 2 NA 4
# 51 1 2 NA 4
# 52 1 2 NA 4
# 53 NA 2 NA 4
# 54 NA 2 NA 4
# 55 NA 2 NA 4
Mang g
và leg
cùng nhau sử dụng grid.arrange()
tronggridExtra
library(gridExtra)
grid.arrange(g[[1]], g[[2]], g[[3]], leg, layout_matrix = m, widths=c(0.32, 0.32, 0.32, 0.06))
Đây gần như là những gì tôi đang theo đuổi, nhưng tôi không hài lòng vì a) các ô trong các cột khác nhau có độ rộng khác nhau vì độ dài của tên quốc gia và lục địa dài nhất không bằng nhau và b) rất nhiều mã cần được điều chỉnh mỗi thời gian tôi muốn thực hiện một âm mưu như thế này - với các dữ liệu khác tôi muốn sắp xếp các khía cạnh theo khu vực, ví dụ "Tây Âu" thay vì các lục địa hoặc số lượng quốc gia thay đổi - không có quốc gia Trung Á nào trong gapminder
dữ liệu.
Tiến trình tạo hàm facet_multi_cols ()
Tôi muốn truyền ma trận bố cục cho hàm facet, trong đó ma trận sẽ tham chiếu đến từng khía cạnh và sau đó hàm có thể tìm ra độ cao dựa trên số lượng khoảng trắng trong mỗi bảng. Đối với ví dụ trên, ma trận sẽ là:
my_layout <- matrix(c(1, NA, 2, 3, 4, 5), nrow = 2)
my_layout
# [,1] [,2] [,3]
# [1,] 1 2 4
# [2,] NA 3 5
Như đã đề cập ở trên, tôi đã điều chỉnh từ mã facet_col()
để thử và xây dựng một facet_multi_col()
hàm. Tôi đã thêm một layout
đối số để cung cấp ma trận như my_layout
ở trên, với ý tưởng rằng, ví dụ, mức thứ tư và thứ năm của biến được đưa ra cho facets
đối số được vẽ trong cột thứ ba.
facet_multi_col <- function(facets, layout, scales = "fixed", space = "fixed",
shrink = TRUE, labeller = "label_value",
drop = TRUE, strip.position = 'top') {
# add space argument as in facet_col
space <- match.arg(space, c('free', 'fixed'))
facet <- facet_wrap(facets, col = col, dir = dir, scales = scales, shrink = shrink, labeller = labeller, drop = drop, strip.position = strip.position)
params <- facet$params
params <- facet$layout
params$space_free <- space == 'free'
ggproto(NULL, FacetMultiCols, shrink = shrink, params = params)
}
FacetMultiCols <- ggproto('FacetMultiCols', FacetWrap,
# from FacetCols to allow for space argument to work
draw_panels = function(self, panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) {
combined <- ggproto_parent(FacetWrap, self)$draw_panels(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params)
if (params$space_free) {
widths <- vapply(layout$PANEL, function(i) diff(ranges[[i]]$x.range), numeric(1))
panel_widths <- unit(widths, "null")
combined$widths[panel_cols(combined)$l] <- panel_widths
}
combined
}
# adapt FacetWrap layout to set position on panels following the matrix given to layout in facet_multi_col().
compute_layout = function(self, panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) {
layout <- ggproto_parent(FacetWrap, self)$compute_layout(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params)
# ???
)
Tôi nghĩ rằng tôi cần phải viết một cái gì đó cho compute_layout
phần này, nhưng tôi đang đấu tranh để tìm ra cách để làm điều này.
grid.arrange
ví dụ trên .. trừ khi bạn có ý gì khác? Tôi nghĩ những vấn đề tương tự sẽ tồn tại với độ dài nhãn khác nhau trong mỗi cột?
grid.arrange
. Đây là một bài viết rất dài nên rất khó để theo dõi mọi thứ bạn đã thử. Một chút hacky, nhưng bạn có thể thử một phông chữ đơn cách / gần hơn với phông chữ cách đều nhau cho các nhãn để độ dài của chúng dễ dự đoán hơn. Bạn thậm chí có thể đệm nhãn với các khoảng trắng để đảm bảo văn bản gần với cùng độ dài.