ggplot镜像geom_bar自定义颜色匹配异常问题求助
解决思路与修正代码
问题根源在于直接给geom_bar()的fill参数传入拼接向量时,ggplot会严格按数据行的顺序分配颜色,而非按name分组匹配。正确的做法是将颜色信息整合到数据框中,通过映射关系实现颜色与分组的对应,具体步骤如下:
在数据预处理阶段添加颜色列
不再单独创建两个颜色向量,而是在数据处理管道中,根据name和最大值的位置,为每一行数据分配对应的颜色:- 对于
mean_tmax,默认橙色,最大值设为蓝色 - 对于
mean_rain,默认灰色,最大值设为蓝色
- 对于
在ggplot的
aes中映射fill到新的颜色列
这样ggplot会自动根据每行数据的颜色值匹配填充色,同时如果需要保留图例,可以通过scale_fill_identity()配合guide_legend()来手动设置图例标签。
修正后的代码:
library(tidyverse) # 预处理数据并添加颜色列 df_processed <- df.long %>% filter(place == "sheffield", name %in% c("mean_rain", "mean_tmax")) %>% group_by(name) %>% mutate( # 转换降雨量为负值 value = case_when( name == "mean_rain" ~ value/10 * -1, TRUE ~ value ), # 添加颜色列 bar_color = case_when( name == "mean_tmax" & value == max(value) ~ "blue", name == "mean_tmax" ~ "orange", name == "mean_rain" & abs(value) == max(abs(value)) ~ "blue", # 取绝对值判断最大值 name == "mean_rain" ~ "grey" ), # 重命名name和place name = recode(name, "mean_rain" = "rainfall", "mean_tmax" = "max temp"), place = str_to_sentence(place) ) %>% ungroup() # 绘制镜像柱状图 ggplot(df_processed, aes(x = yyyy, y = value, fill = bar_color)) + geom_bar(stat = "identity", position = "identity") + labs( x = "Year", y = expression("Rain in cm, temperature in ("*~degree *C*")") ) + geom_smooth(colour = "black", lwd = 0.5, se = F) + scale_y_continuous(breaks = seq(-30, 30, 5)) + scale_x_continuous(breaks = seq(1990, 2025, 5)) + # 手动设置图例:对应颜色和标签 scale_fill_identity( guide = "legend", labels = c("Max temperature", "Rainfall", "Max value"), breaks = c("orange", "grey", "blue") ) + guides(fill = guide_legend(title = NULL, reverse = T))
关键说明
- 数据处理时通过
case_when()直接为每行分配颜色,确保每个年份的对应分组(气温/降雨)颜色正确匹配 - 使用
scale_fill_identity()让ggplot直接使用数据中的颜色值,同时通过guide参数保留图例并自定义标签 - 对于降雨量的最大值判断,因为已经转换为负值,所以用
abs(value)来获取原始数值的最大值
内容的提问来源于stack exchange,提问作者NoaMi
相关产品推荐
相关产品推荐

