如何在循环中使用时绘制scale_manual而不绘制绘图?

时间:2016-04-28 19:37:59

标签: r ggplot2

我试图为数据框列表生成一个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,那真的很奇怪......它在调试模式下工作,当我手动执行循环的每一行时。花了很长时间才注意到这是因为我绘制了这些图在每个循环中...)

1 个答案:

答案 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