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

时间:2011-02-24 15:35:13

标签: r ggplot2

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

考虑一个名为data.frame的{​​{1}},它存储两个条件和两个我想要绘制的平均值(条件将出现在X轴上,表示在Y上)。

means

因此,似乎ggplot正在调用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 ,它无法找到参数eval。有谁知道我怎么能成功地将函数参数传递给ggplot?

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

11 个答案:

答案 0 :(得分:34)

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

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

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


在全局环境中而不是在调用环境中查找变量的事实实际上是Hadley目前不认为可修复的a known bug in ggplot2。 如果希望使用局部变量(例如meansdf)来影响用于绘图的数据,则会导致问题:

scale

Winston Chang在引用的GitHub问题中为此案例提供了一个非常好的解决方法:在调用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") } 期间将environment参数显式设置为当前环境。 以下是上述示例的结果:

ggplot

答案 1 :(得分:26)

以编程方式使用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")
}

答案 2 :(得分: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")

注意当使用不同的变量或数据集时,y轴标签也会发生变化。

答案 3 :(得分: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)

生产:

enter image description here

答案 4 :(得分:15)

这是一个讨论earlier问题的例子。基本上,它归结为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")
}

编辑:

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

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

答案 5 :(得分:3)

这让我很沮丧。我想发送具有不同变量名称的不同数据帧,我希望能够从数据框中绘制不同的列。我终于通过创建一些虚拟(全局)变量来处理函数

中的绘图和强制赋值
plotgraph function(df,df.x,df.y) {

dummy.df <<- df
dummy.x <<- df.x
dummy.y <<- df.y

p = ggplot(dummy.df,aes(x=dummy.x,y=dummy.y,.....)
print(p)

}

然后在主代码中我可以调用函数

plotgraph(data,data$time,data$Y1)
plotgraph(data,data$time,data$Y2)

答案 6 :(得分:1)

简短回答:使用qplot

答案很长: 从本质上讲,你想要这样的东西:

my.barplot <- function(x=this.is.a.data.frame.typically) {
   # R code doing the magic comes here
   ...
}

但是缺乏灵活性,因为你必须坚持一致的列命名,以避免恼人的R范围特性。当然,下一个逻辑步骤是:

my.barplot <- function(data=data.frame(), x=..., y....) {
   # R code doing something really really magical here
   ...
}

然后开始看起来像是对qplot()的调用,对吗?

qplot(data=my.data.frame, x=some.column, y=some.other column,
      geom="bar", stat="identity",...)

当然,现在你想改变比例标题之类的东西,但是这个功能很方便......好消息是范围问题大多已经消失了。

my.plot <- qplot(data=my.data.frame, x=some.column, y=some.other column,...)
set.scales(p, xscale=scale_X_continuous, xtitle=NULL,
           yscale=scale_y_continuous(), title=NULL) {
  return(p + xscale(title=xtitle) + yscale(title=ytitle))
}
my.plot.prettier <- set.scale(my.plot, scale_x_discrete, 'Days',
                              scale_y_discrete, 'Count')

答案 7 :(得分:1)

另一种解决方法是将aes(...)定义为函数的变量:

func<-function(meansdf, aes(...)){}

这对我来说在类似的主题上工作得很好

答案 8 :(得分:1)

你不需要任何花哨的东西。甚至不是虚拟变量。您只需要在函数内添加print(),就像在控制台中显示某些内容时使用cat()一样。

myplot&lt; - ggplot(......)+无论你想要什么 print(myplot)

它在同一个函数中不止一次地为我工作

答案 9 :(得分:0)

我只是在函数内生成具有所需名称的新数据框变量:

testplot <- function(df, xVar, yVar, fillVar) {
    df$xVar = df[,which(names(df)==xVar)]
    df$yVar = df[,which(names(df)==yVar)]
    df$fillVar = df[,which(names(df)==fillVar)]
    p <- ggplot(df,
                aes(x=xvar, y=yvar, fill=fillvar)) +
             geom_bar(position="dodge", stat="identity")
    }

答案 10 :(得分:0)

如果将变量(列名)传递给不带引号的自定义绘图函数很重要,而函数中使用了不同的变量名,那么我尝试的另一种解决方法是利用match.call()和{ {1}}(也类似于here):

eval

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

另一种解决方法,但使用引号将变量传递给自定义绘图功能是使用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)

get()

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