首页 > 解决方案 > 在函数中生成表达式并在 R 中返回

问题描述

我试图在一个单独的函数中生成一个表达式。防止重复代码。然后将表达式传递到 ggplot。

这很好用(一个简单的表达式)

ggplot(mpg, aes(x = model, y = displ)) + geom_boxplot()

这也很好用(带有公式和字符串的表达式)

x = "displ"
xVar = expr(!!ensym(x) * 2)
ggplot(mpg, aes(x = model, y = !!xVar)) + geom_boxplot()

这不起作用(公式中生成的表达式)

makeExpression = function(varName){
    return(expr(!!ensym(varName) * 2))
}
xVar = makeExpression(x)
ggplot(mpg, aes(x = model, y = !!xVar)) + geom_boxplot()

这有效(在公式中生成的表达式带有肮脏的技巧)

makeExpression = function(varName){
    a = varName
    return(expr(!!ensym(varName) * 2))
}
xVar = makeExpression(x)
ggplot(mpg, aes(x = model, y = !!xVar)) + geom_boxplot()

第三个示例给出以下错误: *Error in x * 2 : non-numeric argument to binary operator*

这意味着不评估提供给函数的“x”。x 包含一个列名的字符串。表达式应该是:displ * 2

有趣的是,在函数中访问 varName 一次后,第 4 个示例也可以工作。请注意,从未使用过a 。

我不明白为什么会这样。对我来说,这看起来像是一个肮脏的黑客,但它可能与范围界定有关。有没有更清洁的方法来做到这一点?

标签: rexpression

解决方案


如果要将包含名称的变量作为字符值传递,则要使用sym而不是ensym. sym将评估要传递给它的参数以获取值。ensym仅用于在函数中捕获传递给函数的表达式。请注意,此魔法仅在参数仍处于“承诺”状态并且尚未由函数中的任何先前代码评估时才有效。这就是第 4 个示例“有效”的原因,因为额外的代码会强制对 promise 进行评估。


推荐阅读