欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

D3.js入门教程之比例尺

程序员文章站 2023-11-14 16:20:52
d3.js入门教程之比例尺,在数据可视化的过程中,往往需要将一个值转换为另一个值。例如要绘制一个历年产值的柱状图,我们需要把3000万的产值投射为屏幕上300个像素的高度。以数学上...

d3.js入门教程之比例尺,在数据可视化的过程中,往往需要将一个值转换为另一个值。例如要绘制一个历年产值的柱状图,我们需要把3000万的产值投射为屏幕上300个像素的高度。以数学上的“函数”为例:y=2x+1。在这里,x的取值范围假定为[0, 2],这称为“定义域”。则y的取值范围为[1, 5],这称为“值域”。通过一个函数式提供了定义域到值域的对应关系,d3提供了将一个量转换为另一个量的方法,称为“比例尺”(scale)。

比例尺是d3的基本概念,每一种比例尺都要指定一个定义域(domain)和值域(range)。比例尺分为两种情况:
(1)连续的定义域对应连续的(或离散的)值域——定量比例尺;
(2)离散的定义域对应离散的值域——序数比例尺;

一、定量比例尺

1. 线性比例尺:计算线性对应关系。将连续的定义域对应到连续的值域上。

d3.scalelinear()——创建一个线性比例尺; linear(x)——输入定义域x的值,返回值域对应的值; linear.invert(y)——输入值域内的值,返回定义域内对应的值; linear.domain([numbers])——获取或定义定义域; linear.range([values])——获取或定义值域; linear.rangeround([values])——等同于range(),获取或定义值域。比例尺的输出值会进行四舍五入的运算,得到一个整数; linear.clamp([boolean])——定义当比例尺得到一个超过定义域的值的时候,是否进行转换。默认为flase表示可以接受超出范围的值; linear.nice([count])——将定义域的范围扩展到比较理想的形式; linear.ticks([count])——设定或获取定义域内具有代表性的值得数目,count默认为10。该方法主要用于获取坐标轴的刻度; linear.tickformat(count[, format])——设置定义域内具有代表性值的表现形式,主要用于坐标轴上;

<script>
        var linear = d3.scalelinear() // 创建线性比例尺
                .domain([0, 500]) // 定义域
                .range([0, 100]);   // 值域

        console.log(linear(50)); // 输出定义域50所对应的值域值:10
        console.log(linear.invert(50)); // 输出值域50所对应的定义域的值:250
        console.log(linear.domain()); // 获取定义域
        console.log(linear.range()); // 获取值域

        console.log(linear(1000)); // 输出200
        linear.clamp(true); // 禁止接受超值范围的输入
        console.log(linear(1000)); // 只输出定义域最大值500所对应的值域:100

        linear.rangeround([0, 100]);
        console.log(linear(13.33)); // 本身的输出是2.66,四舍五入为3

        linear.domain([0.12300000, 0.488888888]).nice();
        console.log(linear.domain()); // [0.1, 0.5]

        linear = d3.scalelinear()
                .domain([-20, 20])
                .range([0, 100]);
        var ticks = linear.ticks(5);
        console.log(ticks); // [-20, -10, 0, 10, 20]
        var tickformat = linear.tickformat(5, "+"); // 给数字添加符号,0或正数添加+,负数添加-
        //for(var i=0; i;>

定义域和值域也可以定义多个数字,但是两者数量必须相等。

2. 指数比例尺和对数比例尺:用于计算指数对应关系和对数对应关系。将连续的定义域对应到连续的值域上。
方法和线性比例尺一样,指数比例尺(scalepow)多了一个exponent([value]),用于指定指数。对数比例尺(scalelog)多了一个方法名为base([value]),用于设定对数。


<script>
        // 指数比例尺
        var pow = d3.scalepow().exponent(2);
        console.log(pow(10)); // 100

        // 对数比例尺
        var log = d3.scalelog().base(10);
        console.log(log(100)); // 2

        // domain和range的意义
        var pow1 = d3.scalepow().exponent(3)
                .domain([0, 3])
                .range([0, 90]);
        console.log(pow1(1.5)); // 11.25
    </script>

在指数和对数比例尺情况下,定义domain和range的意义在于,d3会先把定义域按照指数关系计算出来,并对应到值域上面去。比如上面的代码,定义了指数为3,定义域为[0, 3]。实际上,d3建立了一个定义域的指数计算,即[0, 27],并通过线性比例尺将其对应到[0, 90]上面去。然后计算了1.5的3次方为3.375,线性过去以后就是11.25。

3. 量化比例尺和分位比例尺:将连续的定义域对应到离散的值域
量化比例尺(scalequantize)将连续的定义域自动对应到离散的值域上。比如定义域为[0, 10],值域为[“red”, “green”, “blue”, “yellow”, “black”]。则转换为:

[0, 2)——red [2, 4)——green [4, 6)——blue [6, 8)——yellow [8, 10)——black
例如下面的代码输入为5个不同灰度的圆:

<script>
        var color = d3.scalequantize()
                .domain([0, 50])
                .range(["#000", "#222", "#444", "#666", "#888"]);

        // 定义圆半径
        var r = [45, 35, 25, 15, 5]; 

        // 添加svg元素
        var svg = d3.select("body").append("svg")
                .attr("width", 400)
                .attr("height", 400);

        // 画圆
        svg.selectall("circle")
                .data(r)
                .enter()
                .append("circle")
                .attr("cx", function(d, i){ return 50+i*30; })
                .attr("cy", 50)
                .attr("r", function(d){ return d; })
                .attr("fill", function(d){ return color(d); });
    </script>

分位比例尺(scalequantile),和量化比例尺一样,也是将连续的定义域定义到离散的值域上。和量化比例尺不同的是,量化比例值只考虑定义域的起止值,然后根据值域平均切割。而分位比例尺考虑定义域中的所有的值。如下:


<script>
        // 量化比例尺
        var quantize = d3.scalequantize()
                .domain([0, 10])
                .range([1, 100]);
        // 分位比例尺
        var quantile = d3.scalequantile()
                .domain([0, 2, 4, 10])
                .range([1, 100]);

        console.log(quantize(3)); // 1
        console.log(quantile(3)); // 100
    </script>

对于scalequantize而言,值域为1和100,则定义域进行两段的平均切割。定义域[0, 10]的平均切割就是中位数5。而scalequantile而言,值域也是离散值1和100,但定义域为[0, 2, 4, 10]。那么它的中位数就是(2+4)/2=3。如果定义域为[0, 2, 4, 9, 10],则它的中位数就是4。如果不确定分位比例尺的分位数,可以通过方法scalequantile.quantiles()来获取。

4. 阈值比例尺:设定n个阈值,将值域分成n+1个。连续的定义域对应离散的自值域。阈值比例尺(threshold),比如下面的例子:


<script>
        var threshold = d3.scalethreshold()
                .domain([10, 20, 30])
                .range(["red", "green", "blue", "black"]);

        console.log(threshold(5)); // red
        console.log(threshold(15)); // green
        console.log(threshold(25)); // blue
        console.log(threshold(35)); // black
    </script>

二、序数比例尺

序数比例尺实现离散的定义域到离散的值域的对应关系。

d3.scaleordinal()——创建一个序数比例尺; ordinal(x)——根据定义域的x的值获取值域对应的值; ordinal.domain([values])——获取或设置定义域; ordinal.range([values])——获取或定义值域;

<script>
        var ordinal = d3.scaleordinal()
                .domain([1, 2, 3, 4, 5])
                .range([10, 20, 30, 40, 50]);
        console.log(ordinal(1)); // 10
        console.log(ordinal(3)); // 30
        console.log(ordinal(5)); // 50
        console.log(ordinal(8)); // 不在定义域内,输出为10
    </script>