You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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, ...)
  }
}

验证修改后的代码

  1. 测试OBJECT不存在的情况:

    # 确保OBJECT不存在
    if(exists("OBJECT", envir = globalenv())) rm(OBJECT)
    make_graphs(data = data, x = Species, y = Petal.Width, colour = Species, fill = Species)
    

    此时会正常生成jitter图。

  2. 测试OBJECT存在的情况:

    OBJECT <- 4
    make_graphs(data = data, x = Species, y = Petal.Width, colour = Species, fill = Species)
    

    此时会正常生成bar图。

内容的提问来源于stack exchange,提问作者MM1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 05:25:50