在R中的另一个函数中使用ggplot()

tre*_*rev 46 r ggplot2

我正在尝试使用ggplot2库编写一个简单的绘图函数.但是对ggplot的调用没有找到函数参数.

考虑一个存储两个条件和两个我想要绘制的平均值的data.frame调用means(条件将出现在X轴上,表示在Y上).

library(ggplot2)
m <- c(13.8, 14.8)
cond <- c(1, 2)
means <- data.frame(means=m, condition=cond)
means
# The output should be:
#     means    condition
#   1 13.8     1
#   2 14.8     2

testplot <- function(meansdf)
{
  p <- ggplot(meansdf, aes(fill=meansdf$condition, y=meansdf$means, x = meansdf$condition))
  p + geom_bar(position="dodge", stat="identity")
}

testplot(means)
# This will output the following error:
# Error in eval(expr, envir, enclos) : object 'meansdf' not found
Run Code Online (Sandbox Code Playgroud)

所以似乎ggplot正在调用eval,它无法找到参数meansdf.有谁知道如何成功将函数参数传递给ggplot?

(注意:是的我可以直接调用ggplot函数,但最后我希望让我的绘图函数做更复杂的东西!:))

jhi*_*hin 37

由于Joris和Chase已经正确回答,标准的最佳实践是简单地省略该meansdf$部分并直接引用数据框列.

testplot <- function(meansdf)
{
  p <- ggplot(meansdf, 
              aes(fill = condition,
                  y = means,
                  x = condition))
  p + geom_bar(position = "dodge", stat = "identity")
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为aes在全局环境或传递给的数据框中查找引用的变量ggplot.这也是你的示例代码 - 使用meansdf$condition等 - 不起作用的原因:meansdf在全局环境中既不可用,也不在传递给它的数据框内可用ggplot,这meansdf本身也是如此.


在全局环境中而不是在调用环境中查找变量这一事实实际上是ggplot2中的一个已知错误,Hadley目前不认为它是可修复的.如果想要使用局部变量scale来影响用于绘图的数据,这会导致问题:

testplot <- function(meansdf)
{
  scale <- 0.5
  p <- ggplot(meansdf, 
              aes(fill = condition,
                  y = means * scale,   # does not work, since scale is not found
                  x = condition))
  p + geom_bar(position = "dodge", stat = "identity")
}
Run Code Online (Sandbox Code Playgroud)

Winston Chang在引用的GitHub问题中提供了一个非常好的解决方法:environment在调用期间将参数显式设置为当前环境ggplot.这是上面例子的样子:

testplot <- function(meansdf)
{
  scale <- 0.5
  p <- ggplot(meansdf, 
              aes(fill = condition,
                  y = means * scale,
                  x = condition),
              environment = environment())   # This is the only line changed / added
  p + geom_bar(position = "dodge", stat = "identity")
}

## Now, the following works
testplot(means)
Run Code Online (Sandbox Code Playgroud)

  • 如果我只想在函数内使用局部变量调用 geom_bar/geom_line/geom_point 怎么办 - 环境是一个未知参数。 (3认同)

Gre*_*gor 30

ggplot编程方式使用的"正确"方法是使用aes_string()而不是aes()使用列的名称作为字符而不是作为对象:

对于更多编程用途,例如,如果您希望用户能够将各种美学的列名称指定为参数,或者如果此函数在需要传递的包中,R CMD CHECK而没有关于没有定义的变量名称的警告,则可以使用aes_string(),作为字符需要的列.

testplot <- function(meansdf, xvar = "condition", yvar = "means",
                     fillvar = "condition") {
    p <- ggplot(meansdf,
                aes_string(x = xvar, y= yvar, fill = fillvar)) +
             geom_bar(position="dodge", stat="identity")
}
Run Code Online (Sandbox Code Playgroud)


小智 18

这是我在函数环境中定义变量的一个简单技巧(第二行):

FUN <- function(fun.data, fun.y) {
    fun.data$fun.y <- fun.data[, fun.y]
    ggplot(fun.data, aes(x, fun.y)) + 
        geom_point() + 
        scale_y_continuous(fun.y)    
}

datas <- data.frame(x = rnorm(100, 0, 1),
                    y = x + rnorm(100, 2, 2),
                    z = x + rnorm(100, 5, 10))
FUN(datas, "y")
FUN(datas, "z")
Run Code Online (Sandbox Code Playgroud)

请注意当使用不同的变量或数据集时,y轴标签也会如何变化.


Cha*_*ase 16

我认为您不需要meansdf$在函数调用中包含该部分.这似乎适用于我的机器:

meansdf <- data.frame(means = c(13.8, 14.8), condition = 1:2)

testplot <- function(meansdf)
{
p <- ggplot(meansdf, aes(fill=condition, y=means, x = condition))
p + geom_bar(position="dodge", stat="identity")
}


testplot(meansdf)
Run Code Online (Sandbox Code Playgroud)

生产:

在此输入图像描述

  • @trev:因为ggplot在数据帧meansdf的"环境"中查找变量. (3认同)

Jor*_*eys 15

这是前面讨论的问题的一个例子.基本上,它归结为ggplot2主要用于全球环境.在aes()调用中,变量在全局环境中或在指定的数据帧中查找.

library(ggplot2)
means <- data.frame(means=c(13.8,14.8),condition=1:2)

testplot <- function(meansdf)
{
  p <- ggplot(meansdf, aes(fill=condition, 
          y=means, x = condition))
  p + geom_bar(position="dodge", stat="identity")
}
Run Code Online (Sandbox Code Playgroud)

编辑:

更新:看到其他答案并更新ggplot2包后,上面的代码工作.正如评论中所解释的那样,原因是ggplot将在全局环境中查找aes中的变量(当数据帧专门添加为meandf $ ...时)或在上述环境中.

为此,请务必使用最新版本的ggplot2.


Val*_*tin 8

如果将变量(列名称)传递给不带引号的自定义绘图函数很重要,而函数中使用不同的变量名称,那么我尝试的另一个解决方法是使用match.call()and eval(也像这里一样):

library(ggplot2)

meansdf <- data.frame(means = c(13.8, 14.8), condition = 1:2)

testplot <- function(df, x, y) {
  arg <- match.call()
  scale <- 0.5
  p <- ggplot(df, aes(x = eval(arg$x),
                      y = eval(arg$y) * scale,
                      fill = eval(arg$x)))
  p + geom_bar(position = "dodge", stat = "identity")
}

testplot(meansdf, condition, means)
Run Code Online (Sandbox Code Playgroud)

由reprex 包(v0.2.1)于 2019-01-10 创建

另一种解决方法是将带引号的变量传递给自定义绘图函数,方法是使用get()

meansdf <- data.frame(means = c(13.8, 14.8), condition = 1:2)

testplot <- function(df, x, y) {
  scale <- 0.5
  p <- ggplot(df, aes(x = get(x),
                      y = get(y) * scale,
                      fill = get(x)))
  p + geom_bar(position = "dodge", stat = "identity")
}

testplot(meansdf, "condition", "means")
Run Code Online (Sandbox Code Playgroud)

由reprex 包(v0.2.1)于 2019-01-10 创建

  • 获得完美作品!比其他答案简单得多 (2认同)