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])——设置定义域内具有代表性值的表现形式,主要用于坐标轴上;
<body>
    <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<ticks.length; i++){
        //    ticks[i] = tickFormat(ticks[i]);
        //}
        //console.log(ticks); // [-20, -10, +0, +10, +20]
        console.log(ticks.map(tickFormat)); // [-20, -10, +0, +10, +20]
    </script>
</body>

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

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

<body>
    <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>
</body>

在指数和对数比例尺情况下,定义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个不同灰度的圆:
<body>
    <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>
</body>

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

<body>
    <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>
</body>

对于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),比如下面的例子:

<body>
    <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>
</body>

二、序数比例尺

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

  • d3.ScaleOrdinal()——创建一个序数比例尺;
  • ordinal(x)——根据定义域的x的值获取值域对应的值;
  • ordinal.domain([values])——获取或设置定义域;
  • ordinal.range([values])——获取或定义值域;
<body>
    <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>
</body>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值