D3.js系列——比例尺

Posted 古兰精

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了D3.js系列——比例尺相关的知识,希望对你有一定的参考价值。

  比例尺是 D3 中很重要的一个概念。绘制图形时直接用数值的大小来代表像素不是一种好方法,本章正是要解决此问题。

一、为什么需要比例尺

  上一章制作了一个柱形图,当时有一个数组,绘图时,直接使用 250 给矩形的宽度赋值,即矩形的宽度就是 250 个像素。此方式非常具有局限性,如果数值过大或过小,例如:

var dataset_1 = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
var dataset_2 = [ 2500, 2100, 1700, 1300, 900 ];

  对以上两个数组,绝不可能用 2.5 个像素来代表矩形的宽度,那样根本看不见;也不可能用 2500 个像素来代表矩形的宽度,因为画布没有那么长。于是,我们需要一种计算关系,能够:将某一区域的值映射到另一区域,其大小关系不变这就是比例尺(Scale)。

二、有哪些比例尺

  比例尺,很像数学中的函数。例如,对于一个一元二次函数,有 x 和 y 两个未知数,当 x 的值确定时,y 的值也就确定了。在数学中,x 的范围被称为定义域,y 的范围被称为值域

  D3 中的比例尺,也有定义域和值域,分别被称为 domain 和 range。开发者需要指定 domain 和 range 的范围,如此即可得到一个计算关系。

  D3 提供了多种比例尺,下面介绍最常用的两种。

1、线性比例尺

  线性比例尺,能将一个连续的区间,映射到另一区间。要解决柱形图宽度的问题,就需要线性比例尺。

  假设有以下数组,现有要求如下:将 dataset 中最小的值,映射成 0;将最大的值,映射成 300。代码如下:

        var dataset = [1.2, 2.3, 0.9, 1.5, 3.3];

        var min = d3.min(dataset);
        var max = d3.max(dataset);
         
        var linear = d3.scale.linear()
                .domain([min, max])//注意:domain()/range()里面是个数组形式哦
                .range([0, 300]);
         
        linear(0.9);    //返回 0
        linear(2.3);    //返回 175
        linear(3.3);    //返回 300

  其中,d3.scale.linear() 返回一个线性比例尺。domain() 和 range() 分别设定比例尺的定义域和值域。在这里还用到了两个函数,它们经常与比例尺一起出现:

  d3.max() 、和d3.min():这两个函数能够求数组的最大值和最小值,是 D3 提供的。

  按照以上代码:比例尺的定义域 domain 为:[0.9, 3.3],比例尺的值域 range 为:[0, 300]

  因此,当输入 0.9 时,返回 0;当输入 3.3 时,返回 300。当输入 2.3 时呢?返回 175,这是按照线性函数的规则计算的。

  有一点请大家记住:d3.scale.linear() 的返回值,是可以当做函数来使用的。因此,才有这样的用法:linear(0.9)。

2、序数比例尺

  有时候,定义域和值域不一定是连续的。例如,有两个数组:

var index = [0, 1, 2, 3, 4];
var color = ["red", "blue", "green", "yellow", "black"];

  我们希望 0 对应颜色 red,1 对应 blue,依次类推。但是,这些值都是离散的,线性比例尺不适合,需要用到序数比例尺。

var ordinal = d3.scale.ordinal()
        .domain(index)
        .range(color);
 
ordinal(0); //返回 red
ordinal(2); //返回 green
ordinal(4); //返回 black

  序数比例尺:d3.scale.ordinal();用法与线性比例尺是类似的。

3、应用:

<html> 
<head> 
    <meta charset="utf-8"> 
    <title>简单矩形</title> 
</head> 
<body>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> 
    <script>
    var width = 300;  //画布的宽度
    var height = 300;   //画布的高度
 
    var svg = d3.select("body")     //选择文档中的body元素
        .append("svg")          //添加一个svg元素
        .attr("width", width)       //设定宽度
        .attr("height", height);    //设定高度

    var dataset = [ 2.5 , 2.1 , 1.8 , 1.3 , 0.9 ]; //数据(表示矩形的宽度)
    var linear = d3.scale.linear()
                .domain([0,d3.max(dataset)])
                .range([0,250]);

    var rectHeight = 25;   //每个矩形所占的像素高度(包括空白)
 
    svg.selectAll("rect")
        .data(dataset)
        .enter()
        .append("rect")
        .attr("x",20)
        .attr("y",function(d,i){
             return i * rectHeight;
        })
        .attr("width",function(d){
             return linear(d);  // 此处应用比例尺
        })
        .attr("height",rectHeight-2)
        .attr("fill","steelblue");
    </script> 
</body> 
</html>

  主要就是标红那两块的应用。如此一来,所有的数值,都按照同一个线性比例尺的关系来计算宽度,因此数值之间的大小关系不变。

 

 

以上是关于D3.js系列——比例尺的主要内容,如果未能解决你的问题,请参考以下文章

d3.js(v5.7)的比例尺以及坐标轴

D3.js 入门系列 --- 5.1 做一个带坐标轴和标签的图表

d3.js 颜色比例尺 d3.scale.category10();

D3.js的v5版本入门教程(第七章)—— 比例尺的使用

如何在 d3.js 中同步地图和点图层的比例和位置?

精通D3.js学习笔记比例尺和坐标