基于Base R将带引号函数参数传递至另一函数的...参数
用Base R解决裸变量传递到split_group函数的问题
问题背景
需要将geom_col_wrap函数group参数中的裸变量(如c(vs, am))传递给split_group函数,但直接传递会触发列不存在的错误——因为split_group依赖substitute(...)处理参数,却无法解析group这个中间变量。
原函数代码
geom_col_wrap函数
# 为便于阅读,删除了函数的其余部分 geom_col_wrap = function(data, mapping, group, ...) { data |> split_group(group) }
split_group函数
# 该函数基于tidytable包实现 split_group = function(data, ...) { by_quote = as.list(substitute(...())) by = sapply(by_quote, deparse) split = vctrs::vec_split(data, data[c(by)]) out = split[["val"]] names = do.call(paste, c(split[["key"]], sep = "_")) names(out) = names return(out) }
错误重现
调用geom_col_wrap传入裸变量组时会报错:
geom_col_wrap( mtcars, mapping = ggplot2::aes(x = cyl, y = hp, color = am), group = c(vs, am) )
错误信息:
Error in `[.data.frame`(data, c(by)) : undefined columns selected
错误根源是split_group中的as.list(substitute(...()))将传入的group直接解析为字符串"group",而非其实际对应的c(vs, am),导致无法匹配数据框列名。
Base R解决方案
通过捕获参数表达式并解析变量名的方式解决,无需依赖rlang或...参数:
修改后的geom_col_wrap函数
geom_col_wrap = function(data, mapping, group, ...) { # 捕获group参数的原始表达式 group_expr = substitute(group) data |> split_group(group_expr) }
修改后的split_group函数
split_group = function(data, group_expr) { # 解析表达式,提取内部变量符号 by_quote = as.list(group_expr)[-1] # 移除c()调用,保留变量列表 by = sapply(by_quote, deparse) # 将符号转为列名字符串 split = vctrs::vec_split(data, data[c(by)]) out = split[["val"]] names = do.call(paste, c(split[["key"]], sep = "_")) names(out) = names return(out) }
验证调用
修改后重新执行调用即可正常返回分组结果:
result = geom_col_wrap( mtcars, mapping = ggplot2::aes(x = cyl, y = hp, color = am), group = c(vs, am) ) str(result) # 查看按vs和am分组后的列表结构
核心原理
- 在
geom_col_wrap中用substitute(group)捕获用户传入的原始表达式(而非变量值),确保传递给split_group的是c(vs, am)而非字符串"group"。 - 在
split_group中解析传入的表达式:通过as.list(group_expr)[-1]剥离c()函数调用,提取内部的变量符号,再用deparse将符号转换为可用于索引数据框的列名字符串。
内容的提问来源于stack exchange,提问作者arturhgq
相关产品推荐
相关产品推荐

