如何正确使用scale_fill_gradientn()与scale_color_gradientn()?
解决scale_fill_gradientn固定颜色映射且不截断极值的问题
你的核心需求是保留固定的颜色-数值对应关系(对称但间隔不均),同时不截断超出[-2,2]的极值,而是让这些极值使用颜色映射的两端颜色,保证中间颜色刻度以0为中心且对应准确。
方法一:使用oob = scales::squish参数
scale_fill_gradientn的oob参数可控制超出limits范围的数值处理方式,scales::squish会把超出范围的数值“压缩”到limits边界,极值将使用两端颜色而非被截断为NA,同时中间颜色映射完全符合设定的breaks和colorscale。
修改后的代码:
library(tidyverse) # 固定的颜色和断点 colorscale <- c("#760005", "#ec0013", "#ffa938", "#fdd28a", "#fefe53", "#ffffff", "#a2fd6e", "#00b44a", "#008180", "#2a23eb", "#a21fec") breaks <- c(-2.00, -1.50, -1.20, -0.70, -0.50, 0.00, 0.50, 0.70, 1.20, 1.50, 2.00) df <- data.frame( year = seq(2000:2020), value = c(0.24, 1.74, -2.33, 1.48, 0.38, 0.64, 0.97, -1.83, -1.25, -0.49, 3.15, -0.16, -0.12, 0.09, -1.67, -0.64, 0.39, 0.52, -0.58, 0.74, -1.24) ) ggplot(data = df, aes(x = year, y = value, fill = value)) + theme_minimal() + geom_bar(stat = "identity", color = "#c5c5c5c5", linewidth = 0.25) + scale_fill_gradientn( colors = colorscale, values = scales::rescale(breaks), limits = c(-2, 2), oob = scales::squish, # 关键参数:挤压超出范围的数值到边界 na.value = "#e5e5e5", breaks = breaks, # 显示自定义断点 labels = breaks # 断点标签与数值一致 )
方法二:手动分箱+scale_fill_manual
如果需要更精确控制每个区间的颜色(明确每个断点间数值对应的颜色),可先将value按自定义breaks分箱,再用scale_fill_manual指定每个区间的颜色。
代码示例:
library(tidyverse) colorscale <- c("#760005", "#ec0013", "#ffa938", "#fdd28a", "#fefe53", "#ffffff", "#a2fd6e", "#00b44a", "#008180", "#2a23eb", "#a21fec") breaks <- c(-Inf, -2.00, -1.50, -1.20, -0.70, -0.50, 0.00, 0.50, 0.70, 1.20, 1.50, 2.00, Inf) # 增加-inf和inf覆盖极值 df <- df %>% mutate(value_bin = cut(value, breaks = breaks, labels = colorscale)) # 按断点分箱,标签对应颜色 ggplot(data = df, aes(x = year, y = value, fill = value_bin)) + theme_minimal() + geom_bar(stat = "identity", color = "#c5c5c5c5", linewidth = 0.25) + scale_fill_manual( values = setNames(colorscale, colorscale), # 颜色与分箱标签对应 breaks = colorscale, labels = c("< -2", "-2~-1.5", "-1.5~-1.2", "-1.2~-0.7", "-0.7~-0.5", "-0.5~0", "0~0.5", "0.5~0.7", "0.7~1.2", "1.2~1.5", "1.5~2", ">2"), # 自定义刻度标签 name = "Value" )
两种方法的说明
- 方法一适合需要渐变过渡的场景,既保留固定颜色映射,又让极值显示两端颜色,不丢失数据可视化信息。
- 方法二更适合需要明确区间划分的场景,完全手动控制每个区间颜色,适配非均匀间隔的断点需求。
内容的提问来源于stack exchange,提问作者Steffen
相关产品推荐
相关产品推荐

