「前言」
网上关于桑基图的例子也有一些,但是对于初入门的新手并不友好、易懂。如果仅用百度搜索,资料更是少得可怜(这里感谢同事推荐shadowsocks进行科学上网●^●)。当然有些语句没有看懂,anyway先实现了再说~
「什么是桑基图」
桑基图(Sankey diagram),即桑基能量分流图,主要是用来描述能量、人口、经济等的流动情况。因1898年Matthew Henry Phineas Riall Sankey绘制的“蒸汽机的能源效率图”而闻名,此后便以其名字命名为“桑基图”。
桑基图主要关注能量、物料或资本等在系统内部的流动和转移情况。Sankey diagram的特点有:
- 起始流量和结束流量相同
- 在内部,不同的线条代表了不同的流量分流情况,它的宽度成比例地显示此分支占有的流量
- 节点不同的宽度代表了特定状态下的流量大小
在数据可视化中,桑基图有利于展现分类维度间的相关性,以流的形式呈现共享同一类别的元素数量。特别适合表达集群的发展,比如展示特定群体的人数分布等。我们可以欣赏下利用桑基图展示的可视化作品,太美了简直!
「绘制桑基图」
绘制画布SVG
|
|
在body中定义一个<p>
元素,令id="chart"
,画布SVG作用在元素<p>
中,保持有一定的margin。
定义桑基布局
|
|
sankey.link()
函数应该是插件sankey.js中定义好的,目的是生成节点相对应的路径。
绑定数据
|
|
这里我们通过引用外部JS数据的方式来绑定,之后直接使用energy.
的方式调用,方式如下:d3.json("XXX.json", function(error, energy) {};
注意
如果不启动外部服务器,是没有办法加载外部数据的。由于Python自带的包可以建立简单的Web服务器,便直接用Python:
- 命令行中直接CD到准备做服务器的根目录下,输入命令:
python -m SimpleHTTPServer 8080
(这里使用的2.X版本,3.X版本稍有不同) - 然后就可以在浏览器中输入:
http://localhost:8080/路径
来访问服务器的资源
JSON数据
这里的JSON数据长这样:
{“nodes”:[
{“name”:”Wealth Management”},
{“name”:”WMA”},
…
{“name”:”Switzerland”}
],
“links”:[
{“source”:0,”target”:5,”value”:100},
{“source”:1,”target”:5,”value”:1800},
….
{“source”:4,”target”:8,”value”:400}
]}
nodes表示节点数据;links表示连线数据,其中source为起始节点,target表示终点节点,value为量的大小。关于.layout()
,查了相关资料,好像是跟计算出来的节点与路径数据的迭代次数(iterations)有关,但是调整参数值并没有发现什么变化。
绘制路径数据links
|
|
stroke-width
参数表示links的宽度,返回的是1和dy中的最大值,但大部分情况都会返回dy。如果换成10(这样每根连线都是一样宽度),看一下效果就知道stroke-width
的作用了:
stroke
其实是描边的意思,感觉由于header部分设置过了fill:none
,所以才默认为填充的颜色。这里设置相同起始节点的连线具有相同的颜色,确保达到你想要颜色分类的效果。同时对每条links添加title,鼠标悬停会显示相应内容。
绘制节点数据nodes
|
|
每个rect
元素的高度(height)相同,宽度(width)为相应的dy;stroke
把外框颜色设置成与rect
元素同样的颜色并加深,图片放大可以明显的看出效果),.text
添加鼠标悬停显示相应文字,效果如下:
添加交互效果
1.用CSS控制悬浮样式,让连接线在鼠标悬停的时候高亮显示:
2.节点添加拖动事件
定义一个拖动事件,这里仅限于水平方向的移动,移动之后重新布局并生成行的路径
1234567function dragmove(d) {d3.select(this).attr("transform","translate(" + (d.x = Math.max(0,Math.min(width - d.dy, d3.event.x))) + "," + d.y + ")") ;sankey.relayout(); // 重新布局link.attr("d",path);}对node节点添加事件
123456789node.call(d3.behavior.drag() //这一段只知道大概是什么意思.origin(function(d){return d;}).on("dragstart",function() {this.parentNode.appendChild(this);}).on("drag",dragmove));
好了,现在我们就可以做出首页第一张sankey图的效果了,最后再附上自己做的另一张横版sankey图(好像是由于sankey.js插件的问题,导致横竖排版)
源代码
|
|
「参考资料」
【D3 Tips and Tricks v4.x】
【D3.js数据可视化实战】—(3)桑基图(sankey)的绘制
【USB 2015 Q1 Results】