该文章内容摘抄自:https://segmentfault.com/a/1190000011006780
概念
一个函数,可以将某一区域的值映射到另一区域,其大小关系不变。
比例尺,很像数学中的函数。例如,对于一个一元二次函数,有 x 和 y 两个未知数,当 x 的值确定时,y 的值也就确定了。
在数学中,x 的范围被称为定义域,y 的范围被称为值域。
D3 中的比例尺,也有定义域和值域,分别被称为 domain 和 range。开发者需要指定 domain 和 range 的范围,如此即可得到一个计算关系。
interpolotor
分类
连续性比例尺
d3.scaleLinear线性比例尺
使用d3.scaleLinear()创造一个线性比例尺,而domain()是输入域,range()是输出域,相当于将domain中的数据集映射到range的数据集中。
1
| let scale = d3.scaleLinear().domain([1,5]).range([0,100])
|
映射关系:

接下来,我们来研究这个比例尺的输入和输出。
1 2 3
| scale(1) scale(4) scale(5)
|
刚才的输入都是使用了domain区域里的数据,那么使用区域外的数据会得出什么结果呢?
所以这只是定义了一个映射规则,映射的输入值并不局限于domain()中的输入域。
d3.scaleQuantize量化比例尺
d3.scaleQuantize()也属于连续性比例尺。定义域是连续的,而输出域是离散的。
1
| let scale = d3.scaleQuantize().domain([0, 10]).range(['small', 'medium', 'long'])
|
映射关系:

输入与输出:
1 2 3
| scale(1) scale(5.5) scale(8)
|
而对于domain()域外的情况:
大概就是对于domain()域的两侧的延展。
序数比例尺
d3.scaleBand
d3.scaleBand()并不是一个连续性的比例尺,domain()中使用一个数组,不过range()需要是一个连续域。
1
| let scale = d3.scaleBand().domain([1,2,3,4]).range([0,100])
|
映射关系:

看一下输入与输出:
1 2 3
| scale(1) scale(2) scale(4)
|
当输入不是domain()中的数据集时:
由此可见,d3.scaleBand()只针对domain()中的数据集映射相应的值。
d3.scaleOrdinal
d3.scaleOrdinal()的输入域和输出域都使用离散的数据。
1
| let scale = d3.scaleOrdinal().domain(['jack', 'rose', 'john']).range([10, 20, 30])
|
映射关系:

输入与输出:
1 2 3
| scale('jack') scale('rose') scale('john')
|
当输入不是domain()中的数据集时:
1 2
| scale('tom') scale('trump')
|
时间比例尺
d3.scaleTime
1 2 3 4 5 6
| let scale = d3.scaleTime() .domain([new Date(2017, 0, 1, 0), new Date(2017, 0, 1, 2)]) .range([0,100])
scale(new Date(2017, 0, 1, 0)) scale(new Date(2017, 0, 1, 1))
|
d3.scaleUtc
依据世界标准时间(UTC)来计算
颜色比例尺
10就是10种颜色,20就是20种:
1 2 3 4 5 6 7
| d3.schemeCategory10 d3.schemeCategory20 d3.schemeCategory20b d3.schemeCategory20c
let color = d3.scaleOrdinal(d3.schemeCategory10)
|
其他比例尺
1 2 3 4 5
| d3.scaleIdentity() d3.scaleSqrt() d3.scalePow() d3.scaleLog() d3.scaleQuantile()
|
技巧
如何实现逆向比例尺?
D3中提供了invert()以及invertExtent()方法可以实现这个过程:
1 2 3 4 5
| let scale = d3.scaleLinear().domain([1,5]).range([0,100]) scale.invert(50)
let scale2 = d3.scaleQuantize().domain([0,10]).range(['small', 'big']) scale2.invertExtent('small')
|
不过,值得注意的是,这两种方法只针对连续性比例尺有效,即domain()域为连续性数据集的比例尺。那么非连续性的比例尺就没有invert()方法了吗?
也是有办法的,比如d3.scalePoint的逆向,就可以参考这个文章的方式:
https://stackoverflow.com/questions/40573630/how-can-i-implement-an-invert-function-for-a-point-scale
1 2 3 4 5 6 7 8 9 10 11
|
getDateByPageX(pageX) { const domain = this.xScale.domain(); const range = this.xScale.range(); const rangePoints = d3.range(range[0], range[1], this.xScale.step()) return domain[d3.bisect(rangePoints, pageX) - 1]; }
|
怎么实现负对数比例尺?
将数据处理成线性数据再作图
这是ZHQ想出来的方案,太赞了,这样大大提升了我们组件的扩展性。
参考资料
(精)常用的3种比例尺的可视化讲解:
https://segmentfault.com/a/1190000011006780