ggplot2绘图Y轴数值异常偏高(远超最大63%)及添加误差棒需求
问题
使用ggplot2绘制图表时遇到两个问题:
- Y轴显示数值高达400,但实际Cover最大值仅为63%,即使将Cover除以100,Y轴最大值变为4,仍不符合预期
- 需要为图表添加误差棒
数据结构
> data.frame': 720 obs. of 6 variables: > Site : Factor w/ 2 levels "DRP","PSP": 2 2 2 2 2 2 2 2 2 2 ... > Plot_ID : int 1 2 3 4 5 6 7 8 9 10 ... > Gradient: Factor w/ 3 levels "Low","Medium",..: 3 3 3 3 3 3 3 3 3 3 ... > Sp. : Factor w/ 4 levels "AG","FA","SN",..: 2 2 2 2 2 2 2 2 2 2 ... > P.A : int 1 1 1 1 1 1 1 1 1 1 ... > Cover : int 16 36 16 36 36 63 16 36 36 36 ...
数据表格示例
Site Plot_ID Gradient Sp. P.A Cover G2 Percentage > 1 PSP 1 High FA 1 16 3 0.16 > 2 PSP 2 High FA 1 36 3 0.36 > 3 PSP 3 High FA 1 16 3 0.16 > 4 PSP 4 High FA 1 36 3 0.36 > 5 PSP 5 High FA 1 36 3 0.36 > 6 PSP 6 High FA 1 63 3 0.63
数据集样本
Site Plot_ID Gradient Sp. P/A Cover PSP 1 High FA 1 16 DRP 1 Medium FA 0 0 PSP 1 High AG 1 16 DRP 1 Medium AG 0 0 PSP 1 High SS 0 0 DRP 1 Medium SS 0 0 PSP 1 High SN 1 16 DRP 1 Medium SN 0 0 PSP 2 High FA 1 36 DRP 2 Medium FA 0 0 PSP 2 High AG 0 0 DRP 2 Medium AG 1 3 PSP 2 High SS 0 0 DRP 2 Medium SS 0 0 PSP 2 High SN 0 0 DRP 2 Medium SN 0 0 PSP 3 High FA 1 16 DRP 3 High FA 1 1 PSP 3 High AG 1 16 DRP 3 High AG 1 36 PSP 3 High SS 0 0 DRP 3 High SS 0 0 PSP 3 High SN 0 0 DRP 3 High SN 0 0 PSP 4 High FA 1 36 DRP 4 High FA 1 16 PSP 4 High AG 0 0 DRP 4 High AG 1 1 PSP 4 High SS 0 0 DRP 4 High SS 1 16 PSP 4 High SN 0 0 DRP 4 High SN 1 16 PSP 5 High FA 1 36 DRP 5 Medium FA 0 0 PSP 5 High AG 0 0 DRP 5 Medium AG 0 0 PSP 5 High SS 0 0 DRP 5 Medium SS 0 0 PSP 5 High SN 0 0
当前代码
ggplot(df) + aes( x = Sp., fill = Gradient, group = Gradient, weight = Cover ) + geom_bar(position = "dodge") + scale_fill_brewer(palette = "Greys", direction = 1) + theme_bw() + facet_wrap(vars(Site))
解决方案
1. 解决Y轴数值异常问题
你的代码中使用geom_bar(weight = Cover)时,ggplot2会对每个分组下的所有Cover值求和,而不是取均值或单个值。因为每个Sp.+Gradient+Site组合对应多个Plot_ID的记录,求和后数值自然远大于单个Cover的最大值。
方法1:提前汇总数据(推荐,更灵活)
用dplyr包对数据按Site、Gradient、Sp.分组,计算平均Cover(以及后续误差棒需要的标准差):
library(dplyr) df_summary <- df %>% group_by(Site, Gradient, Sp.) %>% summarise( mean_cover = mean(Cover, na.rm = TRUE), sd_cover = sd(Cover, na.rm = TRUE), .groups = "drop" )
用汇总后的数据绘图:
ggplot(df_summary) + aes(x = Sp., y = mean_cover, fill = Gradient) + geom_bar(stat = "identity", position = "dodge") + scale_fill_brewer(palette = "Greys", direction = 1) + theme_bw() + facet_wrap(vars(Site)) + labs(y = "Cover (%)")
方法2:直接用stat_summary绘图
无需提前汇总,直接用stat_summary计算均值并绘制柱状图:
ggplot(df) + aes(x = Sp., y = Cover, fill = Gradient) + stat_summary(fun = mean, geom = "bar", position = "dodge") + scale_fill_brewer(palette = "Greys", direction = 1) + theme_bw() + facet_wrap(vars(Site)) + labs(y = "Cover (%)")
2. 添加误差棒
误差棒通常基于标准差或标准误,以下是两种实现方式:
基于提前汇总的数据
在汇总数据基础上,用geom_errorbar添加误差棒,注意设置对齐的dodge宽度:
ggplot(df_summary) + aes(x = Sp., y = mean_cover, fill = Gradient, group = Gradient) + geom_bar(stat = "identity", position = position_dodge(width = 0.9)) + geom_errorbar( aes(ymin = mean_cover - sd_cover, ymax = mean_cover + sd_cover), position = position_dodge(width = 0.9), width = 0.2 ) + scale_fill_brewer(palette = "Greys", direction = 1) + theme_bw() + facet_wrap(vars(Site)) + labs(y = "Cover (%)")
直接用stat_summary添加误差棒
无需提前汇总,用stat_summary同时绘制均值和误差棒:
# 用均值±标准差 ggplot(df) + aes(x = Sp., y = Cover, fill = Gradient) + stat_summary(fun = mean, geom = "bar", position = "dodge") + stat_summary( fun.data = mean_sdl, geom = "errorbar", position = position_dodge(width = 0.9), width = 0.2 ) + scale_fill_brewer(palette = "Greys", direction = 1) + theme_bw() + facet_wrap(vars(Site)) + labs(y = "Cover (%)")
如果想用标准误,可自定义计算函数:
mean_se <- function(x) { se <- sd(x, na.rm = TRUE)/sqrt(length(na.omit(x))) data.frame(y = mean(x, na.rm = TRUE), ymin = mean(x, na.rm = TRUE) - se, ymax = mean(x, na.rm = TRUE) + se) } ggplot(df) + aes(x = Sp., y = Cover, fill = Gradient) + stat_summary(fun = mean, geom = "bar", position = "dodge") + stat_summary( fun.data = mean_se, geom = "errorbar", position = position_dodge(width = 0.9), width = 0.2 ) + scale_fill_brewer(palette = "Greys", direction = 1) + theme_bw() + facet_wrap(vars(Site)) + labs(y = "Cover (%)")
内容的提问来源于stack exchange,提问作者Fabio Giacomelli
相关产品推荐
相关产品推荐

