You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 10:29:59