猿问

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

我的问题与此相似。当我循环生成图对象(在本例中为直方图)时,似乎所有对象都被最新图覆盖。


为了调试,在循环中,我正在打印索引和生成的图,两者均正确显示。但是当我查看存储在列表中的图时,除了标签外,它们都相同。


(我正在使用多图制作合成图像,但是如果一次print (myplots[[1]]) 完成print(myplots[[4]])一次,则会得到相同的结果。)


因为我已经有一个附加的数据框(与类似问题的发布者不同),所以我不确定如何解决该问题。


(顺便说一句,列类是我在此处近似的原始数据集中的因子,但是如果它们是整数,则会发生相同的问题)


这是一个可重现的示例:


library(ggplot2)

source("http://peterhaschke.com/Code/multiplot.R") #load multiplot function


#make sample data

col1 <- 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 plots

myplots <- list()  # new empty list

for (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]是问题所在,但我很沮丧!我无法发布图片,因此如果我对问题的解释令人困惑,则需要运行我的示例并查看图表。


谢谢!


蛊毒传说
浏览 2879回答 3
3回答

三国纷争

除了其他出色的答案之外,这里还有一个使用看起来“正常”的评估而不是的解决方案eval。由于for循环没有单独的变量范围(即,它们在当前环境中执行),因此我们需要使用它local来包装for块;此外,我们需要创建i一个局部变量-我们可以通过将其重新分配为其自己的名称1来做到这一点:myplots <- vector('list', ncol(data2))for (i in seq_along(data2)) {&nbsp; &nbsp; message(i)&nbsp; &nbsp; myplots[[i]] <- local({&nbsp; &nbsp; &nbsp; &nbsp; i <- i&nbsp; &nbsp; &nbsp; &nbsp; p1 <- ggplot(data2, aes(x = data2[[i]])) +&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; geom_histogram(fill = "lightgreen") +&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; xlab(colnames(data2)[i])&nbsp; &nbsp; &nbsp; &nbsp; print(p1)&nbsp; &nbsp; })}但是,完全干净的方法是for完全放弃循环,并使用列表函数生成结果。这可以通过几种可能的方式工作。我认为以下是最简单的方法:plot_data_column = function (data, column) {&nbsp; &nbsp; ggplot(data, aes_string(x = column)) +&nbsp; &nbsp; &nbsp; &nbsp; geom_histogram(fill = "lightgreen") +&nbsp; &nbsp; &nbsp; &nbsp; xlab(column)}myplots <- lapply(colnames(data2), plot_data_column, data = data2)这有几个优点:更简单,并且不会使环境混乱(使用loop变量i)。1这看起来似乎令人困惑:为什么根本i <- i没有效果?—因为执行分配,所以我们创建了一个新的局部变量,其名称与外部作用域中的变量相同。我们同样可以使用其他名称,例如local_i <- i。

小怪兽爱吃肉

由于所有传递的表达式都被引用,因此i在循环结束时求值的那是i当时发生的一切,这是它的最终值。您可以通过eval(substitute(在每次迭代中输入正确的值来解决此问题。myplots <- list()&nbsp; # new empty listfor (i in 1:4) {&nbsp; &nbsp; p1 <- eval(substitute(&nbsp; &nbsp; &nbsp; &nbsp; ggplot(data=data.frame(data2),aes(x=data2[ ,i]))+&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; geom_histogram(fill="lightgreen") +&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; xlab(colnames(data2)[ i])&nbsp; &nbsp; ,list(i = i)))&nbsp; &nbsp; print(i)&nbsp; &nbsp; print(p1)&nbsp; &nbsp; myplots[[i]] <- p1&nbsp; # add each plot into plot list}multiplot(plotlist = myplots, cols = 4)

翻阅古今

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