使用ggplot2的geom_col绘制分组条形图时柱子高度一致问题排查
分组条形图柱子高度一致的问题解决
问题描述
想要绘制各柱子高度不同的分组条形图,但当前代码生成的条形图所有柱子高度一致。使用geom_col作为绘图函数,但不清楚问题出在哪里。
原代码:
# Add a new column to indicate age group young$age_group <- "Young" old$age_group <- "Old" # Combine the data frames combined_df <- bind_rows(young, old) # Plot ggplot(combined_df, aes(x = age_group, y = implvdm, fill = gndr)) + geom_col(position = "dodge") + labs(x = "Age Group", y = "implvdm", fill = "Gender") + theme_minimal()
示例数据:
young <- structure(list(gndr = c("woman", "man", "man", "man", "woman", "man", "man", "woman", "woman", "man"), yrbrn = c(2003L, 1999L, 1998L, 1999L, 2002L, 1999L, 2001L, 2004L, 2004L, 1999L), agea = c(18L, 22L, 23L, 22L, 19L, 22L, 21L, 17L, 18L, 22L), impdema = c(6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L), implvdm = c(10L, 7L, 9L, 7L, 10L, 10L, 9L, 10L, 8L, 10L), accalaw = c(0L, 2L, 1L, 0L, 5L, 3L, 3L, 0L, 2L, 0L), imwbcnt = c(9L, 2L, 7L, 4L, 0L, 10L, 2L, 3L, 7L, 6L), euftf = c(4L, 3L, 7L, 4L, 6L, 5L, 8L, 5L, 5L, 9L), freehms = c(1L, 3L, 1L, 2L, 2L, 1L, 1L, 2L, 1L, 2L), gincdif = c(2L, 3L, 2L, 3L, 2L, 3L, 2L, 3L, 2L, 3L), prtclffi = c(NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_)), row.names = c(NA, -10L), class = "data.frame") old <- structure(list(gndr = c("man", "woman", "woman", "man", "woman", "man", "woman", "woman", "woman", "woman"), yrbrn = c(1943L, 1975L, 1974L, 1977L, 1959L, 1993L, 1990L, 1993L, 1958L, 1971L ), agea = c(78L, 46L, 47L, 44L, 63L, 27L, 31L, 29L, 63L, 50L), impdema = c(6L, 6L, 6L, 5L, 6L, 6L, 6L, 3L, 6L, 1L), implvdm = c(10L, 9L, 9L, 6L, 8L, 10L, 4L, 8L, 9L, 10L), accalaw = c(0L, 8L, 2L, 2L, 2L, 0L, 3L, 3L, 9L, 0L), imwbcnt = c(9L, 1L, 3L, 3L, 5L, 5L, 7L, 4L, 3L, 7L), euftf = c(8L, 2L, 4L, 3L, 4L, 3L, 7L, 5L, 4L, 5L), freehms = c(2L, 2L, 4L, 2L, 2L, 1L, 4L, 2L, 4L, 1L), gincdif = c(2L, 2L, 2L, 3L, 2L, 4L, 1L, 2L, 2L, 3L), prtclffi = c(NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_)), row.names = c(NA, -10L), class = "data.frame")
原因分析
geom_col(stat = "identity")默认会将同一分组(age_group + gndr)下的所有implvdm数值累加,最终柱子高度是该组的总和。如果数据中各组总和恰好相近,就会出现柱子高度几乎一致的情况。而你想要的应该是每个分组的汇总统计值(比如均值、中位数),或是每个个体的条形按分组独立展示。
解决方案
方案1:先汇总数据再绘图
使用dplyr对数据按age_group和gndr分组,计算所需的统计量(这里以均值为例),再用geom_col绘图:
library(dplyr) library(ggplot2) # 数据分组汇总(计算均值) summary_df <- combined_df %>% group_by(age_group, gndr) %>% summarise(mean_implvdm = mean(implvdm), .groups = "drop") # 绘制分组条形图 ggplot(summary_df, aes(x = age_group, y = mean_implvdm, fill = gndr)) + geom_col(position = "dodge") + labs(x = "年龄组", y = "implvdm均值", fill = "性别") + theme_minimal()
方案2:用stat_summary直接在绘图时计算统计量
无需提前汇总数据,直接在ggplot中使用stat_summary计算并绘制统计量:
ggplot(combined_df, aes(x = age_group, y = implvdm, fill = gndr)) + stat_summary(fun = mean, geom = "col", position = "dodge") + labs(x = "年龄组", y = "implvdm均值", fill = "性别") + theme_minimal()
方案3:展示每个个体的条形(若需要)
如果想要展示每个样本的数据,而非汇总值,可以添加group参数确保每个个体条形独立展示:
ggplot(combined_df, aes(x = age_group, y = implvdm, fill = gndr, group = interaction(age_group, gndr))) + geom_col(position = position_dodge(width = 0.9)) + labs(x = "年龄组", y = "implvdm", fill = "性别") + theme_minimal()
结果说明
方案1和方案2会生成每个年龄组内男女各一个柱子,高度为对应分组的均值(可替换为median、sum等其他统计量),满足"各柱子高度不同"的分组条形图效果。
内容的提问来源于stack exchange,提问作者Espejito
相关产品推荐
相关产品推荐

