D3.js数据可视化实战手册

978-7-115-36096-0
作者: 【加拿大】Nick Qi Zhu
译者: 杨锐刘夏王超张沙沙
编辑: 王峰松

图书目录:

详情

本书展示了D3数据可视化库的强大功能,并通过代码示例让读者快速熟悉D3。同时,本书收录了超过70个实际的数据可视化案例,有助于读者解决实际应用中的可视化问题。本书适合那些熟悉HTML、CSS和JavaScript的开发者。

图书摘要

D3.js数据可视化实战手册
[加]Nick Qi Zhu 著

杨锐 刘夏 王超 张沙沙 译

人民邮电出版社

北京

内容提要

如今这个互联网时代,人们每天都生产海量的数据,如果直接面对这些数据,可能让人无从下手。将数据可视化,用形象立体的形式将其展现,有利于分析其中的关联,攫取可能存在的商业机会。本书意图通过大量的示例和代码,向读者讲述如何利用D3.js来实现数据可视化。只要读者了解JavaScript,就能完全掌握本书的内容。

本书一共13章,从如何搭建D3.js的开发环境开始,逐步介绍D3中的各种操作,包括选集、数据的初步处理、数据映射、坐标轴组件、动画过渡效果、SVG相关介绍、绘制图表、安排布局、可视化交互、力学模拟、制作地图和测试驱动。本书包含有大量的示例和代码,可以帮助读者充分理解书中讲述的每一个概念。本书最后的附录部分,介绍了另外两个 JavaScript 库,主要是关于三维制图和多维图表的。希望本书的内容能对读者理解和学习数据可视化有所帮助。

推荐序

ThoughtWorks 公司从 2010 年开始,每年都会发布至少一份引领行业技术潮流和走向的“技术雷达”,在这样的“技术雷达”中,或平台,或工具,或语言,被技术专家们贴上不同的标签——“采用”、“试用”、“尝试”和“停用”,以表明ThoughtWorks根据自己的技术经验和见解,向整个IT行业从业者推介某个条目的程度。如果你是“技术雷达”的长期关注者,你会发现这个舞台上真是瞬息万变,伴随着行业领域的变化和技术趋势的新走向,“技术雷达”也在不断地推陈出新。“你方唱罢我登场”,“技术雷达”上鲜有长期的优胜者,但本书的主角D3.js却是个另类。

D3.js第一次出现在“技术雷达”,是在2012年10月的工具篇中,我们推荐人们“试用”它。而在接下来连着两年的“技术雷达”中,我们都推荐人们在自己的工作和项目中直接“采用”D3.js。D3.js作为遵守Web标准的JavaScript库,凭借其轻量级和易于学习的特性,已经成为新兴的数据可视化技术领域中的重要力量,甚至有人将其比作通用Web开发中的jQuery。

数据可视化是一个逐渐受到重视的领域。人们每天都在生产海量的数据,但海量的数据中依旧蕴含着无限的可能,越是大规模的数据,越是存在可以被挖掘的商业机会,我们可以从中分析出公司的库存走向、用户的行为习惯,甚至新兴行业机会的萌动。这些被分析后得出的数据,成为我们改进和拓展新领域的数据支撑。而数据可视化,会让这个过程更加明晰和具备可说服力。

D3.js作为数据可视化技术领域的佼佼者,相对于其他工具,拥有庞大的用户基数、更加友好开放的社区以及大量的学习资料。我们还注意到,越来越多的非IT从业者,比如业务人员,甚至是记者,也在借助D3.js的强大能力。

很荣幸的是,D3.js 以及本书的原作者Nick Qi Zhu,还有中文版的译者杨锐、刘夏、王超、张沙沙,都是我目前在ThoughtWorks的同事。他们在本书中为读者呈现了大量的示例,以帮助读者最快速地上手D3.js。

谢谢我的同事们。

张凯峰

高级咨询师

ThoughtWorks中国

作者和译者简介

Nick Qi Zhu,资深程序员,可视化实践的狂热爱好者,拥有十多年的软件开发经验。他是 dc.js (dc.js 是基于 D3 开发的,可用于制作多维图表的库)的作者,现就职于ThoughtWorks,任资深咨询师。

在这里,特别感谢Packt出版社对我整个写书过程的支持,尤其是编辑Martin Bell和Sweny Sukumaran,是他们的巧斧神功让我的书更加浅显易读。特别感谢我的技术审核,是他们带给了我很多灵感,让这本书更加完美。

最后,要感谢我的妻子 Sherry,在写书的几个月中,她一直耐心地陪伴我,给我无数支持,没有她,这本书是无法完成的。

杨锐,现就职于ThoughtWorks,QA,工作内容涉及软件测试、Devops。

刘夏,现就职于ThoughtWorks,高级咨询师,关注互联网开发。

王超,现就职于ThoughtWorks,高级咨询师。

张沙沙,80后女程序员,毕业于西南交通大学,现就职于ThoughtWorks,致力于企业级软件开发工作,追求软件质量的卓越和自身的不断提高。

审核人员简介

Andrew Berls 是一名Ruby和JavaScript的开发人员,居住在加拿大的圣芭芭拉。他从知晓HTML标签开始,就爱上了构建网站,现在是一名全栈工程师,网站前台、后端无所不知。他目前在Causes.com公司实习,使用D3.js为虚拟社交网络搭建数据看板。Andrew即将完成加利福尼亚大学圣芭芭拉分校计算机科学专业的学位。除了编程,他还酷爱烹饪(虽然做得不好)和远足。

Kevin Coughlin 拥有着新泽西大学的计算机科学和经济学的双学位。他拥有两年的JavaScript 开发经验。Kevin 结合 HTML 5 标准,使用尖端的客户端和服务端技术,诸如Angular.js、Backbone.js以及Node.js等,为开放网络提供了很多高效的现代化解决方案。

Kevin 还是一名博客活跃分子,他会定期在他的博客上更新新兴技术,有兴趣请查阅http://kevintcoughlin.com。

Ismini Lourentzou 拥有工商管理学学士学位,长期任职于希腊国家银行。对Java 的极大热忱和对新知识的渴望,促使她又在雅典经济与商务大学(AUEB,Athens University of Economics and Business)开始了她的计算机科学学位之路。本科阶段,其作为由Michalis Vazirgiannis教授领衔的AUEB数据和网络挖掘组的成员之一,参与了2012年知识探索与数据挖掘大赛,研究题目为“在线广告代码自动生成(Automated Snippet Generation of Online Advertising)”,并在 2013 年信息知识管理大会(CIKM)上得以发表。同时她也是 AUEB信息恢复组的成员,该小组由Theodore Kalamboukis教授领队,参与了ImageClef 2013大赛。他们的参赛作品在基于图像的文字检索大赛中荣获第 2,在基于图像的视觉检索大赛中获得第5。她对研究和编程的热爱,促成了她的职业转型。目前她是伊利诺伊大学Urbana-Champaign 分校(University of Illinois at Urbana-Champaign)的一名博士生,研究方向为智能信息系统中的机器学习与信息搜索,该技术主要针对文本信息挖掘,以减少用户对文字信息的手动搜索、组织、信息理解的量,来改善用户体验。她希望在完成博士学业后,可以继续研究,每天学习更多的知识。

我要特别感谢我的家人对我的支持和帮助,他们总是激励我,我的妈妈更是在我非常繁忙的时候来照顾我,我的姐姐总是能够理解我,我的父亲亦会在困难的时候支持我。还有,我的男朋友,他用他永恒的耐心和爱来陪伴我,我的朋友也在这个过程中为我提供了很多意见。

Pablo Navarro 是来自智利的数据可视化咨询师。他在法国巴黎高等矿业德·圣-艾蒂安大学(École des Mines de Saint-Etienne,France)获得应用数学硕士学位。在搜索以及数据分析方面工作数年后,他决定专攻网络平台的数据展示,这也正是他目前工作的主要领域。在业余时间,他喜欢水彩插画、跑步以及阅读人类进化论方面的东西。如果你对他的工作有兴趣,请关注http://pnavarrc.github.io。

前言

D3.js是一个JavaScript库,它主要用于对数据的动态图表展示。通过HTML、SVG以及CSS,D3可以让数据展现得更加鲜活。D3使得数字的图形化展示变得异常简单,可以说,它是当下最强大的基于网络的数据可视化技术。

本书理论与实践结合,力图向读者全方位地展示 D3 数字可视化技术,帮助读者快速利用 D3 创建可视化程序。学习完本书后,快速高效地创建叹为观止的数据可视化程序,对读者来说将是小菜一碟!

本书由浅入深,首先介绍了一些 D3 数字可视化编程中的基本概念,继而通过一些代码样例,对D3的其他特性做逐一展示。

在这里,读者将会学习到数据可视化的基本概念,JavaScript 的函数式编程,以及 D3的基础概念,例如元素选取、数据绑定、动画以及SVG生成。除此之外,读者还会领略到D3的一些高级特性,例如自定义插值、自定义中间帧、定时器、布局管理、力,等等。本书还提供了许多预生成的图表和代码,帮助读者更快起步。

本书包括

第1章,D3入门指南,是D3.js预热。它涵盖了一些基本概念,诸如D3.js是什么,以及如何搭建一个适用于D3.js数据可视化程序的开发环境等。

第 2章,精挑细选,向你介绍了D3数字可视化中最基本的一项操作——选集。选集可以帮助读者定位页面上的元素。

第3章,与数据同行,探索了任何数据可视化程序中都会涉及的基础问题——如何通过程序构造、可视化效果展示数据。

第4章,张弛有“度”,介绍了数字可视化中非常重要的一个子领域。作为一个数字可视化的开发人员,如何将数据映射为可视化元素,是一个每天都要面对的问题,本章就此问题做了深入探索。

第5章,玩转坐标轴,介绍了坐标轴组件,以及基于笛卡尔坐标系的可视化程序的相关技术。

第6章,优雅变换,介绍了过渡相关的概念。“一图胜千言”正是对数字可视化的最好总结。这一章涵盖了D3库中过渡以及动画的相关概念。

第7章,图形之美,介绍了SVG相关的概念。SVG是一个广泛用于数字可视化程序的W3C(World Wide Web Consortium)标准。

第8章,图表美化,探索了数据可视化中最为人知的组件——图表。图表是定义良好的且易于理解的数据可视化展示方式。

第9章,井然有序,本章集中讲述D3的布局。D3的布局是一种算法,用于计算和生成元素的位置信息,这些元素可用于生成复杂又有趣的可视化程序。

第10章,可视化交互,本章集中讲述D3对可视化交互的支持,换句话说,即如何向你的可视化程序添加控制能力。

第 11 章,使用“原力”,介绍了D3 中又一神奇的功能——力学。力模拟是数字可视化程序中最炫的一项技术。

第12章,地图的奥秘,介绍了D3基本的地图可视化技术,以及如何在D3中实现一个全功能的可视化地图。

第13章,测试驱动,帮助你使用TDD的方式来实现可视化程序。

附录,Building Interactive Analytics in Minutes,介绍了三维制图Crossfilter.js 和 dc.js技术。

准备工作

◆ 文本编辑器:编辑、创建HTML、CSS、JavaScript文件。

◆ 浏览器:浏览器(火狐3、IE9、Chrome、Safari 3.2及以上版本浏览器)。

◆ 一个本地的HTTP 服务器:本书中的一些章节需要HTTP 服务器来存储数据文件。在第1章,我们将对如何搭建一个简单的Node或者Python的HTTP服务器做出介绍。

◆ Git 客户端(可选):如果你想从 Git 目录迁入本书的源码,你需要在你的机器上安装一个Git客户端。

本书面向对象

如果你是一个开发人员,或者是一个HTML、CSS、JavaScript的狂热爱好者,你希望了解D3的大部分知识,那么这本书非常适合你。这本书还可以作为资深的D3数字可视化程序开发人员的快速参考指南。

读者反馈

我们非常期待读者的反馈。让我们知道你对此书的观点——你喜欢什么,不喜欢什么,这很重要。读者反馈能够帮助我们调整此书内容,更好地为读者介绍所需要的知识。

你可以通过向 feedback@packtpub.com 发送邮件来表达自己的观点,请在主题栏中注明本书的标题。

如果书中包含了你非常擅长的话题,或者你有兴趣编写的部分,请在www.packtpub.com/authors查看我们的指南。

客户支持

作为Packt书籍的拥有者,读者享有如下权利。

下载样例代码

你可以使用你的账户在http://www.packtpub.com下载所购买书籍中的样例代码。如果是在其他地方购买的此书,请通过http://www.packtpub.com/support注册获取源代码。

勘误表

虽然我们尽全力保证书中内容的准确性,但是错误还是在所难免。如果读者在本书中找到错误,可能是文章的错误,也可能是代码的错误,请告知我们。这样,其他读者就不会被错误内容困扰,更好地帮助我们在后续的发行中提升本书质量。如果你发现书中的勘误,请通过 http://www.packtpub.com/submit-errata 来报告,在页面选取你的书籍,然后单击erratasubmissonform链接,并键入错误的详细内容。读者指出的勘误一旦被验证后,就会被上传到我们的网站,或者添加到已存勘误的列表中。读者可以通过http://www.packtpub. com/support进入相关书目标题,查看已知勘误。

版权

版权材料在互联网中的盗版现象几乎是所有媒体中存在的通病。对于Packt,我们严格保护版权和许可证。如果读者在互联网中,无论以任何形式见到我们作品的复制品,请向我们提供地址或者网站名称。

对于涉嫌盗版的材料,请将链接发送至copyright@packtpub.com。

非常感谢你对我们的作者以及本书内容的厚爱!

问题

任何关于本书的疑问,请通过 questions@packtpub.com 联系我们,我们将尽全力帮助你解惑。

第1章 D3.js入门指南

本章涵盖以下内容:

◆ 搭建简易的D3开发环境

◆ 搭建基于NPM(Node Packaged Modules是Node.js的套件管理工具)的开发环境

◆ 理解D3风格的JavaScript

1.1 简介

本章旨在帮助读者初步认识并且运行D3.js。其中包含一些基本知识,比如什么是D3.js,如何搭建一个典型的 D3.js 数据可视化(data visualization)环境。还有一个专门的章节,解释了一些JavaScript中鲜为人知而D3.js又甚为倚重的特性。

什么是D3?D3是指数据驱动文档(Data-Driven Documents),根据D3的官方定义:

D3.js 是一个 JavaScript 库,它可以通过数据来操作文档。D3 可以通过使用HTML、SVG和CSS把数据鲜活形象地展现出来。D3严格遵循Web标准,因而可以让你的程序轻松兼容现代主流浏览器并避免对特定框架的依赖。同时,它提供了强大的可视化组件,可以让使用者以数据驱动的方式去操作DOM。

D3维基(2013年8月)

总的来说,D3是这样一个特殊的JavaScript库,它利用现有的Web标准,通过更简单的(数据驱动)方式来制作炫目的可视化效果。D3.js 由Mike Bostock(http://bost.ocks.org/mike/)制作。之前他制作过一个叫Protovis的数据可视化JavaScript库,如今它已经被D3.js取代。如果想了解更多诸如D3.js制作过程、影响Protovis和D3.js的相关理论这类的信息,可以看看下面的链接。而本书将着眼于如何使用D3.js来增强可视化。D3使用 JavaScript 实现数据可视化的方式比较特别,因此刚开始时可能会让人觉得有些难懂。我希望通过本书中的大量实例,其中有基础的,也有高级的话题,能够帮助大家更好更高效地使用D3。一旦理解了原理,使用D3就可以让数据可视化的效率和丰富程度产生指数化的增长。

更多有关制作 D3 的创意,可以参考 Mike Bostock 于2010年在IEEE InfoVis发表的论文Declarative Language Design fo rInteractive Visualization,链接:http://vis.stanford.edu/papers/protovis-design。

如果对于 D3 是如何制作的感兴趣,建议看看 Mike Bostock 于 2011 年在 IEEE InfoVis 发表的论文 D3:Data-Driven Document,链接:http://vis.stanford.edu/papers/d3。Protovis,D3.js的前辈,是Mike Bostock 和斯坦福可视化组的 Jeff Heer 制做的,相关链接:http://mbostock.github.io/protovis/。

1.2 搭建一个简易的 D3开发环境

在开始使用 D3 之前,我们要做的第一件事是搭建一个开发环境。这节里,我们将告诉你如何在几分钟内搭建一个简单的D3开发环境。

1.2.1 准备阶段

在我们开始前,请确保你已经安装好一个文本编辑器。

1.2.2 搭建环境

我们先要下载D3.js。

1.我们可以在http://d3js.org/下载最新版本的D3.js,也可以在https://github.com/mbostock/d3/tags下载之前的版本。另外,如果你对开发中的最新D3版本感兴趣,可以fork以下的代码库https://github.com/mbostock/d3。

2.下载并且解压缩后,我们得到了3个文件:d3.v3.js、d3.v3.min.js和许可证文件。在开发过程中,建议使用d3.v3.js,它可以帮你深入到D3库中跟踪调试JavaScript代码。把d3.v3.js和新建的index.html放在同一个文件夹里,index.html应该包含下面的代码。

<!--index.html-->

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>Simple D3 Dev Env</title>

<script type="text/javascript" src="d3.v3.js"></script>

</head>

<body>

</body>

</html>

如果是直接下载源代码或者 tagged 版本,JavaScript文件的名字会略微不同,叫做d3.js,而非d3.v3.js。

我们已经搭建了一个最简单的 D3 数据可视化开发环境。现在可以用我们最喜欢的文本编辑器编辑那个html文件,还可以用浏览器打开它来检查可视化的效果。

可以在这里下载这个例子的源码:https://github.com/NickQiZhu/d3-cookbook/tree/master/src/chapter1/simple-dev-env。

1.2.3 工作原理

D3是个相当独立的程序库。它不依赖于特定浏览器提供的功能以及其他JavaScript库。实际上,你甚至可以通过简单的配置,让D3脱离浏览器而在诸如Node.js这样的环境中运行起来(后面的章节会更详细地介绍这点)。

如果你的浏览器是IE9,建议使用Aight兼容库和Sizzle selector engine。其中前者可以在这里下载:https://github.com/shawnbot/aight ,而后者可以在这里下载:http://sizzlejs.com/。

html文件的头部信息中必须包含如下的编码格式声明。

<meta charset="utf-8">

上述声明会告诉浏览器和验证器在渲染页面的时候使用哪个字符集,否则浏览器就不会正确加载D3了,因为D3使用了一些utf-8里面的特殊字符,比如π。

D3是完全开源的。它使用了它的作者Michael Bostock自己定制的开源许可证。该许可证跟流行的MIT许可证十分类似,仅有一点不同,就是其明确声明了Michael Bostock 的名字未经允许不可用来标记此软件的派生品,或者用以扩大此软件的派生品的影响。

1.2.4 更多内容

本书提供了大量的代码示例。所有的源码均可在 GitHub 上下载到( https://github.com)。

如何获取源码

最简单的方式就是直接克隆 Git 上的代码库(https://github.com.NickQiZhu/d3-cookbook)。如果你不打算构建开发环境,跳过这步即可。

如果你不熟悉Git,克隆(clone)很类似于其他的版本控制软件中的签出(checking out)。不过克隆所做的并非简单的签出。它把所有分支和历史拷贝到了你的本地机器,也就是把整个代码库都拷贝到了本地机器中,所以你完全可以使用这个拷贝过来的代码库,在本地环境中离线工作。

如果是首次安装 Git,可以在这里找到 Git 客户端下载列表:http://git-scm.com/downloads,在这里还有针对不同操作系统的安装向导:http://git-scm.com/book/en/Getting-StartedInstalling-Git。

另一个使用Git和GitHub的方式是安装GitHub客户端,它提供了比Git更多样的功能。在作者编写本书时,GitHub仅仅提供了Windows版(http://windows.github.com/)和Mac OS版(http://mac.github.com/)。

安装完Git客户端后,运行下面的命令就可以把本书中所有的代码都下载到你的机器里。

>git clone git://github.com/NickQiZhu/d3-cookbook.git

如果你打算使用GitHub客户端(目前还没有中文版),在 https://github.com/NickQiZhu/d3-cookbook页面点击Fork按钮(在页面的右上角),之后你就可以在GitHub客户端中看到这个代码库了。

1.3 搭建一个基于 NPM的开发环境

如果你所在的项目是一个略复杂的数据展示项目,并且使用了为数不少的 JavaScript库,那我们之前讨论的那个简单的解决方案可能就显得有些褚小杯大,不能胜任了。在这一节当中,我们将展示一个使用了NPM(Node Packaged Modules,实际上就是JavaScript库的代码库管理系统)的更加强大的系统。如果你像我一样没有耐心,想更快地尝试本书最带劲儿的部分,想学点秘传招式,完全可以跳过这部分,如果想搭建一个产品开发环境,再回来看看这部分也不迟。

1.3.1 准备阶段

我们开始前要先确保NPM已经安装好了。在安装Node.js时,NPM作为其中一部分也被安装了。可以在 http://nodejs.org/download/下载 Node.js。选择适合你操作系统的Node.js,安装完毕后,在终端窗口运行如下npm命令。

>npm-v

1.2.14

如果前面的命令输出了NPM客户端的版本号,就说明安装成功了。

1.3.2 搭建环境

安装完NPM后,让我们创建一个包描述符文件,以便自动化一些手动安装的过程。

1.首先,在工程文件夹下,创建名为package.json的文件,包含下面的代码。

{

"name": "d3-project-template",

"version": "0.1.0",

"description": "Ready to go d3 data visualization project template",

"keywords": [

"data visualization",

"d3"

],

"homepage": "<project home page>",

"author": {

"name": "<your name>",

"url": "<your url>"

},

"repository": {

"type": "git",

"url": "<source repo url>"

},

"dependencies": {

"d3":"3.x"

},

"devDependencies": {

"uglify-js": "2.x"

}

}

2.定义package.json文件后,运行下面的命令。

>npm install

1.3.3 工作原理

package.json 文件中绝大部分字段仅仅用于提供信息,比如 name、description、homepage、author和repository。如果你打算把自己的库发布到NPM的代码库中,就要用到name和version字段。现在,我们在意的是dependencies和devDependencies字段。

◆ dependencies字段描述了你的工程所用到的库在运行时的依赖,它们可以使你的工程在浏览器中正常运行。在这个简单的例子中,对于d3我们只有一个依赖。d3是D3在NPM库中发布时使用的名字。版本号3.x标明该工程可以兼容任意大版本为3的发行版,并且NPM应该获取大版本为3的最新的稳定发布版本来满足依赖。

D3是个自满足的库,运行时对外部是零依赖。然而这并不意味着它不能跟其他JavaScript库一起运行。作者平时也使用一些其他的库以便让自己的工作容易些,比如JQuery、Zepto.js、Underscore.js和Backbone.js。

◆ devDependencies字段描述了库在开发时(编译时)的依赖。就是说,这个字段内罗列出来的库文件仅仅在构建工程时会用到,运行JavaScript工程时用不到它们。

关于NPM包JSON文件更详细的文档,可以参考这里https://npmjs.org/doc/json.html。

执行npminstall可以自动触发NPM去下载你工程中所引用的所有依赖,包括递归的下载依赖的依赖。所有的依赖库文件会被下载到node_modules文件夹中,该文件夹位于工程文件夹中的根目录里。这些完成以后,就可以创建一个HTML文件(跟我们之前创建的那个一样),HTML文件直接从node_modules/d3/d3.js来引用D3的JavaScript库。

本节中的代码可以在此处下载,里面包含了自动构建脚本。

https://github.com/NickQiZhu/d3-cookbook/tree/master/src/chapter1/npm-dev-env

工程中会有一些麻烦的地方,比如手动下载JavaScript库以时刻保持它们的版本更新。为了避免这些麻烦,使用 NPM 是个行之有效的方式,可以拯救你于水火之中。当然,一些聪明的读者可能已经发现了,使用这个方法可以把我们的“搭建环境”过程直接提升一个档次。想象一下,你正在构建一个巨大的可视化工程,其中包含了上千行的 JavaScript 代码,很明显我们这里所描述的简单的搭建方式满足不了这种情形。因为“模块化的 JavaScript开发”这个话题足够写本书了,所以这里我们就不再讨论这方面的话题了,我们将把注意力放在数据可视化和D3上。如果你对这方面感兴趣,可以看看这一节的代码,里面演示了如果实现一个模块化的工程,当然也包含了自动构建脚本。在后面单元测试相关的章节中,我们会针对这个话题多讲一些,演示一下,可以在某些方面增强环境,以便运行自动化单元测试。

1.3.4 更多内容

前面提到过,你可以通过浏览器直接打开HTML文件来查看可视化的结果,不过这种方式有一些局限性。一但我们需要从其他文件中加载数据(后面的章节中我们就要这么做了,这也很像你平时工作中的情形),由于浏览器内建的安全机制,这种方式就不好用了。为了绕开这个安全限制,强烈建议搭建一个本地的HTTP服务器,用该服务器来维护HTML页面和数据文件,而非直接从文件系统加载。

搭建本地HTTP服务器

由于使用的操作系统不同,HTTP 服务器的软件包不同,搭建 HTTP 服务器的方法也很不同。这里说几种比较流行的搭建方式。

Python简易HTTP服务器

这是我最喜欢的方式。如果你的机器上已经安装了Python,通常UNIX/Linux/Mac OS发行版上都有,直接运行下面的命令即可。

>python –m SimpleHTTPServer 8888

如果你拥有更新版本的Python,那么你也可以运行如下命令。

>python –m http.server

这个python小程序可以启动一个HTTP服务器,然后你就可以访问该程序所在文件夹中的所有文件。这是目前所有操作系统中运行HTTP服务器最简单的方式。

如果你的机器没有安装 python ,可以在这里下载http://www.python.org/getit/。现在所有的操作系统,诸如Windows、Linux,还有Mac,都支持它。

Node.js HTTP 服务器

安装Node.js之后(前面的小节中所做的搭建开发环境练习,包含了相应的内容),就可以搭建http-server模块了。与Python简易HTTP服务器类似,通过该模块,你可以从任意的文件夹快速启动一个轻量级的HTTP服务器。

安装http-server模块。

>npm install http-server –g

命令中的-g参数会把http-server模块设置为全局的,这样你就可以在命令行里直接使用http-server命令。完成此步后,可以通过下面的命令,在任意文件夹内启动一个服务器。

>http-server .

该命令可以启动一个Node.js驱动的HTTP服务器,默认端口号是8080,也可以用-p参数指定一个端口号。

如果是在Linux/UNIX/Mac的操作系统中运行该命令,需要用sudo模式或者root权限来运行。

1.4 理解 D3风格的 JavaScript

对于那些习惯了过程式或者面向对象式的JavaScript风格的人来说,他们会感觉D3使用函数式的JavaScript编程风格有一些奇怪。本节会涵盖一些JavaScript中函数式编程最根本的功能性概念,以便对D3有个基本的理解,将来可以用D3的风格来编写可视化工程的代码。

1.4.1 准备阶段

在浏览器中打开下面文件的本地副本。

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter1/functional-js.html

1.4.2 开始编程

现在让我们尝试更深入一点,了解一下JavaScript函数式方面的内容。请看下面的代码段,

function SimpleWidget(spec){

var instance={};//<--A

var headline, description;//<--B

instance.render=function(){

var div=d3.select('body').append("div");

div.append("h3").text(headline);//<--C

div.attr("class", "box")

.attr("style", "color:"+spec.color)//<--D

.append("p")

.text(description);//<--E

return instance;//<--F

};

instance.headline=function(h){

if(!arguments.length)h;//<--G

headline=h;

return instance;//<--H

};

instance.description=function(d){

if(!arguments.length)d;

description=d;

return instance;

};

return instance;//<--I

}

var widget=SimpleWidget({color: "#6495ed"})

.headline("Simple Widget")

.description("Thisisasimplewidgetdemonstratingfunctionaljavascript.");

widget.render();

这段代码在页面上生成了下面图片中的示例。

函数式JavaScript简单示例

1.4.3 工作原理

尽管非常简单,但是不可否认,这段示例中的代码跟D3风格的JavaScript非常相似。这不是巧合,在 JavaScript 编程范型中,这叫做函数对象。跟很多有趣的话题一样,这个话题也能写一本书。不过在本节中,我会尝试尽量多讲一些这种特殊范型的东西,好让不理解D3语法的读者也能创建这种风格的库文件。正如D3的维基页面上所讲的那样,这种函数式编程风格给D3带来了很大的便利性。

D3的函数风格,使得多种组件插件之间的代码重用成为现实。

D3维基(2013年8月)

函数即对象

JavaScript中的函数是对象。跟其他的对象一样,函数只是键值对的一个集合。函数对象跟普通对象的区别就是,函数可以执行,函数还带有两个隐藏的属性,即函数上下文和函数代码。这两个隐藏属性有时候会给你一个大大的“意外惊喜”,如果你有着很深的过程式编程背景,这点可能更明显。不过这也是我们最需要注意的关键点了,要了解一下 D3使用函数的奇怪方式。

JavaScript的大部分特性都显得有些不够“面向对象”,不过在函数对象这方面,JavaScript跟其他语言相比较应该更胜一筹。

现在我们心里有了这样的概念,那就再看一遍这段代码。

var instance={};//<--A

var headline, description;//<--B

instance.render=function(){

var div=d3.select('body').append("div");

div.append("h3").text(headline);//<--C

div.attr("class", "box")

.attr("style", "color:"+spec.color)//<--D

.append("p")

.text(description);//<--E

return instance;//<--F

};

在 A、B 和 C行,我们可以看到 instance、headline 和 description 都是 SimpleWidget这个函数对象的内部私有变量。可是render函数却是instance对象的一个方法,并且被定义为对象字面量。函数本身也是对象,它可以存储在对象/函数、其他变量、数组里,也可以作为函数参数。运行SimpleWidget的结果就是I行所写的,返回一个instance对象。

function SimpleWidget(spec){

...

return instance;//<--I

}

render 函数中用到了一些我们还没讲过的 D3 中的函数,不过我们现在先不管它们,后面的章节中我们会详细讲解的。它们也只是渲染了一些可视化的东西,跟我们目前的话题没有太多的关系。

下载示例代码

可以从http://www.packtpub.com下载你购买的所有Packt图书的示例代码。如果是在其他地方购买的话,可以在 http://www.packtpub.com/support 注册一下,代码会通过邮件发送给你。

静态变量作用域

好奇的读者可能会问,这个示例中的变量作用域到底是怎样的啊?看上去好奇怪, render函数不仅访问了instance、headline和description,还访问了从SimpleWidget传进来的spec变量。这个怪异的变量作用域其实是由一个简单的静态作用域规则来决定的。可以把这个规则想象成这样:当查找一个变量引用时,该变量先被当成是一个本地变量。如果没有找到变量声明(比如C行中的headline),就继续在父对象里找(本例中,SimpleWidget函数就是静态的父对象,headline变量的声明在B行)。如果还是没有找到,就不断地重复这个过程,递归地去父对象里查找,一直到全局变量的定义那层。如果最后还是没有找到,就针对该变量生成一个引用错误。这样的作用域行为与大多数流行语言(诸如Java、C#)中的变量处理方式大不相同,可能需要一段时间适应,要是你觉得不习惯的话,也不用担心,练得多了,就习惯了。

对于有 Java 和 C#背景的人,需要再提醒一下, JavaScript没有实现块作用域(block scoping)。我们这里描述的静态作用域规则,仅仅适用于函数/对象级别,不适用于块级别。

for(var i=0;i <10;i++){

for(var i=0;i <2;i++){

console.log(i);

}

}

对于上面这段代码,你可能觉得它会打印20个数字。其实在JavaScript里,这段代码会陷入到无限循环。因为JavaScript没有实现块级别的作用域,所以里面那层循环的i跟外面那层循环的i是同一个变量。于是里面的循环改变了i的值,导致外面的循环永远不会结束。

跟流行的原型编程中的伪类模式相比,这样的模式通常被称作函数模式。函数模式的优点是提供了更好的信息隐藏和封装。因为只能通过静态作用域规则里限定的那些嵌套定义的函数来访问私有变量(我们示例中的headline和description),所以SimpleWidget函数返回的对象就更加灵活,也更加健壮。

如果我们用函数式风格创建对象,并且该对象所有的方法都没有用this,那这个对象就是持久(durable)的 [1]。持久对象就是许多功能行为的集合了。

(CrockfortD.2008年)

可变参数函数

在G行有些奇怪的东西。

instance.headline=function(h){

if(!arguments.length)h;//<--G

headline=h;

return instance;//<--H

};

你可能会问,G行的这个arguments从哪里来的?这个例子中从来没有定义过它。其实这个arguments是内建的隐藏参数,并可在函数执行时直接使用。arguments是一个数组,它包含了所在函数的全部参数。

实际上,arguments本身并不是JavaScript的数组对象。虽然它有 length 属性,并可以用索引下标访问每个元素,但是它没有JavaScript中数组对象的那么多方法(比如slice、concat)。如果你想在arguments上使用JavaScript数组对象的方法,需要这样:

var newArgs=Array.prototype.slice.apply(arguments);

把这个隐藏的参数和JavaScript可以在函数声明时省略参数的功能结合起来,就可以写出instance.headline这种不需要指定参数个数的函数。在本例中,我们可以传一个参数h,也可以不传。因为如果没有传进来参数,arguments.length就返回0,headline函数就返回h,如果h有值,就变成了一个赋值操作。为了说清楚,我们看看下面这段代码。

var widget=SimpleWidget({color: "#6495ed"})

.headline("Simple Widget");//给headline 赋值

console.log(widget.headline());//输出"Simple Widget"

这里你可以看到headline在参数不同的情况下,可以分别作为setter和getter(赋值操作和取值操作)。

函数级联调用

这个例子另一个有趣的地方是函数的级联调用。这也是 D3 库提供的一个主要的函数调用方式,因为 D3 库中的大多数函数都设计成了这种链式的结构,以便能提供简洁的、上下文连贯的编程接口。如果你理解可变参数函数的概念,就很好理解这个了。可变参数函数(比如 headline 函数)能同时作为 setter和 getter,当其作为 setter时,返回 instance对象,这就使得你可以在返回的instance上立即执行另一个函数,此即链式调用。

看下面这段代码。

var widget=SimpleWidget({color: "#6495ed"})

.headline("Simple Widget")

.description("This is ...")

.render();

这个例子中,SimpleWidget 函数返回了 instance 对象(如 I 行所示)。那么,headline函数在这里是一个setter,同时也返回一个instance对象(如H行所示)。description函数执行后也返回instance对象。最后调用了render函数。

现在我们已经大概了解了JavaScript的函数式风格,有了一个可工作的D3开发环境,也准备好了使用 D3 提供的丰富功能来一试身手。在开始前,我还想讲几个比较重点的事情,即如何寻找、分享代码以及有困难时如何获取帮助。

1.4.4 更多内容

先让我们看几个有用的东西。

寻找、分享代码

在 D3 众多值得称赞的亮点中,有一个是比其他可视化工具提供了更加丰富的示例和教程,你可以从中汲取灵感。当我创建自己的开源可视化图表项目,还有写作这本书的时候,我在那些资源中获得了大量的灵感。我会在那些最棒的例子里,挑出一些列个清单出来。这个清单虽然不是百科全书,但却是个不错的入门参考。

◆ D3 gallery(https://github.com/mbostock/d3/wiki/Gallery),这里有不少有趣的例子,可以帮你在线查找 D3 的使用方法,有各种各样的图表、特定的技术,还有一些跟其他工具一起实现的示例。

◆ BioVisualize(http://biovisualize.github.io/d3visualization),算是一个分门别类的D3 gallery,可以帮你快速地在线查找你想要的例子。

◆ D3 教程(https://github.com/mbostock/d3/wiki/Tutorials),有很多朋友不断更新提供的教程、讨论和文档,给你细致地演示了D3的使用方法。

◆ D3 插件(https://github.com/d3/d3-plugins),可能有些你需要的功能是D3没有的。在你自己实践之前,先查查D3的插件库,它提供了各种常用的、不常用的功能。

◆ D3 API(https://github.com/mbostock/d3/wiki/API-Reference)是很不错的文档。这里你能找到D3所提供的全部功能、属性的详细说明。

◆ Mike Bostok's Blocks(http://bl.ocks.org/mbostock)是个D3示例站点,作者是Mike Bostock,这个站点里有很多有趣的例子。

◆ JS Bin(http://jsbin.com/ugacud/1/edit)是个在线的D3测试、实验环境。你可以很容易地通过该工具跟其他人分享一些简单的代码。

◆ JS Fiddle(http://jsfiddle.net/qAHC2/)跟JS Bin差不多,也是一个在线JavaScript代码分享平台。

如何获取帮助

即便有了这些例子、教程,还有书,你在实践的过程里仍然会遇到问题。不过 D3 有数目庞大并且活跃度不错的社区。一般情况,简单地“google”一下,就能找到满意的答案。要是没有也不用担心,D3还有强大的社区支持。

◆ StackOverFlow 上 的 D3.js (http://stackoverflow.com/questions/tagged/d3.js):StackOverflow 是最著名的免费技术主题问答社区站点,D3 在StackOverflow上有专门的页面,可以帮你找到专家,快速地解决你的问题。

◆ D3 Google讨论组(https://groups.google.com/forum/?fromgroups#!forum/d3-js):这是个官方的用户组,不单单有D3,还有一些其他相关的库。

注 释

[1]. 译者注:如果一个对象不包含外部可见的成员数据,并且其方法不会使用this,那么这个对象就是持久的。

相关图书

Python数据科学实战
Python数据科学实战
数据分析实战:方法、工具与可视化
数据分析实战:方法、工具与可视化
Power BI数据挖掘与可视化分析
Power BI数据挖掘与可视化分析
从0到1——Python数据可视化
从0到1——Python数据可视化
善用图表——一看就懂的商业数据表达术
善用图表——一看就懂的商业数据表达术
从Power BI 到 Power Platform:低代码应用开发实战
从Power BI 到 Power Platform:低代码应用开发实战

相关文章

相关课程