如何在ggplot2柱状图中仅修改年度平均分组的柱子颜色?
问题描述
我使用ggplot2绘制柱状图,x轴为分类变量,每个分类对应两个定量变量a和b(分属不同列)。前9个分类变量是月份,最后一个为年度平均值。我希望将年度平均值对应的最后两个柱子填充为与其他柱子不同的颜色,但当前代码会将所有柱子设置为相同颜色。我在scale_fill_manual中按图表显示顺序设置了颜色,但最后两个柱子未呈现预期效果。
原始数据与代码
a= c(10,11,12,13,14,15,16,17,18,14) # 最后一个是平均值 b= c(20,19,18,17,16,15,14,13,12,16) # 最后一个是平均值 df <- data.frame(Mon= c("February", "February", "March", "March", "April", "April", "May", "May", "June", "June", "July", "July", "August", "August", "September", "September", "October", "October", "Year Average to 01/11", "Year Average to 01/11"), Metrics=c('a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b'), Values=c(10, 20,11,19,12,18,13,17,14,16,15,15,16,14,17,13,18,12,14,16)) df$Mon <- factor(df$Mon, levels = unique(df$Mon)) # 避免x轴变量按字母顺序重排 ggplot(df)+ geom_bar( aes(x=Mon, y=Values, fill=Metrics, group=Metrics), stat='identity', position='dodge' )+ scale_fill_manual(values=c("#9BD4F5", "#6CC4EE", "#9BD4F5", "#6CC4EE", "#9BD4F5", "#6CC4EE", "#9BD4F5", "#6CC4EE", "#9BD4F5", "#6CC4EE", "#9BD4F5", "#6CC4EE", "#9BD4F5", "#6CC4EE", "#9BD4F5", "#6CC4EE", "#9BD4F5", "#6CC4EE", "#1D8ECE", "#2E77BB") )+ geom_text( aes(x=Mon, y=Values, label=Values, fill=Metrics, group=Metrics), position = position_dodge(width = 1), vjust = 2, size = 3 )+ theme( plot.title = element_text(hjust = 0.5, size = 25), plot.subtitle = element_text(hjust = 0.5, color = "darkgrey", size = 20), axis.title = element_text(size = 20), axis.text = element_text(size = 15), panel.background = element_rect(fill = "white", color = "white"), panel.grid.major.y = element_line(color = "grey"), axis.line = element_line(color = "black") )+ labs( x = "", y = "Values", title = "OSAT and RTF Overview", subtitle = "February to October 2022" )
问题原因
你当前的fill映射的是Metrics变量,它只有a和b两个水平。scale_fill_manual会自动循环使用你提供的颜色值,只取前两个分别对应a和b,后面的颜色值不会生效,所以所有a类柱子都是同色,b类柱子也都是同色。
解决方案
需要创建一个新的分组变量,同时区分Metrics和是否为年度平均值,让fill映射这个新变量,这样就能给年度平均值的柱子单独设置颜色。
修正后的代码
a= c(10,11,12,13,14,15,16,17,18,14) # 最后一个是平均值 b= c(20,19,18,17,16,15,14,13,12,16) # 最后一个是平均值 df <- data.frame(Mon= c("February", "February", "March", "March", "April", "April", "May", "May", "June", "June", "July", "July", "August", "August", "September", "September", "October", "October", "Year Average to 01/11", "Year Average to 01/11"), Metrics=c('a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b'), Values=c(10, 20,11,19,12,18,13,17,14,16,15,15,16,14,17,13,18,12,14,16)) df$Mon <- factor(df$Mon, levels = unique(df$Mon)) # 避免x轴变量按字母顺序重排 # 创建新的填充分组变量:区分普通月份和年度平均值的Metrics df$FillGroup <- ifelse(df$Mon == "Year Average to 01/11", paste(df$Metrics, "Avg"), df$Metrics) ggplot(df)+ geom_bar( aes(x=Mon, y=Values, fill=FillGroup, group=Metrics), stat='identity', position='dodge' )+ # 按新的分组变量设置颜色 scale_fill_manual(values = c( "a" = "#9BD4F5", "b" = "#6CC4EE", "a Avg" = "#1D8ECE", "b Avg" = "#2E77BB" ))+ geom_text( aes(x=Mon, y=Values, label=Values, group=Metrics), position = position_dodge(width = 1), vjust = 2, size = 3, color = "white" # 文字设为白色更清晰 )+ theme( plot.title = element_text(hjust = 0.5, size = 25), plot.subtitle = element_text(hjust = 0.5, color = "darkgrey", size = 20), axis.title = element_text(size = 20), axis.text = element_text(size = 15), panel.background = element_rect(fill = "white", color = "white"), panel.grid.major.y = element_line(color = "grey"), axis.line = element_line(color = "black") )+ labs( x = "", y = "Values", title = "OSAT and RTF Overview", subtitle = "February to October 2022", fill = "Metrics" # 手动修改图例标题 )
说明
- 新增
FillGroup列,将年度平均值的a和b标记为a Avg和b Avg,和普通月份的a、b区分开; fill映射改为FillGroup,这样有四个不同的水平对应四种颜色;scale_fill_manual直接按分组名称指定颜色,清晰且不会出错;- 调整了文本颜色为白色,避免深色柱子上的文字看不清。
内容的提问来源于stack exchange,提问作者SlicerLice
相关产品推荐
相关产品推荐

