ggplot2中geom_errorbar异常与条件设置点形状失效问题
问题背景
我有一组拆分存储在列表中的数据框,需为每个数据框绘制折线图:未检出(低于检出限)的数据使用空心符号(点形状值为1)展示,检出数据(均值+标准差)使用填充符号(点形状值为16)展示。
以下为可复现问题的示例代码:
OutdoorAir <- data.frame( "Sample" = c("Air", "Air", "Air", "Air","Aerosol", "Aerosol", "Aerosol", "Aerosol"), "Date" = c("1980", "1990", "2000", "2010", "1980", "1990", "2000", "2010"), "Value" = c(331, 250, 484, 221, 545, 131, 417, 476), "Locality" = c("Paris", "Lyon", "Paris", "Lyon", "Paris", "Lyon", "Paris", "Lyon"), "Less.Than" = c("<","<","","<","","","<",""), "Uncertainty" = c(NA,NA,45,NA,10,8,NA,71), "Nuclides" = c("K-40","K-40", "K-40", "K-40", "C-14", "C-14", "C-14", "C-14")) OutdoorAir_l <- split(OutdoorAir,list(OutdoorAir$Sample,OutdoorAir$Locality, OutdoorAir$Nuclides), drop=TRUE) lapply(names(OutdoorAir_l), function(i){ ggplot(OutdoorAir_l[[i]], aes(Date, Value, group = Nuclides, col = as.factor(Nuclides))) + colorization + geom_errorbar(aes(ymin=Value-Uncertainty, ymax=Value+Uncertainty), color = "black") + geom_point() + scale_shape_manual(values=ifelse("Less.Than" == "<",c(1),c(15)), guide = "none") + ggsave(paste(i, ".png", sep = ""), dpi = 100, width = 30, height = 20, units = "cm") }) dev.off()
数据规则说明
- 若检测结果低于检出限,
Less.Than列填充值为<,此时Value列存储的实际为检出限值,需在图中显示为空心圆 - 其余情况
Value列为检测均值,Uncertainty列为标准差
待解决问题
- 上述代码中
scale_shape_manual函数无法按Less.Than列的条件正确匹配点形状,写法存在什么错误? geom_errorbar绘制的误差线存在样式不一致问题:部分误差线为带两端水平端帽的标准样式,部分仅显示单条竖线,该问题的成因是什么?
问题解答
1. 点形状匹配错误的原因
代码中形状映射存在3个核心问题:
- 未在美学映射中绑定形状字段:
geom_point()没有将shape参数和Less.Than列关联,ggplot无法根据每行数据的属性动态分配点形状 - 条件判断逻辑完全失效:
ifelse("Less.Than" == "<",c(1),c(15))是在判断字符串常量"Less.Than"是否等于<,而非逐行判断数据框中Less.Than列的值,永远只会返回单一值15 - 形状值不符合需求:代码中检出数据配置的形状是15(实心方块),和需求要求的16(实心圆)不匹配
2. 误差线样式不一致的原因
异常样式的核心成因是低于检出限的数据Uncertainty列为NA:
- 当
Uncertainty为有效值时,ymin = Value - Uncertainty和ymax = Value + Uncertainty是两个不同数值,误差线有正常的上下延伸长度,会完整绘制两端的水平端帽 - 当
Uncertainty为NA时,ymin和ymax计算结果均为NA,ggplot会默认在数据点位置绘制长度为0的误差线,两端端帽完全重合,视觉上就呈现为单条竖线 - 低于检出限的数据本身不需要展示误差线,直接过滤这部分数据的误差线绘制即可解决样式问题。
修正后可运行代码
library(ggplot2) # 注:原代码中colorization为自定义主题/色板,此处可替换为自己的配色配置 OutdoorAir_l <- split(OutdoorAir,list(OutdoorAir$Sample,OutdoorAir$Locality, OutdoorAir$Nuclides), drop=TRUE) lapply(names(OutdoorAir_l), function(i){ p <- ggplot(OutdoorAir_l[[i]], aes(x = Date, y = Value, group = Nuclides, col = as.factor(Nuclides))) + # 仅为检出数据绘制误差线,过滤未检出的NA值 geom_errorbar(data = ~subset(.x, Less.Than != "<"), aes(ymin=Value-Uncertainty, ymax=Value+Uncertainty), color = "black", width = 0.2) + # 补充折线图所需的连线层 geom_line() + # 将形状映射到Less.Than字段 geom_point(aes(shape = Less.Than), size = 3) + # 手动匹配两类点的形状:< 对应空心圆(1),正常值对应实心圆(16) scale_shape_manual(values = c("<" = 1, "" = 16), guide = "none") ggsave(paste0(i, ".png"), plot = p, dpi = 100, width = 30, height = 20, units = "cm") }) dev.off()
内容的提问来源于stack exchange,提问作者Sylvain
相关产品推荐
相关产品推荐

