为了账号安全,请及时绑定邮箱和手机立即绑定

从R中的循环内将ggplot对象存储在列表中

从R中的循环内将ggplot对象存储在列表中

蛊毒传说 2019-11-29 14:32:21
我的问题与此相似。当我循环生成图对象(在本例中为直方图)时,似乎所有对象都被最新图覆盖。为了调试,在循环中,我正在打印索引和生成的图,两者均正确显示。但是当我查看存储在列表中的图时,除了标签外,它们都相同。(我正在使用多图制作合成图像,但是如果一次print (myplots[[1]]) 完成print(myplots[[4]])一次,则会得到相同的结果。)因为我已经有一个附加的数据框(与类似问题的发布者不同),所以我不确定如何解决该问题。(顺便说一句,列类是我在此处近似的原始数据集中的因子,但是如果它们是整数,则会发生相同的问题)这是一个可重现的示例:library(ggplot2)source("http://peterhaschke.com/Code/multiplot.R") #load multiplot function#make sample datacol1 <- c(2, 4, 1, 2, 5, 1, 2, 0, 1, 4, 4, 3, 5, 2, 4, 3, 3, 6, 5, 3, 6, 4, 3, 4, 4, 3, 4,           2, 4, 3, 3, 5, 3, 5, 5, 0, 0, 3, 3, 6, 5, 4, 4, 1, 3, 3, 2, 0, 5, 3, 6, 6, 2, 3,           3, 1, 5, 3, 4, 6)col2 <- c(2, 4, 4, 0, 4, 4, 4, 4, 1, 4, 4, 3, 5, 0, 4, 5, 3, 6, 5, 3, 6, 4, 4, 2, 4, 4, 4,           1, 1, 2, 2, 3, 3, 5, 0, 3, 4, 2, 4, 5, 5, 4, 4, 2, 3, 5, 2, 6, 5, 2, 4, 6, 3, 3,           3, 1, 4, 3, 5, 4)col3 <- c(2, 5, 4, 1, 4, 2, 3, 0, 1, 3, 4, 2, 5, 1, 4, 3, 4, 6, 3, 4, 6, 4, 1, 3, 5, 4, 3,           2, 1, 3, 2, 2, 2, 4, 0, 1, 4, 4, 3, 5, 3, 2, 5, 2, 3, 3, 4, 2, 4, 2, 4, 5, 1, 3,           3, 3, 4, 3, 5, 4)col4 <- c(2, 5, 2, 1, 4, 1, 3, 4, 1, 3, 5, 2, 4, 3, 5, 3, 4, 6, 3, 4, 6, 4, 3, 2, 5, 5, 4,          2, 3, 2, 2, 3, 3, 4, 0, 1, 4, 3, 3, 5, 4, 4, 4, 3, 3, 5, 4, 3, 5, 3, 6, 6, 4, 2,           3, 3, 4, 4, 4, 6)data2 <- data.frame(col1,col2,col3,col4)data2[,1:4] <- lapply(data2[,1:4], as.factor)colnames(data2)<- c("A","B","C", "D")#generate plotsmyplots <- list()  # new empty listfor (i in 1:4) {  p1 <- ggplot(data=data.frame(data2),aes(x=data2[ ,i]))+     geom_histogram(fill="lightgreen") +    xlab(colnames(data2)[ i])  print(i)  print(p1)  myplots[[i]] <- p1  # add each plot into plot list}multiplot(plotlist = myplots, cols = 4)当我在图列表中查看图对象的摘要时,这就是我看到的> summary(myplots[[1]])data: A, B, C, D [60x4]mapping:  x = data2[, i]faceting: facet_null() -----------------------------------geom_histogram: fill = lightgreen stat_bin:  position_stack: (width = NULL, height = NULL)我认为这mapping:  x = data2[, i]是问题所在,但我很沮丧!我无法发布图片,因此如果我对问题的解释令人困惑,则需要运行我的示例并查看图表。谢谢!
查看完整描述

3 回答

?
三国纷争

TA贡献1804条经验 获得超7个赞

除了其他出色的答案之外,这里还有一个使用看起来“正常”的评估而不是的解决方案eval。由于for循环没有单独的变量范围(即,它们在当前环境中执行),因此我们需要使用它local来包装for块;此外,我们需要创建i一个局部变量-我们可以通过将其重新分配为其自己的名称1来做到这一点:


myplots <- vector('list', ncol(data2))


for (i in seq_along(data2)) {

    message(i)

    myplots[[i]] <- local({

        i <- i

        p1 <- ggplot(data2, aes(x = data2[[i]])) +

            geom_histogram(fill = "lightgreen") +

            xlab(colnames(data2)[i])

        print(p1)

    })

}

但是,完全干净的方法是for完全放弃循环,并使用列表函数生成结果。这可以通过几种可能的方式工作。我认为以下是最简单的方法:


plot_data_column = function (data, column) {

    ggplot(data, aes_string(x = column)) +

        geom_histogram(fill = "lightgreen") +

        xlab(column)

}


myplots <- lapply(colnames(data2), plot_data_column, data = data2)

这有几个优点:更简单,并且不会使环境混乱(使用loop变量i)。


1这看起来似乎令人困惑:为什么根本i <- i没有效果?—因为执行分配,所以我们创建了一个新的局部变量,其名称与外部作用域中的变量相同。我们同样可以使用其他名称,例如local_i <- i。


查看完整回答
反对 回复 2019-11-29
?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

由于所有传递的表达式都被引用,因此i在循环结束时求值的那是i当时发生的一切,这是它的最终值。您可以通过eval(substitute(在每次迭代中输入正确的值来解决此问题。


myplots <- list()  # new empty list

for (i in 1:4) {

    p1 <- eval(substitute(

        ggplot(data=data.frame(data2),aes(x=data2[ ,i]))+ 

          geom_histogram(fill="lightgreen") +

          xlab(colnames(data2)[ i])

    ,list(i = i)))

    print(i)

    print(p1)

    myplots[[i]] <- p1  # add each plot into plot list

}

multiplot(plotlist = myplots, cols = 4)


查看完整回答
反对 回复 2019-11-29
?
翻阅古今

TA贡献1780条经验 获得超5个赞

拥有很多非常大的地块是一个问题,而这两种解决方案都不是。一种常见的解决方案是对您绘制的数据点数进行二次采样(通常,这样的大图无论如何都无法可靠地显示所有单独的数据点),或者在绘制之前计算汇总统计信息(并绘制这些而不是原始数据)。但有时两者都不起作用。在这种情况下,唯一的解决方案是避免一次在内存中包含多个图。

查看完整回答
反对 回复 2019-11-29
  • 3 回答
  • 0 关注
  • 2552 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信