ggplot2分面绘制有序变量图时如何同时展示组内与全样本百分比
实现方法
核心是拆分计算逻辑,避免分组维度冲突:先单独计算四个种族各自的组内百分比,再单独计算所有种族合并的全样本百分比,给全样本数据统一打上all的组别标签,最后把两份数据合并后绘图即可。不需要在原单一种族分组的计算链中强行插入mutate步骤,很容易因为分组层级不匹配出问题。
完整可运行代码
library(tidyverse) # 测试数据 set.seed(123) d <- data.frame( race = sample(c("White", "Hispanic", "Black", "Other"), 100, replace = TRUE), question1 = sample(0:4, 100, replace = TRUE), question2 = sample(0:4, 100, replace = TRUE), question3 = sample(0:4, 100, replace = TRUE) ) # 转换为长格式,统一处理所有题项 d_long <- d %>% pivot_longer(cols = starts_with("question"), names_to = "question", values_to = "response") # 计算分种族的组内百分比 pct_race <- d_long %>% group_by(question, race, response) %>% summarise(n = n(), .groups = "drop_last") %>% mutate(pct = n/sum(n)*100) %>% ungroup() # 计算全样本百分比,组别统一标记为all pct_all <- d_long %>% group_by(question, response) %>% summarise(n = n(), .groups = "drop_last") %>% mutate(pct = n/sum(n)*100, race = "all") %>% ungroup() # 合并数据,调整组别显示顺序 plot_data <- bind_rows(pct_race, pct_all) %>% mutate(race = factor(race, levels = c("White", "Black", "Hispanic", "Other", "all"))) # 绘图 ggplot(plot_data, aes(x = factor(response), y = pct, fill = race)) + geom_col(position = position_dodge(width = 0.8), width = 0.7) + # 添加百分比数值标签 geom_text(aes(label = paste0(round(pct, 1), "%")), position = position_dodge(width = 0.8), vjust = -0.3, size = 3) + # 按题项分面 facet_wrap(~question, nrow = 1) + labs(x = "题项响应值", y = "组内百分比(%)", fill = "组别") + theme_bw()
可调细节
- 组别顺序可自由调整:修改
mutate(race = factor(...))中的水平顺序,就能把all组放到任意位置,比如放在四个种族最前、最后,或者插在两个种族中间,满足和单种族结果并排展示的需求。 - 可做视觉区分:如果需要把全样本组和单种族组明确区分开,可以给
all组单独设置边框、透明度等样式,示例代码如下:
ggplot(plot_data, aes(x = factor(response), y = pct, fill = race)) + geom_col(position = position_dodge(width = 0.8), width = 0.7, aes(colour = race, linewidth = race)) + # 给all组设置黑色粗边框,其余种族用细白边框 scale_linewidth_manual(values = c("White" = 0.5, "Black" = 0.5, "Hispanic" = 0.5, "Other" = 0.5, "all" = 1.2)) + scale_colour_manual(values = c("White" = "white", "Black" = "white", "Hispanic" = "white", "Other" = "white", "all" = "black")) + geom_text(aes(label = paste0(round(pct, 1), "%")), position = position_dodge(width = 0.8), vjust = -0.3, size = 3) + facet_wrap(~question, nrow = 1) + labs(x = "题项响应值", y = "组内百分比(%)", fill = "组别", colour = "组别", linewidth = "组别") + theme_bw()
内容的提问来源于stack exchange,提问作者a_todd12
相关产品推荐
相关产品推荐

