我为我生成ggplots的多个站点提供了csv的时间序列数据,显示了使用changepoint包的方法的变化。我编写了一个函数,它接受csv,执行一些计算以获得方法然后遍历站点,为每个站点生成一个图。我的问题是找不到在for循环中创建的对象。
下面是一个非常简单的示例,但会产生相同的错误:
df1 <- data.frame(date = seq(as.Date("2015-01-01"), as.Date("2015-01-10"),
by = "day"),
site1 = runif(10),
site2 = runif(10),
site3 = runif(10))
example <- function(df1){
sname <- names(df1)[-1]
for (i in 1:length(sname)){
df2 <- df1[,c(1, 1+i)]
df2$label <- factor(rep("ts", by=length(df2[,1])))
plot <- ggplot()+
geom_point(data=df2, aes(x=date, y=df2[,2]))+
geom_line(data=df2, aes(x=date, y=df2[,2]))
sname.i<-sname[i]
filename<-paste0(sname.i, "-test-plot.pdf")
ggsave(file=filename, plot)
}
}
example(df1)
我得到的错误是:“eval中的错误(expr,envir,enclos):找不到对象'df2'”
我不太确定问题是什么,因为我创建了类似的循环,这些循环在过去有效。如果我为i分配一个值并循环遍历循环中的代码,它可以正常工作。我在想环境问题?还是ggsave在做什么呢?感激地收到任何帮助/指针。 感谢。
答案 0 :(得分:4)
你的问题不是你的代码,而是ggplot2包的实现。该软件包使用非标准评估,这会严重影响您的结果。
看一下本文末尾的示例代码。我在全局环境中创建了一个名为df2
的数据框,其值不同。如果我现在运行你的代码,你会得到如下图:
请注意,在X轴上,它使用正确的日期,但Y轴上的值是来自全局环境中的数据框df2
的值!因此函数aes()
在两个不同的位置查找数据。如果将变量的名称指定为符号(date
),则该函数首先查看函数调用中指定的数据框。但是,在数据框中找不到像df2[,2]
这样的表达式,因为没有该名称的变量。由于构造ggplot2
包的方式,R将在全局环境中而不是调用环境中寻找它。
根据 wici 的评论:你最好的选择可能是使用函数aes_string()
,因为这允许你传递字符形式的aes,这个函数在正确的环境中评估表达式:
plot <- ggplot()+
geom_point(data=df2, aes_string(x="date", y=sname[i]))+
geom_line(data=df2, aes_string(x="date", y=sname[i]))
或者,您可以使用eval()
和parse()
来解决这个问题:
example <- function(df1){
sname <- names(df1)[-1]
for (i in 1:length(sname)){
df2 <- df1[,c(1, 1+i)]
df2$label <- factor(rep("ts", by=length(df2[,1])))
aesy <- sname[i]
command <- paste("plot <- ggplot()+
geom_point(data=df2, aes(x=date, y=",aesy,"))+
geom_line(data=df2, aes(x=date, y=",aesy,"))")
eval(parse(text=command))
sname.i<-sname[i]
print(plot)
}
如果你尝试使用下面的示例脚本,你会看到这一次你得到正确的值显示。请注意,这是一个次优解决方案,因为大多数解决方案涉及eval()
。我来这里aes_string()
。
示例脚本
df1 <- data.frame(date = seq(as.Date("2015-01-01"), as.Date("2015-01-10"),
by = "day"),
site1 = runif(10),
site2 = runif(10),
site3 = runif(10))
df2 <- data.frame(date = seq(as.Date("2014-10-01"), as.Date("2014-10-10"),
by = "day"),
site1 = runif(10,10,20),
site2 = runif(10,10,20),
site3 = runif(10,10,20))
example <- function(df1){
sname <- names(df1)[-1]
for (i in 1:length(sname)){
df2 <- df1[,c(1, 1+i)]
df2$label <- factor(rep("ts", by=length(df2[,1])))
plot <- ggplot()+
geom_point(data=df2, aes(x=date, y=df2[,2]))+
geom_line(data=df2, aes(x=date, y=df2[,2]))
sname.i<-sname[i]
print(plot)
}
}
example(df1)