【问题标题】:List of plots using lapply使用 lapply 的地块列表
【发布时间】:2014-04-10 17:00:41
【问题描述】:

我最近一直使用 lapply 和 sapply 作为我的首选功能。到目前为止一切都很好,但是为什么下面的代码不起作用让我感到困惑。

df<-as.data.frame(matrix(rnorm(50),ncol=5))
names(df)<-c("x1","x2","x3","x4","x5")
df1<-seq_len(10)

ll<-lapply(seq(1,5), function(i) qplot(df1,df[,i]))

我得到错误:

Error in `[.data.frame`(df, , i) : undefined columns selected

好的,显然我在可重现的代码中犯了一个非常不幸的错误。它现在可以工作,但ll 列表中的所有图都是同一个图。当我运行这个时:

do.call(grid.arrange,ll)

我得到以下图像:

所有的情节都是一样的!这也是我通过数据运行时得到的输出。

【问题讨论】:

  • 它会给你什么错误?
  • 将其添加到答案中。
  • 鉴于您发布的示例图,我不会使用grid.arrange,而是改用分面(facet_wrap 或facet_grid)。请参阅我的答案以获取示例。在我看来,分面更容易和灵活。
  • 是的,我知道刻面,但在这里没有想到。谢谢你的建议。但我仍然想知道为什么这段代码给了我 5 个相同的图。
  • 见@BrodieG 的回答,与惰性评估有关。

标签: r ggplot2 lapply


【解决方案1】:

懒惰的评估存在问题,或者类似的东西。您需要执行以下操作:

ll<-lapply(
  seq(1,5), 
  function(i) qplot(data=data.frame(y=df[, i]), df1, y)
)

这将强制更新每个绘图的 y 值。

更多讨论在此其他SO Post。

【讨论】:

  • +1!或者完全跳过循环,并使用刻面。这就是 ggplot2 的设计方式。
  • @PaulHiemstra,我同意,尽管在某些情况下 ggplot 图列表实际上是有用的,但您可能是对的,在这种情况下,多面方法是更好的结果。跨度>
【解决方案2】:

您遇到的问题与惰性评估有关。这意味着ll 中的函数只有在您调用它们时才真正被评估,即在grid.arrange 中。那时,每个函数都会尝试定位i,到那时,5 的值将是i 在lapply 循环结束时的最后一个值。因此,从df 提取的数据始终是第五列,因此您的图都是相等的。

为防止这种情况,您需要在创建函数时强制执行数据提取,例如使用@BrodieG 的方法。在那里,创建了一个新的data.frame,强制提取来自df 的数据。或者,您可以使用force 强制评估i。

有关惰性求值的更多示例和解释,另请参阅:


为了在同一个 data.frame 中创建多列图,我会使用 facet_wrap。要使用facet_wrap,您需要使用reshape2 包中的melt 重新排序数据:

library(ggplot2)
library(reshape2)
df$xvalues = 1:10
df_melt = melt(df, id.vars = 'xvalues')
ggplot(df_melt, aes(x = xvalues, y = value)) + 
    geom_point() + facet_wrap(~ variable)

【讨论】:

  • 这确实是一个更好的解决方案,因为它允许我使用更优雅的ggplot + ggsave 组合而不是qplot + grid.arrange 混乱。感谢您的帮助。
  • 我很少使用循环,几乎总是可以使用分面来获得相同的结果。
【解决方案3】:

您告诉它执行 10 列,而您只有 5 列。这有效:

ll<-lapply(seq(1,5), function(i) qplot(df1,df[,i]))

【讨论】:

  • 谢谢。我已经编辑了我的初始帖子,因为我现在看到了与我的数据集中相同的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-05
  • 2013-02-16
  • 1970-01-01
  • 2021-07-02
  • 2019-11-17
相关资源
最近更新 更多