我正在尝试使用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函数,但最后我希望让我的绘图函数做更复杂的东西!:))
答案 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)
生产:
答案 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创建