如何在ggplot中手动设置geom_bar的填充颜色

23

我正在尝试使用ggplot创建多个图形。这些图形是一系列的条形图,一起描述了一条线,如EXAMPLE所示(顺便说一下,是的,我知道颜色调色板很丑,但对我的受众来说,颜色盲友好很重要)。

我的问题是,我需要创建几个这样的图形,并希望所有图形的颜色保持一致。由于“类型”变量在我将要使用的几个数据集中以不同的顺序出现,因此我需要为每种类型手动设置一种颜色。我认为这个问题:How to manually fill colors in a ggplot2 histogram应该有答案,但是当我尝试时,它会将图例中的名称更改为颜色的十六进制定义,但颜色本身会回到ggplot的默认调色板。

这是我目前的代码:

  cbbPalette <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")

 ggplot()+
    scale_fill_manual(values=cbbPalette)+
    geom_bar(data=subset(eten, Type=="Waste Wood"), aes(x=Tprod, y=acost, fill=cbbPalette[1], width=MGGEY+25), stat="identity")+
    geom_bar(data=subset(eten, Type=="Agricultural Residue"), aes(x=Tprod, y=acost, fill=cbbPalette[2], width=MGGEY+25), stat="identity")+
    geom_bar(data=subset(eten, Type=="Forest Residue"), aes(x=Tprod, y=acost, fill=cbbPalette[3], width=MGGEY+25), stat="identity")+
    geom_bar(data=subset(eten, Type=="Herbaceous Energy Crop"), aes(x=Tprod, y=acost, fill=cbbPalette[4], width=MGGEY+25), stat="identity")+
    geom_bar(data=subset(eten, Type=="MSW"), aes(x=Tprod, y=acost, fill=cbbPalette[5], width=MGGEY+25), stat="identity")+
    scale_y_continuous("Average Cost", labels = dollar, expand=c(0,0))+
    scale_x_continuous("Million Gallons of Gasoline Equivalent", expand=c(0,0))+
    theme(legend.position="bottom", panel.background=element_rect(colour = NA, fill = "white"), axis.line=element_line(), panel.grid.major.y=element_line(colour="black"), panel.grid.minor=element_blank())

我的R语言水平相当低,所以我可能会错过一些简单的东西,但是我自己无法让它运作。提前感谢您的帮助。

更新:我无意中粘贴了一个错误版本的代码,“fill”命令已经恢复到最好的猜测了。一个示例数据集在这里


请问您能提供数据集eten吗,或者至少提供一个可复现的示例 https://dev59.com/eG025IYBdhLWcg3whGSx?此外,您不必为每种类型进行子集筛选。 - Jonas Tundo
2个回答

24

我猜你已经看过这里展示的ggplot色盲示例了?由于没有你的数据,我只能猜测你的geom_bar调用会产生歧义,因为你最初对ggplot的调用没有一个aes参数。尝试将所有数据移入单个数据框中,并在对ggplot的最初调用中引用它,例如,

ggplot(df, aes(x=cond, y=yval)) +
    geom_bar() + 
    scale_fill_manual(values=cbbPalette)

其中df是包含数据的数据框架,aes是变量之间的映射关系。这使得ggplot清楚地知道您希望geom_bar的填充颜色对应于df中的数据。有一些方法可以让您的当前代码工作,但对于创建标准条形图来说它们是不寻常的。


那个答案可以用来创建我在链接图片中展示的示例图,但它对于真正的问题没有帮助。我有5-6个类似的数据集需要为其生成这些图表,并且我想确保每种类型的颜色在每个图表中保持相同。因此,我想手动为“废木材”分配一种颜色,例如另一种颜色为“MSW”,以便每次我再现图表时,颜色都是相同的。您提供的示例似乎让ggplot每次运行脚本时选择要与每种类型关联的颜色。 - scianalysis
1
啊,我明白了。你在处理因子的时候遇到了问题?R 有一个让人烦恼的习惯,会以一种貌似随意的方式重新排序变量。你可以强制 ggplot 按照你想要的任何方式对变量进行排序。请参见这里。使用这些技巧,一旦你按照相同的顺序放置每个标签,每个图表都将具有相同的颜色填充顺序。 - Jay B. Martin
1
那也不行。它确实重新排列了数据框中的因子,因为Type和填充颜色之间的关系发生了变化,但并不是每个类型在我正在处理的每个数据集中都有代表。我真正需要的是一种方法来表达:如果Type="Y",则fill=cbbPalette[x]。 - scianalysis
将您的数据集放入一个聚合数据框中,然后添加一个类型列(以便稍后按类型分组和绘图)。由于您的变量将位于相同的列中,因此 ggplot 将在不同类型之间映射您的因子到相同的颜色(即使某些类型中缺少因子)。最后,使用 facet 创建单独的类型图,例如 ggplot(df, aes(x=cond, y=yval)) + geom_bar() + scale_fill_manual(values=cbbPalette) + facet_grid(. ~ type) - Jay B. Martin

12

Jay B. Martin的回答并没有完全回答这个问题。因此,尽管这个问题很旧,但这里提供了一个解决方案供日后参考。我们制作一些数据以进行可重复的示例:

color_table <- tibble(
  Land_cover = c("Agriculture", "Forest", "Ocean", "Lake", "Populated"),
  Color = c("yellow", "darkgreen", "blue4", "lightblue", "maroon3")
  )

df <- data.frame(
  Region = c(rep(1,5), rep(2,5)),
  Area_no = c(1,2,3,4,5,1,2,3,4,5),
  Land_cover = c("Agriculture", "Forest", "Agriculture", "Agriculture", "Lake", 
                 "Lake", "Populated", "Populated", "Ocean", "Populated"), 
  Square_km = c(10,15,7,12,3, 5,30,20,40,10)
  )

因此,我们想要使用 df 来为每个 Region 制作一个图形,其中 Land_covercolor_table 给出的正确颜色表示。首先,我们必须确保数据集 df 中的 Land_cover 变量是一个类别变量,并且其顺序与我们想要放在每种土地覆盖类型上的颜色相同。我们通过使用来自 color_table 的顺序来实现这一点:

df$Land_cover <- factor(df$Land_cover, levels = color_table$Land_cover)

现在,使用正确颜色最简单的方法是按照Jay B. Martin在评论中建议的那样使用 facet_grid() 或 facet_wrap() 来绘制图形:

ggplot(df, aes(x = Area_no, y = Square_km, fill = Land_cover)) +
  geom_col() +
  scale_fill_manual(values = color_table$Color) +
  facet_grid(.~Region) 

ggplot使用facet 但是如果您想为每个地区制作单独的图形呢?例如,您希望将每个图形保存为单独的文件。

问题

如果我们基本上制作一个小循环,在其中选择数据子集并重用我们以上使用的代码(除了facet_grid),我们会明显得到错误的颜色(在此处显示为区域2):

for (region in 1:2){
  gg <- ggplot(subset(df, Region %in% region), aes(x = Area_no, y = Square_km, fill = 
  Land_cover)) +
    geom_col() + 
    scale_fill_manual(values = color_table$Color) 
  ggsave(paste0("Areas_region_", region, ".png"), width = 5, height = 3)
  }

颜色错误的图表

有两种方法可以获得正确的颜色:

解决方法1:drop = FALSE(图例显示所有类别)

scale_fill_manual 中添加 drop = FALSE 是最简单的方法。然后您将获得正确的颜色,并且图例将显示所有可能的类别,而不仅仅是图表中的类别:

for (region in 1:2){
  gg <- ggplot(subset(df, Region %in% region), aes(x = Area_no, y = Square_km, fill = 
  Land_cover)) +
    geom_col() + 
    scale_fill_manual(values = color_table$Color, drop = FALSE) 
  ggsave(paste0("Areas_region_", region, ".png"), width = 5, height = 3)
  }

图表,颜色和图例正确显示了所有类别

解决方案2. 为每个图表选择颜色(图例仅显示图表中出现的类别)

如果由于某些原因您不想在图例中显示所有可能的类别(例如,如果它们数量巨大),则需要为每个图表选取正确的颜色:

library(magrittr)
for (region in 1:2){
  df_plot <- subset(df, Region %in% region)
  actual_cover <- df_plot$Land_cover %>% as.numeric() %>% table() %>% names() %>% as.numeric()
  gg <- ggplot(df_plot, aes(x = Area_no, y = Square_km, fill = Land_cover)) +
    geom_col() + 
    scale_fill_manual(values = color_table$Color[actual_cover])
  ggsave(paste0("Areas_region_", region, "ver3.png"), width = 5, height = 3)
  }

这将产生以下图表(针对区域2): Plot with correct colours and legend for all categories

我们在这里实际上是创建了一个向量 actual_cover ,该向量包含当前绘图中实际使用的颜色(编号1-6)。因此,图例仅包含绘图中存在的类别,而颜色仍然正确。


现在尝试使用geom_bar。 - Markus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接