我试图为数据框列表生成一个ggplots列表,其中每个图应使用不同的颜色palett,我试图用scale_fill_manual实现。但是,最后一种颜色适用于所有绘图。我最终发现,只有在我将每个情节绘制到列表中之前它才有效...
这是一个最小的例子:
# no extra plotting
df <- split(mtcars, mtcars$gear)
colours <- c("red", "green", "blue")
plots <- list()
for(i in 1:length(df)){
.plot <- ggplot(df[[i]], aes(x=as.factor(carb), fill=as.factor(gear))) + geom_bar() +
scale_fill_manual(values=colours[[i]])
plots[[length(plots)+1]] <- .plot
}
plot1 <- arrangeGrob(grobs=plots)
在输出中,所有条都是蓝色。
#second version:
plots2 <- list()
for(i in 1:length(df)){
.plot2 <- ggplot(df[[i]], aes(x=as.factor(carb), fill=as.factor(gear))) + geom_bar() +
scale_fill_manual(values=colours[[i]])
#the magic trick
grid.draw(.plot2)
plots2[[length(plots2)+1]] <- .plot2
}
plot2 <- arrangeGrob(grobs=plots2)
现在它正常运作。有没有其他方法可以使它工作?在我的情况下,绘制每个子图需要很长时间。
(如果这是一个bug,那真的很奇怪......它在调试模式下工作,当我手动执行循环的每一行时。花了很长时间才注意到这是因为我绘制了这些图在每个循环中...)
答案 0 :(得分:3)
更好的选择是
df <- split(mtcars, mtcars$gear)
colours <- c("red", "green", "blue")
plots <- lapply(1:length(df), function(i) {
.plot <- ggplot(df[[i]], aes(x=as.factor(carb), fill=as.factor(gear))) +
geom_bar() +
scale_fill_manual(values=colours[[i]])
.plot
})
此处我们将for
循环替换为lapply
。这避免了参数的惰性评估问题以及i
的值不会像sapply/lapply
那样在for循环中捕获的事实。基本上问题在于,当您绘制它们时,所有绘图都与i
的值相关联,而不是创建它们时i
的值。这种方法基本上创建了闭包,因此每个图都有自己的值i
。