我有一个如下数据框:
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))
值得注意的是,它包含两个数字列和两个类别列。每列都有一些NA值。
我想制作一个堆叠的条形图,以显示分类列中每个组的比例,并为数字列显示一个色条。类别的顺序对于分类而言无关紧要,除了我希望NA始终位于顶部,并且数值应从底部的最低值到顶部的最大值(但NA也在顶部)排序。>
下面是我试图取得的成功的简要概述。对于数字色条,我想在条上的5点处注释四舍五入到最接近的整数的值。
我首先将数据帧融化以使其更长,但是不确定如何从此处继续。
library(reshape)
df_m = melt(df, id = c())
如果您能提供帮助,我将不胜感激。
谢谢, 杰克
答案 0 :(得分:3)
这可能是比您希望的要复杂得多的问题,并且分几个步骤进行,因此此解决方案感觉有些棘手。可能也不一定正是您要的东西,但仍有调整的余地。
我首先要做的是将数字列分解为区间,将区间划分为因子,确保字符向量为因子,并为每列赋予明确的因子级别"NA"
,而不是值类型{ {1}}。这是一个细微的差异(您可以将此级别称为其他级别),但是它可以让您将此级别放在每个因子的末尾,因此NA
条形图都将放在顶部。但是,填充比例会自动为NA
指定一个灰色值,因此您必须手动执行此操作。为此,我将拉出ColorBrewer调色板“蓝色”,然后在NA
的旁边放置灰色。
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
来制作标签,这也使您可以跳过图例。 (就像我在评论中说的那样,图例会给您带来麻烦,因为所有比例都不同。)我还要删除左侧和右侧的绘图边距,以便您可以在每个绘图旁边并排放置绘图其他,并删除x轴标题,这将是多余的。
geom_text
这将为您提供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
如果您希望将其看起来像是单个图,则有一些冗余,因此您可以从图2、3和4中删除左侧主题元素,然后使用原始的{{1}再次删除wrap_plots(p, nrow = 1)
}}:
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
函数知道每个图在坐标轴上占据的空间,因此列的宽度相同,尽管一个图也具有y轴。要了解我的意思,请将cowplot
替换为patchwork
。
所以已经很多了!还有足够的空间做更多的事情:
wrap_plots
函数中一样。
cowplot::plot_grid
中提供标签来设置间隔标记以外的中断标签。