在循环中使用scale_fill_manual()时,仅保留上次迭代中指定的颜色值

时间:2017-09-05 09:36:00

标签: r ggplot2

代码说明:我有一个数据框dfs,其中我存储了其他数据框的名称(df1df2)。 df1df2都包含两个发行版的数据。

我想制作两个单独的(双)条形图;一个用于df1df2。每个条形图比较两个分布。要使用的小节的颜色列在dfs中(例如df1我要使用red1red4)。

我尝试通过循环数据框dfs来做到这一点(这只是一个说明性示例,实际上我有比df1df2更多的数据框)并创建每个数据框'df1'和'df2'的条形图对象。

我使用scale_fill_manual(values = barColours)为条形指定颜色。不幸的是,当我最后绘制数字(df1_plotdf2_plot)时,会使用最后一次迭代的颜色(换句话说,df2_plot的颜色也用于{ {1}})。

有没有办法确保df1_plot使用预期的颜色而不会丢失df1_plot循环?

for

2 个答案:

答案 0 :(得分:2)

在R中这样做的更惯用的方法是使用列表:

  • 创建输入数据框列表
  • 使用lapply()创建包含图表的新列表:

请注意,这根本不会使用assign() - 一般情况下,如果您想要使用assign(),则表明几乎可以肯定有一种更简单的方法这样做。

试试这个:

input_data = list(df1, df2)

df_plot <- lapply(1:2, function(i){

  dat <- input_data[[i]]
  barColours = c(dfs[i, "col1"], dfs[i, "col2"])

  ggplot(dat, aes(x = category, y = weight, fill = category_type)) + 
    geom_bar(stat = "identity", position = "dodge") + 
    scale_fill_manual(values = barColours)

})

df_plot[[1]]
df_plot[[2]]

答案 1 :(得分:1)

这是因为ggplot个对象仅在打印或构建时进行评估,而不是在构造时进行评估。由于在打印图表时i已更改,因此它将使用新值。解决这个问题的一种方法是明确地构建图:

plots <- list()

for (i in 1:2) {
  df = eval(as.name(dfs[i, "df"]))
  barColours = c(dfs[i, "col1"], dfs[i, "col2"])

  distribution = ggplot(df, aes(x = category, y = weight, fill = category_type)) + 
    geom_bar(stat = "identity", position = "dodge") + 
    scale_fill_manual(values = barColours)

  plots[[i]] = ggplot_build(distribution)
}
plots[[1]]$plot

请注意,我已删除了您对assign的使用,因为我更愿意将内容存储在列表中。

我首选的方法是不使用循环,而是使用带有列表的函数:

f <- function(df, barColours) {
  ggplot(df, aes(x = category, y = weight, fill = category_type)) + 
    geom_bar(stat = "identity", position = "dodge") + 
    scale_fill_manual(values = barColours)
}

plots <- Map(f, list(df1, df2), list(c('red1', 'red4'), c('green1', 'green4')))
plots[[1]]