D3.js比例尺的作用

比例尺是D3中一个很重要的概念,上一章里提到过直接用数值的大小来代表像素不是一种好的办法,这里正是要解决此问题。

为什么需要比例尺?

上一章制作了一个柱形图,当时有一个数组:

var dataset = [ 250 , 210 , 170 , 130 , 90 ];

绘图时,直接使用 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提供了多种比例尺,下面介绍最常用的两种。

线性比例尺

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

假设有以下数组:

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

现要求如下,把最小的映射成0,最大的映射成300.

var min=d3.min(dataset);
var max=d3.max(dataset);
var linear=d3.scaleLinear()
           .domin([min,max])
           .range([0,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)。
序数比例尺

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

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

我们希望 0 对应颜色 red,1 对应 blue,依次类推。

但是,这些值都是离散的,线性比例尺不适合,需要用到序数比例尺。

var ordinal=d3.scaleOrdinal()
              .domian(index)
              .range(color);  

给柱形图添加比例尺:

在上一章的基础上,修改一下数组,再定义一个线性比例尺。

 var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
    var scalelinear=d3.scaleLinear()
      .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 scalelinear(d);
      })
      .attr("height",rectHeight-2)
      .attr("fill","steelblue");

如此一来,所有的数值,都按照同一个线性比例尺的关系来计算宽度,因此数值之间的大小关系不变。

猜你喜欢

转载自blog.csdn.net/GXing007/article/details/83540546