47

aes当我使用 ggplot 绘图时,我正在尝试使用局部变量。这是我的问题归结为本质:

xy <- data.frame(x=1:10,y=1:10)

plotfunc <- function(Data,YMul=2){
    ggplot(Data,aes(x=x,y=y*YMul))+geom_line()
}

plotfunc(xy)

这会导致以下错误:

Error in eval(expr, envir, enclos) : object 'YMul' not found

好像我不能在aes. aes会不会是局部变量超出作用域后执行的内容造成的?我怎样才能避免这个问题(除了不使用内部的局部变量aes)?

4

6 回答 6

39

我会捕捉当地的环境,

xy <- data.frame(x=1:10,y=1:10)

plotfunc <- function(Data, YMul = 2){
    .e <- environment()
    ggplot(Data, aes(x = x, y = y*YMul), environment = .e) + geom_line()
}

plotfunc(xy)
于 2012-05-19T06:33:06.520 回答
10

这是一种替代方法,它允许您通过YMul参数传递任何值,而无需将其添加到Datadata.frame 或全局环境中:

plotfunc <- function(Data, YMul = 2){
    eval(substitute(
        expr = {
            ggplot(Data,aes(x=x,y=y*YMul)) + geom_line()
        }, 
        env = list(YMul=YMul)))
    }

plotfunc(xy, YMul=100)

要了解它是如何工作的,请单独尝试以下行:

substitute({ggplot(Data, aes(x=x, y=y*YMul))}, list(YMul=100))
于 2012-05-18T20:50:13.753 回答
5

ggplot()'saes期望YMuldata数据框中的一个变量。尝试包括YMull那里:

感谢@Justin:ggplot()'saes似乎首先YMuldata数据框中寻找,如果没有找到,然后在全球环境中。我喜欢将这样的变量添加到数据框中,如下所示,因为这在概念上对我来说是有意义的。我也不必担心全局变量的更改会对函数产生意想不到的后果。但所有其他答案也是正确的。所以,选择适合你的。

require("ggplot2")
xy <- data.frame(x = 1:10, y = 1:10)
xy <- cbind(xy, YMul = 2)

ggplot(xy, aes(x = x, y = y * YMul)) + geom_line()

或者,如果您想要示例中的函数:

plotfunc <- function(Data, YMul = 2)
{
    ggplot(cbind(Data, YMul), aes(x = x, y = y * YMul)) + geom_line()
}

plotfunc(xy)
于 2012-05-18T20:35:36.327 回答
4

我正在使用 ggplot2,您的示例似乎适用于当前版本。

但是,很容易想出仍然会造成麻烦的变体。我自己对类似的行为感到困惑,这就是我找到这篇文章的方式(“ggplot 如何在传递时评估变量”的谷歌搜索结果)。例如,如果我们将 ggplot 从 plotfunc 中移出:

xy <- data.frame(x=1:10,y=1:10)

plotfunc <- function(Data,YMul=2){
  geom_line(aes(x=x,y=y*YMul))
}

ggplot(xy)+plotfunc(xy)
# Error in eval(expr, envir, enclos) : object 'YMul' not found

在上面的变体中,“捕获本地环境”不是一个解决方案,因为 ggplot 不是从函数内部调用的,只有 ggplot 有“environment=”参数。

但是现在有一系列函数“aes_”、“aes_string”、“aes_q”,它们类似于“aes”,但捕获局部变量。如果我们在上面使用“aes_”,我们仍然会得到一个错误,因为现在它不知道“x”。但是直接引用数据很容易,这样就解决了问题:

plotfunc <- function(Data,YMul=2){
  geom_line(aes_(x=Data$x,y=Data$y*YMul))
}
ggplot(xy)+plotfunc(xy)
# works
于 2016-03-07T19:39:03.653 回答
1

你看过@wch(W. Chang)给出的解决方案吗?

https://github.com/hadley/ggplot2/issues/743

我认为这是更好的

本质上类似于@baptiste,但在对 ggplot 的调用中直接包含对环境的引用

我在这里报告

g <- function() {
  foo3 <- 4
  ggplot(mtcars, aes(x = wt + foo3, y = mpg),
         environment = environment()) +
    geom_point()
}

g()
# Works
于 2014-05-20T17:17:39.203 回答
0

如果您在函数之外执行代码,它会起作用。如果你在YMul全局定义的函数中执行代码,它就可以工作。我不完全了解内部工作原理,ggplot但这有效......

YMul <- 2

plotfunc <- function(Data){
    ggplot(Data,aes(x=x,y=y*YMul))+geom_line()
}

plotfunc(xy)
于 2012-05-18T20:39:53.070 回答