如何修改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
相关产品推荐
相关产品推荐

