r - ggplot找不到在函数内部创建的对象

标签 r function for-loop ggplot2

我有许多站点的时间序列数据 csv,我为其生成 ggplots,显示使用 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 正在做一些摇摆不定的事情?感谢收到任何帮助/指示。
谢谢。

最佳答案

您的问题不在于您的代码,而在于 ggplot2 包的实现。这个包使用非标准评估,这可能会严重破坏你的结果。

看看这篇文章末尾的示例代码。我在全局环境中创建了一个名为 df2 的数据框具有不同的值(value)。如果我现在运行您的代码,您会得到如下所示的图:

enter image description here

请注意,在 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)

关于r - ggplot找不到在函数内部创建的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30391347/

相关文章:

R 如何在不知道长度的情况下创建 for 循环?

r - 使用 formatC 将 0 添加到 arg 中的序列中,在 R 中返回错误

r - 准引用和 ifelse : Unquoting not resolving as expected

R - 比较 R 中 2 个数据帧之间的数据

r - 列表中多个数据框的摘要统计

javascript - 在javascript中,: (function() {"use strict"}) (); and "use strict"?有什么区别

r - 如何在R中的点阵图形中设置 strip 标签字体大小

c - remove() - 调用的对象 'remove' 不是函数

r - 在 R 中使用 set.seed() 和 foreach()

PHP - 向我解释这个 while/for 循环