r语言 - 在循环中使用 scale_fill_manual() 时,仅保留上次迭代中分配的颜色值



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

我想制作两个单独的(双)条形图;一个用于df1df2。每个条形图比较两个分布。要使用的条形的颜色以dfs列出(例如,对于我想使用red1red4df1)。

我尝试通过循环遍历数据框dfs(这只是一个说明性示例,实际上我拥有的数据框比df1df2多得多)并为每个数据框"df1"和"df2"创建一个条形图对象。

我使用scale_fill_manual(values = barColours)为条形分配颜色。不幸的是,当我最后绘制图形时(df1_plotdf2_plot),使用了上次迭代的颜色(换句话说,df2_plot的颜色也用于df1_plot)。

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

library(ggplot2)
col1          = c("red1", "green1")
col2          = c("red4", "green4")
dfs           = data.frame(df = c("df1", "df2"), col1, col2 , stringsAsFactors = FALSE)
category_type1 = rep(c("A", "B"), each = 3)
category1      = rep(c(1, 2, 3), 2)
weight1        = c(5, 8, 9, 6, 4, 7)
df1            = data.frame(category_type = category_type1, category =     category1, weight = weight1, stringsAsFactors = FALSE)
category_type2 = rep(c("A", "B"), each = 3)
category2      = rep(c(1, 2, 3), 2)
weight2        = c(10, 2, 1, 1, 5 , 7)
df2            = data.frame(category_type = category_type2, category = category2, weight = weight2, stringsAsFactors = FALSE)
for (i in 1:2) {
assign("data", eval(as.name(dfs[i, "df"])))
barColours = c(dfs[i, "col1"], dfs[i, "col2"])
distribution = ggplot(data, aes(x = category, y = weight, fill = category_type)) + 
geom_bar(stat = "identity", position = "dodge") + 
scale_fill_manual(values = barColours)
assign(paste0(dfs[i, "df"], "_plot"), distribution)
}
df1_plot
df2_plot

在 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]]

这是因为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]]