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

如何在tidyterra中对连续值分箱时控制重缩放?

问题描述

我尝试用tidyterra的scale_fill_whitebox_b()函数,通过非均匀分布的自定义断点对连续栅格值分箱,目的是突出低值区间的差异。但分箱刻度会自动根据断点间距重缩放配色方案,导致低值区间的颜色过于相近,难以区分。

测试代码如下:

library(ggplot2)
library(terra)
library(tidyterra)

# 构造包含稀疏高值的示例数据
r <- rast(nrows=10, ncols=10)
values(r) <- abs(rnorm(100))
r[17] <- 12
r[22] <- 17
r[72] <- 7
breaks <- c(0, 0.25, 0.5, 1, 2, 5, 10, 20)

ggplot() +
  geom_spatraster(data=r) +
  scale_fill_whitebox_b("viridi", 
                        breaks=breaks, direction=-1)

我发现scale_fill_whitebox_b()基于ggplot的分箱刻度构造函数,该函数有rescaler参数,但不清楚如何在scale_fill_whitebox_b中正确调用。用ggplot原生的scale_fill_stepsn时,可以通过values和limits参数实现无重缩放的效果:

ggplot(r) +
  geom_raster(aes(x=x, y=y, fill=lyr.1)) + 
  scale_fill_stepsn(colors=terrain.colors(7),
                    breaks=breaks,
                    values = scales::rescale(breaks),
                    limits = range(breaks))

但scale_fill_whitebox_b不支持values参数,调整rescaler参数也没成功。我希望复刻geom_spatraster_contour_filled的配色效果——让配色在指定的断点区间之间均匀分布,代码示例:

ggplot() +
  geom_spatraster_contour_filled(data=r, breaks=breaks) +
  scale_fill_whitebox_d("viridi", direction=-1)

解决方案

方法1:转离散因子后用离散型配色(推荐)

先将连续栅格按自定义断点转换为离散分箱因子,再用scale_fill_whitebox_d()实现均匀配色,完全匹配等高线填充的效果:

library(ggplot2)
library(terra)
library(tidyterra)

# 构造数据
r <- rast(nrows=10, ncols=10)
values(r) <- abs(rnorm(100))
r[17] <- 12
r[22] <- 17
r[72] <- 7
breaks <- c(0, 0.25, 0.5, 1, 2, 5, 10, 20)

# 将连续栅格转为分箱后的离散因子栅格
r_cut <- cut(r, breaks = breaks, include.lowest = TRUE)

# 绘图:用离散型whitebox配色
ggplot() +
  geom_spatraster(data = r_cut) +
  scale_fill_whitebox_d("viridi", direction = -1,
                        labels = paste0(breaks[-length(breaks)], "–", breaks[-1])) +
  labs(fill = "数值区间")

方法2:自定义rescaler参数适配分箱刻度

如果坚持使用scale_fill_whitebox_b(),可以通过自定义rescaler,基于区间索引而非数值间距重缩放,实现均匀配色:

ggplot() +
  geom_spatraster(data=r) +
  scale_fill_whitebox_b("viridi", 
                        breaks=breaks, direction=-1,
                        rescaler = function(x, to = c(0, 1), from = NULL) {
                          # 获取每个值对应的区间索引,再对索引重缩放
                          idx <- findInterval(x, breaks)
                          scales::rescale(idx, to = to, from = c(1, length(breaks)-1))
                        })

原理说明
  • 方法1中,terra::cut()将连续值按断点分割为离散区间并标记为因子,scale_fill_whitebox_d()作为离散型刻度,会把配色方案均匀分配给每个因子水平,不会受区间数值间距影响。
  • 方法2通过findInterval()获取值对应的区间索引,再对索引进行重缩放,让每个区间获得相同的配色权重,避免了原生按数值间距缩放的问题。

内容的提问来源于stack exchange,提问作者Jaken

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 14:55:17