ggplot2连续数据离散化的颜色对应自定义问题排查与解决
ggplot2连续数据离散化颜色映射问题排查与解决
在使用ggplot2处理栅格数据时,用scale_fill_steps2和scale_fill_stepsn做离散化颜色映射会出现颜色与数值不匹配的问题:
- 用
scale_fill_steps2设置蓝-白-红渐变时,最高值(25)没对应红色,最低值(1)没对应蓝色 - 用
scale_fill_stepsn自定义区间和颜色时,颜色也没严格对应预设区间
先看用到的数据和原代码:
数据准备代码
library(terra) library(legendry) library(tidyverse) library(tidyterra) m <- matrix(c(1:24,25), nrow=5, ncol=5) n <- matrix(rep(5,time=25),nrow = 5,ncol = 5) ## as.double() ---- dt <- rast(c(A = rast(m),B = rast(n))) |> as.double()
原scale_fill_steps2代码
ggplot() + geom_spatraster(data = rast(m), na.rm = TRUE) + scale_fill_steps2( low = 'blue', mid = 'white', high = 'red', midpoint = 10, na.value = NA, guide = guide_colourbar( barwidth = unit(5, "cm"), barheight = unit(0.4, "cm"), title = 'Pre (mm/day)', title.position = "top", position = 'bottom' ) ) + scale_y_continuous(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0)) + theme_bw() + theme(aspect.ratio = 1)
原scale_fill_stepsn代码
ggplot() + geom_spatraster(data = dt, na.rm = TRUE) + scale_fill_stepsn( # n.breaks = 5, colors = c("blue", 'green', "yellow", "orange", "red"), breaks = c (5, 10, 15, 20), na.value = NA, guide = guide_colourbar( barwidth = unit(5, "cm"), barheight = unit(0.4, "cm"), title = 'Pre (mm/day)', title.position = "top", position = 'bottom' ) ) + facet_grid(~lyr) + scale_y_continuous(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0)) + theme_bw() + theme(aspect.ratio = 1)
问题原因与解决方法
1. scale_fill_steps2的问题
原因
scale_fill_steps2默认按中点对称的范围映射颜色,不是直接把数据极值绑定到low和high。你的数据范围是1-25,中点设为10,中点到最低值的距离是9,到最高值是15,它会自动把渐变范围扩展到10-15=-5到10+15=25。但你的数据最低值是1(比-5大),所以不会显示最深的蓝色;最高值虽为25,但渐变从-5开始,红色饱和度被拉低,看起来不是纯红。
解决方法
强制颜色渐变范围匹配数据实际极值,或者自定义缩放逻辑,让数据最小值对应low、最大值对应high。
修正后的代码:
ggplot() + geom_spatraster(data = rast(m), na.rm = TRUE) + scale_fill_steps2( low = 'blue', mid = 'white', high = 'red', midpoint = 10, # 强制颜色范围匹配数据极值,让low对应1,high对应25 limits = c(1, 25), # 自定义缩放逻辑,直接把数据范围映射到low-mid-high rescaler = function(x, to = c(0, 1), from = range(x, na.rm = TRUE)) { scales::rescale(x, to = to, from = from) }, na.value = NA, guide = guide_colourbar( barwidth = unit(5, "cm"), barheight = unit(0.4, "cm"), title = 'Pre (mm/day)', title.position = "top", position = 'bottom' ) ) + scale_y_continuous(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0)) + theme_bw() + theme(aspect.ratio = 1)
2. scale_fill_stepsn的问题
原因
scale_fill_stepsn中,breaks是区间分隔点,5个颜色对应4个breaks(划分5个区间),但默认会自动扩展breaks范围到数据极值,导致颜色和区间的对应关系偏移。比如你的数据A层是1-25,breaks设为5,10,15,20,它会自动把第一个区间扩展到(-∞,5],最后一个到(20,+∞),但颜色映射是按数据整体范围线性分配,不是严格对应每个区间。
解决方法
要么把breaks扩展到包含数据极值,明确每个区间的边界;要么设置limits匹配数据范围,同时手动指定颜色对应的数值位置。
方法一:扩展breaks到包含极值
ggplot() + geom_spatraster(data = dt, na.rm = TRUE) + scale_fill_stepsn( colors = c("blue", 'green', "yellow", "orange", "red"), # 加入数据极值,明确5个区间:[1,5],(5,10],(10,15],(15,20],(20,25] breaks = c(1, 5, 10, 15, 20, 25), # 强制范围匹配数据,避免自动扩展 limits = c(1, 25), na.value = NA, guide = guide_colourbar( barwidth = unit(5, "cm"), barheight = unit(0.4, "cm"), title = 'Pre (mm/day)', title.position = "top", position = 'bottom' ) ) + facet_grid(~lyr) + scale_y_continuous(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0)) + theme_bw() + theme(aspect.ratio = 1)
方法二:保留原breaks,手动指定颜色位置
ggplot() + geom_spatraster(data = dt, na.rm = TRUE) + scale_fill_stepsn( colors = c("blue", 'green', "yellow", "orange", "red"), breaks = c(5, 10, 15, 20), limits = c(1, 25), # 手动指定每个颜色对应的数值点,对应区间的边界 values = scales::rescale(c(1,5,10,15,20,25)), na.value = NA, guide = guide_colourbar( barwidth = unit(5, "cm"), barheight = unit(0.4, "cm"), title = 'Pre (mm/day)', title.position = "top", position = 'bottom' ) ) + facet_grid(~lyr) + scale_y_continuous(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0)) + theme_bw() + theme(aspect.ratio = 1)
内容的提问来源于stack exchange,提问作者Breeze
相关产品推荐
相关产品推荐

