《Getting Started with D3》填坑之旅(四):第二章(下)

cover

Chapter 2. The Enter Selection(输入选择)

示例2:绘制广场收费站的日平均流量

本章第二个案例,说的是纽约每天数以万计的上班族都会驱车驶过桥梁隧道,途经多个收费区。交管局会对现金支付和电子支付的情况作统计并向公众公开。利用这一数据,再配合开发者社区的数据清洗,就能绘制出广场收费站的日均流量。

这里分了两步:

  1. 先绘制一个不带说明标签的纯条形图,然后配上 CSS 样式:

    <script>
        let json = null;
        function draw(data) {
            "use strict";
    
            // badass visualization code goes here
            json = data;
            d3.select('body')
                .append('div')
                    .attr('class', 'chart')
                .selectAll('.bar')
                .data(data.cash)
                .enter()
                .append('div')
                    .attr('class', 'bar')
                    .style('width', function(d) { return d.count / 100 + 'px' })
                    .style('outline', '1px solid white')
                    .text(function(d) { return Math.round(d.count) })
        }
    
        d3.json("/demos/data/plaza_traffic.json", draw);
    </script>
    <style>
        * {
            box-sizing: border-box;  /* newly add */
        }
        div.chart {
            font-family: sans-serif;
            font-size: 0.7em;
        }
        div.bar {
            background-color: DarkRed;
            color: white;
            height: 3em;
            line-height: 3em;
            padding-right: 1em;
            margin-top: 0.1rem;  /* original: 2px */
            text-align: right;
        }
    </style>
    

    这里的坑,是加上 CSS 样式后,需要同步修改单个条形轮廓的颜色(或直接注释掉),另外条形图的间距,也最好按实际情况重新设置(0.1rem),即看到如下效果:

纯条形图效果

  1. 接下来要给纯条形图加上广场名,需要调整一下绑定的元素结构:先绑定一个 DIV 容器(.line),在填入两个子容器(.label.bar),分别绑定广场名和流量数:
let json = null;
function draw(data) {
    "use strict";

    // badass visualization code goes here
    json = data;

    d3.select('body')
        .append('div')
            .attr('class', 'chart')
        .selectAll('div.line')
        .data(data.cash)
        .enter()
        .append('div')
            .attr('class', 'line');

    d3.selectAll('div.line')
        .append('div')
            .attr('class', 'label')
            .text(function(d) {return d.name});

    d3.selectAll('div.line')
        .append('div')
            .attr('class', 'bar')
            .style('width', function(d) { return d.count / 100 + 'px' })
            .text(function(d) { return Math.round(d.count) });
}

d3.json("/demos/data/plaza_traffic.json", draw);

注意到父容器 .line 被多次引用,可以在初始绑定时,赋值给一个变量,以便子容器绑定时引用。对第 8、17、22 行作如下微调:

// Line 8
var lines = d3.select('body')
// ...
// Line 17, 22
lines.append('div.line')
// ...

最后再配上 CSS 样式:

* {
    box-sizing: border-box;
}
div.chart {
    font-family: sans-serif;
    font-size: 0.7em;
}
div.bar {
    background-color: DarkRed;
    color: white;
    height: 3em;
    line-height: 3em;
    padding-right: 1em;
    margin-top: .1rem;
    text-align: right;
}
/* New style for lable group */
div.label {
    height: 3em;
    line-height: 3em;
    padding-right: 1em;
    margin-bottom: .1rem;
    float: left;
    width: 20em;
    text-align: right;
}

说好的效果本来是:

在这里插入图片描述

结果却是:

在这里插入图片描述

没错,这是本例留给读者的彩蛋福利:

  1. 标签区宽度 20em 显然是不够的,所以出现了文字重叠(改大些即可,如 25em);
  2. 标签区与数据区重叠:因为没有提到同步修改数据区的 CSS 样式(需加上 margin-left: 25em; 具体空出多少要视 1 的调整结果而定)。

调整后的 CSS 样式:

div.bar {
    background-color: DarkRed;
    color: white;
    height: 3em;
    line-height: 3em;
    padding-right: 1em;
    margin-top: .1rem;
    text-align: right;
    margin-left: 25em; /* newly added */
}
div.label {
    height: 3em;
    line-height: 3em;
    padding-right: 1em;
    margin-bottom: .1rem;
    float: left;
    width: 25em;  /* enlarged width */
    text-align: right;
}

最后来看看版本差异。没有什么特别的注意事项,无非是数据绑定、箭头函数、模板字符串的使用:

d3.select('body')
    .append('div')
        .attr('class', 'chart')
    .selectAll('div.line')
    .data(data.cash)
    .join(enter => {
        const lines = enter.append('div')
            .attr('class', 'line');
        
        lines.append('div')
            .attr('class', 'label')
            .text(d => d.name);
        
        lines.append('div')
            .attr('class', 'bar')
            .style('width', d => `${d.count / 100}px`)
            .text(d => Math.round(d.count));
    });

关于 CSS 样式,再来看书中给过的一处提示(原书第 14 页):

本例采用浮动的 div 标签实现可视化图形,虽然不用混杂除 HTML 以外的知识,但同时也要注意浏览器的布局规则——这样 JavaScript 就要略显复杂;利用 CSS 控制条形图的外观,也可能与用户自定义样式冲突,导致原始图表走样。

填上 CSS 样式的坑后,顿时感到神清气爽(虽然并没有什么直接关联。。。)。要解决上述问题,作者给出的方案,是下一章用到的、基于 SVG 而非 DIV 绘制的可视化图形。

一起来看看下一章(第三章)又给大家精心准备了什么样的坑吧。

内容概要:本文深入探讨了多种高级格兰杰因果检验方法,包括非线性格兰杰因果检验、分位数格兰杰因果检验、混频格兰杰因果检验以及频域因果检验。每种方法都有其独特之处,适用于不同类型的时间序列数据。非线性格兰杰因果检验分为非参数方法、双变量和多元检验,能够在不假设数据分布的情况下处理复杂的关系。分位数格兰杰因果检验则关注不同分位数下的因果关系,尤其适合经济数据的研究。混频格兰杰因果检验解决了不同频率数据之间的因果关系分析问题,而频域因果检验则专注于不同频率成分下的因果关系。文中还提供了具体的Python和R代码示例,帮助读者理解和应用这些方法。 适合人群:从事时间序列分析、经济学、金融学等领域研究的专业人士,尤其是对非线性因果关系感兴趣的学者和技术人员。 使用场景及目标:①研究复杂非线性时间序列数据中的因果关系;②分析不同分位数下的经济变量因果关系;③处理不同频率数据的因果关系;④识别特定频率成分下的因果关系。通过这些方法,研究人员可以获得更全面、细致的因果关系洞察。 阅读建议:由于涉及较多数学公式和编程代码,建议读者具备一定的统计学和编程基础,特别是对时间序列分析有一定了解。同时,建议结合具体案例进行实践操作,以便更好地掌握这些方法的实际应用。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安冬的码畜日常

您的鼓励是我持续优质内容的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值