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

如何修改D3中symlog比例尺的基数?

自定义D3 Symlog比例尺基数的可行方案

我目前在用d3.scaleSymlog绘图,但它不像d3.scaleLog那样支持.base(2)直接设置基数。结合Symlog的数学定义,我尝试了两种可行的自定义基数方案,以下是具体分析:

背景原理

根据D3文档引用的原始论文,Symlog的10进制定义为:

symlog10 = Math.sign(x) * Math.log10(1 + Math.abs(x/c))

而D3内置的symlog用自然对数实现:

symlog = Math.sign(x) * Math.log1p(Math.abs(x / c)) // Math.log1p(x)等价于Math.log(1+x)

根据对数换底公式,要将基数改为2,只需将D3的symlog结果除以Math.log(2),即:

symlog2 = symlog(x) / Math.log(2)

两种实现方法

方法1:基于原生scaleSymlog的缩放变换

利用对数规则log(x^p) = p*log(x),通过对定义域和输入值做幂次缩放,间接实现自定义基数:

const base = 2;
const scalingFactor = 1 / Math.log(base);
const scale = d3.scaleSymlog()
  .domain([Math.pow(domain[0], scalingFactor), Math.pow(domain[1], scalingFactor)])
  .range(range);

// 使用时对输入值做同样缩放
scale(Math.pow(value, scalingFactor))

原理是:symlog(x^(1/Math.log(base))) = (1/Math.log(base)) * symlog(x),刚好等价于目标基数的symlog变换。

方法2:自定义Symlog函数+线性比例尺

直接实现自定义基数的Symlog转换,再结合线性比例尺完成定义域到值域的映射:

function symlog(x, base, c = 1) {
  return (Math.sign(x) * Math.log1p(Math.abs(x / c))) / Math.log(base);
}
const base = 2;
const scale = d3.scaleLinear()
  .domain([symlog(domain[0], base), symlog(domain[1], base)])
  .range(range);

// 使用时先做自定义symlog转换
scale(symlog(value, base))

线性比例尺的逻辑是Y = m * Symlog_base(x) + b,完全符合Symlog变换的映射需求。

关于结果一致性的说明

方法2的结果看起来和原生scaleSymlog()一致,是因为当base=Math.E时,自定义symlog函数的结果就和D3内置的symlog完全相同,此时线性比例尺的映射和原生scaleSymlog的效果自然一致。如果切换到其他基数(比如2),结果就会明显不同。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 19:48:41