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

时间:2015-08-13 16:29:50

标签: r plot ggplot2

我的问题类似于this one;当我在循环中生成绘图对象(在这种情况下是直方图)时,似乎所有这些都被最近的绘图覆盖。

要在循环中进行调试,我将打印索引和生成的图,两者都正确显示。但是当我查看列表中存储的图表时,它们对于标签来说都是相同的除了

(我使用多重图来制作合成图像,但如果你tcase=6 sum=0 def a(m,n): m=m n=n if m==0: return n+1 elif m>0 and n==0: return a(m-1,1) elif m>0 and n>0: return a(m-1,a(m,n-1)) for i in range(0,(tcase+1)): sum+=a(i,i) print sum ,你会得到相同的结果 通过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) 是问题,但我很难过!我无法发布图片,因此如果我对问题的解释令人困惑,您需要运行我的示例并查看图表。

谢谢!

4 个答案:

答案 0 :(得分:39)

除了其他优秀的答案之外,这里的解决方案使用“正常”评估而不是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循环并使用list函数来构建结果。这有几种可能的方式。以下是我认为最简单的方法:

plot_data_column = function (data, column) {
    ggplot(data2, aes_string(x = column)) +
        geom_histogram(fill = "lightgreen") +
        xlab(column)
}

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

这有很多优点:大多数情况下它更简单,它不会使环境混乱(使用循环变量i)。

1 这可能看起来令人困惑:为什么i <- i会产生任何影响? - 因为通过执行赋值,我们创建了一个新的 local 变量,其名称与外部作用域中的变量相同。我们同样可以使用不同的名称,例如local_i <- i

答案 1 :(得分:6)

由于所有传入的表达式的引用,在循环结束时计算的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)

答案 2 :(得分:0)

使用lapply也是有效的,因为匿名函数环境中存在x(使用mtcars作为数据):

plot <- lapply(seq_len(ncol(mtcars)), FUN = function(x) {
  ggplot(data = mtcars) + 
    geom_line(aes(x = mpg, y = mtcars[ , x]), size = 1.4, color = "midnightblue", inherit.aes = FALSE) +
    labs(x="Date", y="Value", title = "Revisions 1M", subtitle = colnames(mtcars)[x]) +
    theme_wsj() +
    scale_colour_wsj("colors6")
})

答案 3 :(得分:0)

我已运行问题和答案中的代码,将 geom_histogram 更改为 geom_bar 以避免错误:Error: StatBin requires a continuous x variable

这是带有可视化效果的代码:

问题

#generate plots
myplots <- list()  # new empty list
for (i in 1:4) {
  p1 <- ggplot(data=data.frame(data2),aes(x=data2[ ,i]))+ 
    geom_bar(fill="lightgreen") +
    xlab(colnames(data2)[ i])
  print(i)
  print(p1)
  myplots[[i]] <- p1  # add each plot into plot list
}

multiplot(plotlist = myplots, cols = 4)
#> Loading required package: grid

回答

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_bar(fill = "lightgreen") +
            xlab(colnames(data2)[i])
        print(p1)
    })
}

multiplot(plotlist = myplots, cols = 4)

使用 lapply 的结果相同:


plot_data_column = function (data, column) {
    ggplot(data, aes_string(x = column)) +
        geom_bar(fill = "lightgreen") +
        xlab(column)
}

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

multiplot(plotlist = myplots, cols = 4)
#> Loading required package: grid

reprex package (v0.3.0) 于 2021 年 4 月 9 日创建