You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 16:14:59