这可能是一个比您希望的要复杂得多的问题,并且需要几个步骤,所以这个解决方案感觉有点笨拙。它也可能不是您想要的,但仍有调整的余地。
我首先要做的是将数值列分解成区间,即因子,确保字符向量是因子,并为每一列提供"NA" 的显式因子级别,而不是值类型NA .这是一个微妙的区别(您可以将此级别称为其他东西),但它允许您将此级别放在每个因素的末尾,因此NA 条将全部放置在顶部。但是,填充比例会自动为NA 分配一个灰度值,因此您必须手动执行此操作。我通过拉出 ColorBrewer 调色板“Blues”来做到这一点,然后在 scale_fill_manual 中将灰色放在它旁边。
library(tidyverse)
library(patchwork)
set.seed(123)
df <- data_frame(Age = c(rep(NA, 10), runif(40, 1, 100)),
Duration = c(rep(NA, 20), runif(30, 0, 4)),
cat = rep(c("A", "B", "C", "D", NA), each = 10),
cat2 = rep(c("X", "Y", "Z", NA, "W"), each = 10))
df_breaks <- df %>%
arrange(Age) %>%
mutate(Age = cut(Age, breaks = seq(0, 100, by = 25)),
Duration = cut(Duration, breaks = seq(0, 4, by = 1))) %>%
mutate_if(is.character, as.factor) %>%
mutate_all(~fct_explicit_na(., na_level = "NA"))
df_breaks
#> # A tibble: 50 x 4
#> Age Duration cat cat2
#> <fct> <fct> <fct> <fct>
#> 1 (0,25] (3,4] NA W
#> 2 (0,25] (1,2] C Z
#> 3 (0,25] NA B Y
#> 4 (0,25] (0,1] C Z
#> 5 (0,25] (1,2] D NA
#> 6 (0,25] (3,4] NA W
#> 7 (0,25] (1,2] NA W
#> 8 (25,50] (0,1] C Z
#> 9 (25,50] NA B Y
#> 10 (25,50] (3,4] D NA
#> # ... with 40 more rows
palette <- RColorBrewer::brewer.pal(4, "Blues")
要为每一列制作单独的图,我使用purrr::imap 在每一列上调用一个函数,使用该列的名称和列本身创建一个新的数据框,计算休息时间,并制作一个条形图。我添加了geom_text 来制作标签,这也可以让您跳过图例。 (就像我在评论中说的那样,传说会给你带来麻烦,因为所有的比例都是不同的。)我还删除了左侧和右侧的情节边距,这样你就可以将情节放在每个旁边其他,并删除 x 轴标题,这将是多余的。
p <- imap(df_breaks, function(col, term) {
data_frame(term = term, group = col) %>%
count(term, group) %>%
ggplot(aes(x = term, y = n, fill = fct_rev(group))) +
geom_col(position = "fill") +
geom_text(aes(label = fct_rev(group)), position = position_fill(vjust = 0.5)) +
scale_fill_manual(values = c("gray70", palette)) +
theme_minimal() +
theme(legend.position = "none", plot.margin = margin(10, 0, 10, 0, "pt")) +
labs(x = NULL)
})
这将为您提供ggplot 对象的列表。我正在按照你显示的顺序重新排列它。
p <- p[c("Age", "cat", "Duration", "cat2")]
然后使用patchwork::wrap_plots,您可以将绘图列表放在一起。
wrap_plots(p, nrow = 1)
如果你想让它看起来像一个单独的情节,有一些冗余,所以你可以从情节 2、3 和 4 中删除左侧的主题元素,然后 wrap_plots 再次使用原始的p$Age:
p_no_y <- map(p[2:4], function(plot) {
plot +
theme(axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank())
})
wrap_plots(p$Age, p_no_y$cat, p_no_y$Duration, p_no_y$cat2, nrow = 1)
使用patchwork 而不是cowplot 的优点是patchwork 函数知道每个绘图中轴所占用的空间,因此列的宽度相同,尽管事实上一个plot 也有一个 y 轴。要明白我的意思,请将wrap_plots 替换为cowplot::plot_grid。
所以这已经很多了!而且还有很多空间可以做更多:
- 您可以进一步调整边距和其他主题元素以及 x 轴和 y 轴,以按照您的需要将绘图组合在一起。
- 如果您想为不同的列使用不同的调色板,例如一个连续的,就像我在这里展示的数字变量,但一个定性的分类变量 - 你可以单独分配填充比例,而不是像我在
imap 函数中所做的那样。
- 您可能希望通过在
cut 中提供标签来设置不在区间表示法中的中断标签。