如何在ggplot2条形图中显示无观测值的类别
解决ggplot显示无数据类别条形图的问题
你之前用scale_x_discrete(drop=FALSE)无效的核心原因是:原数据的age_cat转成因子时,因子水平里根本没有"1"这个类别——因为数据集里没有对应观测,as.factor(age_cat)只会生成现有值的水平(2、3、4、5、6),后续设置breaks也无法显示不存在的因子水平。
解决方案
需要先强制保留所有目标因子水平,再预处理数据补全无观测组的0值,最后用处理好的数据绘图:
1. 加载依赖包并预处理数据
library(ggplot2) library(dplyr) library(tidyr) # 原始数据 f.s_c_subset <- data.frame( study = c(rep(1,10),rep(2,5)), age_cat = c(3,3,4,2,6,3,2,5,2,4,5,6,5,4,4) ) # 强制将age_cat转为包含所有6个类别的因子(即使无数据) f.s_c_subset$age_cat <- factor(f.s_c_subset$age_cat, levels = 1:6) # 计算每个活动地点内各年龄组的相对百分比,补全无数据的组 df_summary <- f.s_c_subset %>% group_by(study, age_cat) %>% summarise(count = n(), .groups = "drop") %>% complete(study, age_cat, fill = list(count = 0)) %>% # 补全所有分组组合,空组count设为0 group_by(study) %>% mutate(percent = count / sum(count)) %>% ungroup() # 年龄组标签 vec.age_cat <- c("< 18 years", "18-23 years", "24-27 years", "28-35 years", "36-45 years", "> 45 years")
2. 绘制条形图
ggplot(data = df_summary, aes(x = age_cat, y = percent, fill = factor(study))) + geom_bar(stat = "identity", position = "dodge") + # 设置填充色和分组标签 scale_fill_manual(values = c("grey40","grey60"), name = "event location", labels = c("university", "outside")) + # 添加百分比文本(可选择隐藏0%文本) geom_text(aes(label = ifelse(percent > 0, scales::percent(percent, accuracy = 1), "")), position = position_dodge(0.9), vjust = -0.5) + # 坐标轴配置 ylab('percent of audience relative to location') + xlab("age groups") + scale_x_discrete(labels = vec.age_cat, drop = FALSE) + scale_y_continuous(labels = scales::percent, limits = c(0, 0.45)) + # 主题样式 theme(axis.text.x = element_text(angle = 45, hjust = .8), axis.ticks.x = element_blank(), panel.border = element_rect(linetype = "solid", colour = "black", linewidth = .5, fill = NA), panel.grid.minor = element_line(colour = "grey80", linewidth = .3), panel.grid.major.y = element_line(colour = "grey80", linewidth = .3), panel.background = element_rect(fill = "grey97"), axis.title.x.bottom = element_text(margin = margin(t = .2, unit = "in")))
关键说明
factor(f.s_c_subset$age_cat, levels = 1:6):强制因子包含所有6个目标水平,确保x轴能显示"18岁以下"类别;complete()函数:补全所有活动地点和年龄组的组合,无数据的组填充为0,保证绘图时该类别有对应的(高度为0的)条形;- 提前用dplyr计算百分比,比在ggplot中用
..count../tapply更直观,也更容易维护逻辑。
内容的提问来源于stack exchange,提问作者Hildrun Walter
相关产品推荐
相关产品推荐

