R将ggplot对象指定给循环中的列表
我正在使用R将ggplot对象指定给循环中的列表,r,loops,ggplot2,cowplot,R,Loops,Ggplot2,Cowplot,我正在使用for循环将ggplot分配给列表,然后将其传递给plot\u grid()(包cowplot)绘图网格将多个GGPlot并排放置在一个图形中。手动操作效果很好,但当我将用于循环时,生成的最后一个绘图将在图形的每个子帧中重复(如下所示)。换句话说,所有子帧显示相同的ggplot 以下是一个玩具示例: require(cowplot) dfrm <- data.frame(A=1:10, B=10:1) v <- c("A","B") dfmsize <- nrow
for循环
将ggplot分配给列表
,然后将其传递给plot\u grid()
(包cowplot
)<代码>绘图网格将多个GGPlot并排放置在一个图形中。手动操作效果很好,但当我将用于循环
时,生成的最后一个绘图将在图形的每个子帧中重复(如下所示)。换句话说,所有子帧显示相同的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)
但我得到了同样的结果
我认为问题在于循环赋值,而不是
plot\u grid()
,但我看不出我做错了什么。我认为ggplot
会因为在dfrm
中查找x
和y
变量而变得混乱,即使您实际上正在动态定义它们。如果您稍微更改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)
myplots对于ggplot2的延迟计算和[this answer]中的for循环,有一个很好的解释(
对于这种情况,我通常切换到aes\u string
或aes\u
,这样我就可以在ggplot2中将变量用作字符串
我发现lappy
循环比for
循环更容易,因为可以避免初始化列表和使用计数器
首先,我将x变量添加到数据集中
dfrm$index = 1:nrow(dfrm)
现在,lappy
循环,循环通过v
中的列
myplots = lapply(v, function(x) {
ggplot(dfrm, aes_string(x = "index", y = x)) +
geom_point() +
labs(y = x)
})
plot_grid(plotlist = myplots)
我认为这里的问题是,对aes
方法的非标准评估会延迟评估I
,直到实际绘制出绘图。绘制时,I
是最后一个值(在玩具示例“B”中)因此,所有绘图的y
美学映射引用最后一个值。同时,labs
调用使用标准评估,因此标签正确引用循环中i
的每个迭代
只需使用映射函数的标准求值版本,aes\u 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)
require(整流罩图)
dfrm到目前为止,答案非常接近,但在我看来并不令人满意。问题是以下问题-在您的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"
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
之所以这样做,是因为环境对于lappy
循环中的每个值都是不同的:
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"
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
详细介绍了ggplot2惰性评估的一些本质。我喜欢你明确提到NSE。在将绘图分配给列表之前,还可以通过在循环中实际打印绘图来验证NSE,这实际上给出了正确的输出(不同于在循环运行后打印)。我将eddi标记为最佳答案,因为通过映射,然后显示循环的每个迭代,plot_env
,可以清楚地看到发生了什么。@jrandall:我没有意识到aes执行非标准评估,正如您所提到的,这就是为什么最好使用aes_q.对其他人提到的
lapply`作为f的替代或循环。@eddi我试图说服ggplot
在for
循环期间,当我最终检查存储在绘图列表中的所有绘图时,遵守绘图生成时的变量值。您对此有何建议?
ls(myplots[[1]]$plot_env)
#[1] "col"