如何固定ggplot2图例各数值区间颜色?实现多数据集图例一致性
问题:固定产量分布图的颜色区间与图例一致性
我需要用Data1和Data2两组数据集,在同一区域绘制median_mafruit的产量分布图,要求固定图例中不同数值区间的对应颜色,但当前代码生成的结果不符合预期:即使数据未达到3.5,图例中仍出现蓝色,且颜色与区间的对应关系和设定不符。
现有代码
library(ggplot2) library(dplyr) library(readr) color_breaks <- c(0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0) colors <- c("#E31A1C", "#FF7F00","#FDBF6F","#E9E4A6", "#A4D4A9", "#B2DF8A", "#33A02C", "#1F78B4") p1<-ggplot(merged_data, aes(x = longitude, y = latitude, z = median_mafruit)) + stat_summary_2d(bins = 30) + scale_fill_gradientn( colors = colors, values = scales::rescale(color_breaks), breaks = color_breaks, labels = scales::number_format(accuracy = 0.1) ) + labs( title = "Data2", x = "Longitude", y = "Latitude", fill = expression("Amount") ) + theme_minimal() + theme( plot.title = element_text(size = 16, face = "bold"), plot.subtitle = element_text(size = 14, face = "italic"), legend.title = element_text(size = 12), legend.text = element_text(size = 10) ) p1
数据示例(Data2部分数据)
merged_data <- structure(list(Order = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20), latitude = c(43.2143, 43.3697, 43.3909, 43.3926, 43.3961, 43.3978, 43.066, 43.2215, 43.368, 43.435, 43.4434, 43.4623, 43.4895, 43.4856, 43.3738, 43.4761, 43.5102, 43.5118, 43.5062, 43.4933), longitude = c(-4.479, -4.4804, -4.4606, -4.4484, -4.4241, -4.412, -4.1046, -4.1049, -4.1031, -4.0818, -4.021, -3.9502, -3.8184, -3.7798, -3.7279, -3.7147, -3.5971, -3.5849, -3.5585, -3.5177), median_mafruit = c(2.73, 1.095, 1.115, 2.73, 0.527, 0.527, 0.962, 1.039, 1.039, 2.73, 2.73, 2.73, 2.73, 2.73, 0.544, 2.73, 2.73, 2.73, 0.478, 2.73)), row.names = c(NA, -20L), spec = structure(list(cols = list(Order = structure(list(), class = c("collector_double", "collector")), latitude = structure(list(), class = c("collector_double", "collector")), longitude = structure(list(), class = c("collector_double", "collector")), median_mafruit = structure(list(), class = c("collector_double", "collector"))), default = structure(list(), class = c("collector_guess", "collector")), delim = ","), class = "col_spec"), problems = <pointer: 0x0000024c6289c0f0>, class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"))
核心需求
无论使用哪组数据集,颜色必须严格遵循以下区间映射:
- [0, 0.5) → #E31A1C
- [0.5, 1) → #FF7F00
- [1, 1.5) → #FDBF6F
- [1.5, 2) → #E9E4A6
- [2, 2.5) → #A4D4A9
- [2.5, 3) → #B2DF8A
- [3, 3.5) → #33A02C
- [3.5, 4) → #1F78B4
即使数据未覆盖高区间(比如最大值不到3),也要保留对应区间的图例项,且Data1与Data2的图例完全一致。
解决方案
问题出在scale_fill_gradientn是基于连续渐变的颜色映射,会自动适配当前数据集的数值范围,导致区间和颜色对应混乱。改用scale_fill_stepsn可以实现固定区间的离散颜色映射,同时通过设置limits强制所有图使用同一数值标尺。
修改后的代码:
library(ggplot2) library(dplyr) library(readr) color_breaks <- c(0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0) colors <- c("#E31A1C", "#FF7F00","#FDBF6F","#E9E4A6", "#A4D4A9", "#B2DF8A", "#33A02C", "#1F78B4") # 自定义区间标签 interval_labels <- c( "0-0.5", "0.5-1", "1-1.5", "1.5-2", "2-2.5", "2.5-3", "3-3.5", "3.5-4" ) p1<-ggplot(merged_data, aes(x = longitude, y = latitude, z = median_mafruit)) + stat_summary_2d(bins = 30) + scale_fill_stepsn( colors = colors, breaks = color_breaks, limits = range(color_breaks), # 固定数值范围,确保所有图用同一标尺 labels = interval_labels, show.limits = TRUE, # 显示完整的区间范围 oob = scales::squish, # 超出范围的数据压缩到最近区间 name = "Amount" # 图例标题 ) + labs( title = "Data2", x = "Longitude", y = "Latitude" ) + theme_minimal() + theme( plot.title = element_text(size = 16, face = "bold"), plot.subtitle = element_text(size = 14, face = "italic"), legend.title = element_text(size = 12), legend.text = element_text(size = 10) ) p1
关键修改说明
scale_fill_stepsn替代scale_fill_gradientn:专门用于分段式的颜色映射,严格对应你定义的区间和颜色。limits = range(color_breaks):强制颜色映射的数值范围为0到4,不管当前数据集的最大值是多少,保证不同数据集的图例完全一致。- 自定义
labels:直接显示区间范围,更清晰直观。 oob = scales::squish:如果数据中有超出0-4范围的值,会自动压缩到0或4对应的区间,避免报错或异常颜色。
这样修改后,无论Data1还是Data2,都会使用完全一致的图例和颜色区间,即使数据未覆盖高区间,图例也会保留所有8个区间的项和对应颜色。
内容的提问来源于stack exchange,提问作者Nightowl
相关产品推荐
相关产品推荐

