ggplot绘图报错‘attempt to replicate an object of type 'language'’求助
用ggplot绘制点与线段的报错解决
需求说明
需要使用ggplot2的geom_point()和geom_segment()绘图:
- 绘制点:x固定为2021,y取
intrcpt列的值 - 绘制线段:起始x为每组
network_id对应数据中的最早年份(2019/2020/2021),起始y取对应年份的simXXXX列值;终止x固定为2022,终止y取sim2022列值
数据示例
# 实际数据包含43个network_id,以下为单组示例 foo <- structure(list( network_id = c(1L, 1L, 1L), intrcpt = c(0.9008887, 0.9008887, 0.9008887), slope = c(-0.05032728, -0.05032728, -0.05032728), interceptx = c(2021L, 2021L, 2021L), sim2019 = c(1.001543, 1.001543, 1.001543), sim2020 = c(0.951216, 0.951216, 0.951216), sim2021 = c(0.9008887, 0.9008887, 0.9008887), sim2022 = c(0.8505614, 0.8505614, 0.8505614), year = c(2019L, 2021L, 2022L) ), class = "data.frame", row.names = c("1", "2", "3"))
原代码及报错信息
原代码
resfil0 <- foo %>% group_by(network_id) %>% mutate(left.seg.y=ifelse(any(year==2019), quo(sim2019), ifelse(any(year==2020), quo(sim2020), quo(sim2021))), left.seg.x=ifelse(any(year==2019), 2019, ifelse(any(year==2020), 2020, 2021)) ) ggplot(resfil0, aes(x=2021, y=intrcpt, label=network_id)) + geom_point() + geom_segment(aes(x=left.seg.x, y=!!left.seg.y, xend=2022, yend=sim2022))
报错信息
Error in `mutate()`: ! Problem while computing `left.seg.end = ifelse(...)`. i The error occurred in group 1: network_id = 1. Caused by error in `rep()`: ! attempt to replicate an object of type 'language'
问题分析
- 核心错误原因:使用
quo()会返回语言对象(表达式),而ifelse()会尝试将这个对象复制到分组的每一行,R无法复制语言类型的对象,因此触发报错。 - 逻辑冗余:原代码用多层
ifelse(any(year==XXX))判断最早年份,不如直接取组内年份的最小值更简洁可靠。 - 绘图语法错误:即便
quo()可用,!!的使用场景是在dplyr或ggplot的表达式中引用符号,但此处不需要动态引用列名,直接提取数值即可。
修正后的代码
数据预处理
library(dplyr) library(ggplot2) resfil0 <- foo %>% group_by(network_id) %>% mutate( # 直接获取组内最早年份 min_year = min(year), # 根据最早年份匹配对应sim列的数值 left.seg.y = case_when( min_year == 2019 ~ sim2019, min_year == 2020 ~ sim2020, min_year == 2021 ~ sim2021 ), left.seg.x = min_year ) %>% ungroup() # 取消分组,避免后续绘图的分组干扰
绘图代码
ggplot(resfil0, aes(label = network_id)) + # 绘制固定x=2021的点 geom_point(aes(x = 2021, y = intrcpt)) + # 绘制线段:起始点由left.seg.x/left.seg.y定义,终止点固定为2022/sim2022 geom_segment(aes(x = left.seg.x, y = left.seg.y, xend = 2022, yend = sim2022))
修正要点
- 用
min(year)直接获取组内最早年份,替代多层ifelse判断,逻辑更简洁且不易出错 - 用
case_when()直接提取对应年份的sim列数值,避免使用quo()生成语言对象 - 绘图时无需使用
!!,因为left.seg.y已经是预处理好的普通数值列
内容的提问来源于stack exchange,提问作者Stuart
相关产品推荐
相关产品推荐

