自定义ggplot派生函数:含if分支的函数调用错误排查
问题与解决方案
问题背景
自定义两个ggplot函数分别生成bar图(make_bar_graph)和jitter图(make_jitter_graph),封装成make_graphs函数后,希望根据全局环境中是否存在OBJECT对象自动选择调用哪个绘图函数,但调用时始终报错“找不到对象(如Species)”。
原代码与报错信息
原代码
data <- iris #graph 1 function: make_bar_graph <- function(data, x, y, xlab = NULL, ylab = NULL, linewidth = 0.5, colour = NULL, fill = NULL, stat.colour = "black", bar.position = "dodge", bar.width = 0.8, bar.colour = "black", point.position = position_jitterdodge(0.7), point.size = 2, errorbar.position = position_dodge(0.8), errorbar.width = 0.3, errorbar.colour = "black", ...) { ggplot(data = data, aes(x = {{x}}, y = {{y}}, fill = {{fill}}, colour = {{colour}})) + geom_bar(stat="summary", fun = "mean", position = bar.position, width = bar.width, colour = bar.colour, show.legend = FALSE, inherit.aes=TRUE, ...) + geom_hline(yintercept=0) + labs(x=xlab, y=ylab) + geom_point(position = point.position, size = point.size, show.legend = FALSE, ...) + scale_fill_manual(values = c("gray95", "gray85", "gray75", "gray65", "gray55", "gray45")) + scale_colour_manual(values=c("#FF5695", "#8E8DFF", "#8CB5FF", "#79DBFF", "#42EFD7", "#79EBAC")) + theme(axis.title.x = element_blank()) } #graph 1 example: make_bar_graph(data, Species, Petal.Width, fill = Species, colour = Species) #graph2 function make_jitter_graph <- function(data, x, y, xlab = NULL, ylab = NULL, linewidth = 0.5, size.jitter = 2, colour = NULL, fill = NULL, stat.colour = "black", ...) { ggplot(data = data, aes(x = {{x}}, y = {{y}}, fill = {{fill}}, colour = {{colour}})) + stat_summary(fun = median, show.legend = FALSE, geom="crossbar", linewidth = linewidth, colour = stat.colour, ...) + geom_jitter(show.legend = FALSE, width = 0.25, size = size.jitter, ...) + labs(x=xlab, y=ylab) } #graph 2 example: make_jitter_graph(data = data, x = Species, y = Petal.Width, colour = Species, fill = Species) #封装函数 make_graphs <- function(data, x, y, xlab = NULL, ylab = NULL, linewidth = 0.5, colour = NULL, fill = NULL, stat.colour = "black", bar.position = "dodge", bar.width = 0.8, bar.colour = "black", point.position = position_jitterdodge(0.7), point.size = 2, errorbar.position = position_dodge(0.8), errorbar.width = 0.3, errorbar.colour = "black", size.jitter = 2, ...){ if(exists("OBJECT")){ require(ggpubr) make_bar_graph(data = data, x=x, y=y, linewidth = linewidth, colour = colour, fill = fill, stat.colour = stat.colour, bar.position=bar.position, bar.width=bar.width, bar.colour=bar.colour, point.position=point.position, point.size=point.size, errorbar.position = errorbar.position, errorbar.width = errorbar.width, errorbar.colour = errorbar.colour, ...) }else{ make_jitter_graph(data = data, x=x, y=y, linewidth = linewidth, colour = colour, fill = fill, stat.colour = stat.colour, size.jitter=size.jitter, ...) } } # 测试:OBJECT不存在时调用 make_graphs(data = data, x = Species, y = Petal.Width, colour = Species, fill = Species) # 测试:OBJECT存在时调用 OBJECT <- 4 make_graphs(data = data, x = Species, y = Petal.Width, colour = Species, fill = Species)
报错信息
- 当
OBJECT不存在时,报错:Error in stat_summary(fun = median, show.legend = FALSE, geom = "crossbar", : ℹ Error occurred in the 1st layer. Caused by error in `FUN()`: ! object 'Species' not found - 当
OBJECT存在时,报错:Error in geom_bar(stat = "summary", fun = "mean", position = bar.position, : ℹ Error occurred in the 1st layer. Caused by error in `FUN()`: ! object 'Species' not found
问题原因
报错核心是非标准求值(NSE)参数传递失败:子函数make_bar_graph和make_jitter_graph使用{{}}(curly-curly)捕获列名表达式,但make_graphs中直接传递x=x、colour=colour时,未保留原表达式上下文,导致子函数无法从data中解析对应列名,反而去全局环境查找Species对象,最终找不到报错。
另外,exists("OBJECT")默认在当前函数环境查找,未明确指定检查全局环境,可能引发环境查找歧义。
解决方案
修改make_graphs函数,对需要非标准求值的参数(x、y、colour、fill)用{{}}包裹后传递给子函数,同时明确指定exists的环境为全局环境:
修改后的make_graphs函数
make_graphs <- function(data, x, y, xlab = NULL, ylab = NULL, linewidth = 0.5, colour = NULL, fill = NULL, stat.colour = "black", bar.position = "dodge", bar.width = 0.8, bar.colour = "black", point.position = position_jitterdodge(0.7), point.size = 2, errorbar.position = position_dodge(0.8), errorbar.width = 0.3, errorbar.colour = "black", size.jitter = 2, ...){ # 明确检查全局环境中的OBJECT if(exists("OBJECT", envir = globalenv())){ require(ggpubr) make_bar_graph(data = data, x={{x}}, y={{y}}, linewidth = linewidth, colour={{colour}}, fill={{fill}}, stat.colour = stat.colour, bar.position=bar.position, bar.width=bar.width, bar.colour=bar.colour, point.position=point.position, point.size=point.size, errorbar.position = errorbar.position, errorbar.width = errorbar.width, errorbar.colour = errorbar.colour, ...) }else{ make_jitter_graph(data = data, x={{x}}, y={{y}}, linewidth = linewidth, colour={{colour}}, fill={{fill}}, stat.colour = stat.colour, size.jitter=size.jitter, ...) } }
验证修改后的代码
测试
OBJECT不存在的情况:# 确保OBJECT不存在 if(exists("OBJECT", envir = globalenv())) rm(OBJECT) make_graphs(data = data, x = Species, y = Petal.Width, colour = Species, fill = Species)此时会正常生成jitter图。
测试
OBJECT存在的情况:OBJECT <- 4 make_graphs(data = data, x = Species, y = Petal.Width, colour = Species, fill = Species)此时会正常生成bar图。
内容的提问来源于stack exchange,提问作者MM1
相关产品推荐
相关产品推荐

