我正在使用for loop
将ggplots分配给list
,然后将其传递给plot_grid()
(包cowplot
)。 plot_grid
将多个ggpl并排放置在一个图中。这可以手动工作,但是当我使用for loop
时,生成的最后一个图在图的每个子帧中重复(如下所示)。换句话说,所有子帧都显示相同的ggplot。
这是一个玩具示例:
require(cowplot)
dfrm <- data.frame(A=1:10, B=10:1)
v <- c("A","B")
dfmsize <- nrow(dfrm)
myplots <- vector("list",2)
count = 1
for(i in v){
myplots[[count]] <- ggplot(dfrm, aes(x=1:dfmsize, y=dfrm[,i])) + geom_point() + labs(y=i)
count = count +1
}
plot_grid(plotlist=myplots)
预期图:
来自for loop
的图:
我尝试将列表元素转换为grobs,如此question中所述,如下所示:
mygrobs <- lapply(myplots, ggplotGrob)
plot_grid(plotlist=mygrobs)
但我得到了同样的结果。
我认为问题在于循环分配,而不是plot_grid()
,但我看不出我做错了什么。
答案 0 :(得分:3)
我认为这里的问题是aes
方法的非标准评估会延迟评估i
,直到实际绘制图。到绘图时,i
是最后一个值(在玩具示例中为“B”),因此所有绘图的y
美学映射都是指最后一个值。同时,labs
调用使用标准评估,因此标签正确引用循环中i
的每次迭代。
只需使用映射函数的标准评估版aes_q
:
require(cowplot)
dfrm <- data.frame(A=1:10, B=10:1)
v <- c("A","B")
dfmsize <- nrow(dfrm)
myplots <- vector("list",2)
count = 1
for(i in v){
myplots[[count]] <- ggplot(dfrm, aes_q(x=1:dfmsize, y=dfrm[,i])) + geom_point() + labs(y=i)
count = count +1
}
plot_grid(plotlist=myplots)
答案 1 :(得分:2)
我认为ggplot
在x
内查找y
和dfrm
变量时会感到困惑,即使您实际上是在动态定义它们。如果您稍微更改for
循环以构建新的子data.frame
作为第一行,则它可以正常工作。
myplots <- list()
count = 1
for(i in v){
df <- data.frame(x = 1:dfmsize, y = dfrm[,i])
myplots[[count]] <- ggplot(df, aes(x=x, y=y)) + geom_point() + labs(y=i)
count = count + 1
}
plot_grid(plotlist=myplots)
答案 2 :(得分:2)
ggplot2的懒惰评估和[本答案]中的循环(https://stackoverflow.com/a/26246791/2461552)有一个很好的解释。
我经常切换到aes_string
或aes_
这样的情况,所以我可以在ggplot2中使用变量作为字符串。
我发现lapply
循环比for
循环容易,因为初始化列表并使用计数器可以避免。
首先,我将x变量添加到数据集中。
dfrm$index = 1:nrow(dfrm)
现在,lapply
循环遍历v
中的列。
myplots = lapply(v, function(x) {
ggplot(dfrm, aes_string(x = "index", y = x)) +
geom_point() +
labs(y = x)
})
plot_grid(plotlist = myplots)
答案 3 :(得分:2)
到目前为止,答案非常接近,但在我看来并不令人满意。问题如下 - 在for
循环之后:
myplots[[1]]$mapping
#* x -> 1:dfmsize
#* y -> dfrm[, i]
myplots[[1]]$plot_env
#<environment: R_GlobalEnv>
myplots[[2]]$mapping
#* x -> 1:dfmsize
#* y -> dfrm[, i]
myplots[[2]]$plot_env
#<environment: R_GlobalEnv>
i
#[1] "B"
正如其他答案所提到的那样,ggplot
实际上在绘制之前并不会对这些表达式进行评估,因为这些表达式都在全局环境中,并且i
的值为"B"
,你会得到不良后果。
有几种方法可以避免这个问题,其中最简单的方法实际上简化了表达式:
myplots = lapply(v, function(col)
ggplot(dfrm, aes(x=1:dfmsize, y=dfrm[,col])) + geom_point() + labs(y=col))
这样做的原因是因为lapply
循环中每个值的环境不同:
myplots[[1]]$mapping
#* x -> 1:dfmsize
#* y -> dfrm[, col]
myplots[[1]]$plot_env
#<environment: 0x000000000bc27b58>
myplots[[2]]$mapping
#* x -> 1:dfmsize
#* y -> dfrm[, col]
myplots[[2]]$plot_env
#<environment: 0x000000000af2ef40>
eval(quote(dfrm[, col]), env = myplots[[1]]$plot_env)
#[1] 1 2 3 4 5 6 7 8 9 10
eval(quote(dfrm[, col]), env = myplots[[2]]$plot_env)
#[1] 10 9 8 7 6 5 4 3 2 1
所以即使表达式相同,结果也不同。
如果你想知道究竟是什么存储/复制到lapply
的环境 - 毫不奇怪它只是列名:
ls(myplots[[1]]$plot_env)
#[1] "col"