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

4xrmg8kj  于 2023-05-11  发布在  其他
关注(0)|答案(5)|浏览(105)

我的问题类似于this one;当我在一个循环中生成绘图对象(在这种情况下是直方图)时,似乎所有对象都被最近的绘图覆盖了。
为了调试,在循环中,我打印索引和生成的图,两者都正确显示。但是当我查看存储在列表中的图时,它们都是相同的**,除了标签**。
(我使用multiplot来制作一个合成图像,但是如果你一次从print (myplots[[1]])print(myplots[[4]])得到一个相同的结果。
因为我已经有一个附加的dataframe(不像类似问题的海报),所以我不确定如何解决这个问题。
(btw,列类是我在这里近似的原始数据集中的因素,但如果它们是整数,也会发生同样的问题)
下面是一个可重复的示例:

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]是问题所在,但我被难住了!我不能发布图像,所以如果我对问题的解释令人困惑,您需要运行我的示例并查看图表。
谢谢!

9jyewag0

9jyewag01#

我已经运行了问题和答案中的代码,将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

创建于2021-04-09由reprex package(v0.3.0)

relj7zay

relj7zay2#

使用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")
})
jaxagkaj

jaxagkaj3#

下面是另一个解决方案:

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

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

nbnkbykc4#

除了其他优秀的答案之外,这里还有一个解决方案,它使用了“正常”的评估而不是eval。由于for循环没有单独的变量作用域(即它们在当前环境中执行),我们需要使用local来 Package for块;此外,我们需要将i设为一个局部变量-我们可以通过将其重新赋值给自己的name 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)

这有几个优点:它更简单,而且不会使环境混乱(使用循环变量i)。
1这可能看起来令人困惑:为什么i <- i有任何影响呢?- 因为通过执行赋值,我们创建了一个新的 local 变量,其名称与外部作用域中的变量相同。我们同样可以使用不同的名称,例如。local_i <- i

pwuypxnk

pwuypxnk5#

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

相关问题