布局 弦图

弦图是什么

弦图(Chord),主要用于展示多个节点之间的联系。

两点之间的连线,表示谁和谁具有联系。

线的粗细表示权重。

上面的介绍源于这里 ,详细的不说了,还是很好理解的。

那么在 D3 中怎么用布局得到绘制弦图所需的数据呢?请耐心往下看。

数据

现有初始数据如下。

var city_name = [ "北京" , "上海" , "广州" , "深圳" , "香港"  ];
        
var population = [
          [ 1000,  3045 , 4567 , 1234 , 3714 ],
          [ 3214,  2000 , 2060 , 124  , 3234 ],
          [ 8761,  6545 , 3000 , 8045 , 647  ],
          [ 3211,  1067 , 3214 , 4000 , 1006 ],
          [ 2146,  1034 , 6745 , 4764 , 5000 ]
        ];

数据是一些城市名和一些数字,这些数字表示城市人口的来源。其意思如下:

城市 北京 上海
北京 1000 3045
上海 3214 2000

左边第一列是被统计人口的城市,上边第一行是被统计的来源城市,即:

北京市的人口有 1000 个人来自本地,有 3045 人是来自上海的移民,总人口为 1000 + 3045。

上海市的人口有 2000 个人来自本地,有 3214 人是来自北京的移民,总人口为 3214 + 2000。

好了!!!对于这样一组数据,怎么进行可视化。

布局(数据转换)

弦图的布局定义如下。

 var chord_layout = d3.layout.chord()
      .padding(0.03) //节点之间的间隔
      .sortSubgroups(d3.descending) //排序
      .matrix(population); //输入矩阵

然后,应用此布局转换数据。

var groups = chord_layout.groups();
var chords = chord_layout.chords();

console.log( groups );
console.log( chords );

population 经过转换后,实际上分成了两部分:groups 和 chords。前者是节点,后者是连线,也就是弦。chords 就是上图中的连线。chords 里面又分为 source 和 target ,也就是连线的两端。

在控制台输出一下节点和连线,看看得到了怎样的数据。

节点:

连线(弦):

定义相关变量

应该很熟悉了,不需要解释。

 var width = 600;
 var height = 600;
 var innerRadius = width/2 * 0.7;
 var outerRadius = innerRadius * 1.1;

 var color20 = d3.scale.category20();

 var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(" + width/2 + "," + height/2 + ")");

绘制节点

绘制节点(即分组,有多少个城市画多少个弧形),及绘制城市名称。

 var outer_arc = d3.svg.arc()
    .innerRadius(innerRadius)
    .outerRadius(outerRadius);
 
 var g_outer = svg.append("g");
 
 g_outer.selectAll("path")
    .data(groups)
    .enter()
    .append("path")
    .style("fill", function(d) { return color20(d.index); })
    .style("stroke", function(d) { return color20(d.index); })
    .attr("d", outer_arc );
 
 g_outer.selectAll("text")
    .data(groups)
    .enter()
    .append("text")
    .each( function(d,i) { 
       d.angle = (d.startAngle + d.endAngle) / 2; 
       d.name = city_name[i];
    })
    .attr("dy",".35em")
    .attr("transform", function(d){
       return "rotate(" + ( d.angle * 180 / Math.PI ) + ")" +
       "translate(0,"+ -1.0*(outerRadius+10) +")" +
       ( ( d.angle > Math.PI*3/4 && d.angle < Math.PI*5/4 ) ? "rotate(180)" : "");
     })
    .text(function(d){
       return d.name;
    });

节点位于弦图的外部。节点数组 groups 的每一项,都有起始角度和终止角度,因此节点其实是用弧形来表示的,这与饼状图类似,可以参照饼状图布局,应该好理解上面的代码。

然后就是节点的文字(即城市名称),有两个地方要特别注意。

each():表示对任何一个绑定数据的元素,都执行后面的无名函数 function(d,i) ,函数体里做两件事:

transform 的参数:用 translate 进行坐标变换时,要注意顺序: rotate -> translate(先旋转再平移)。 此外,

( ( d.angle > Math.PI*3/4 && d.angle < Math.PI*5/4 ) ? "rotate(180)" : "")

意思是,当角度在 135° 到 225° 之间时,旋转 180°。不这么做的话,下方的文字是倒的。

绘制连线(弦)

绘制连线(即所有城市人口的来源,即有 5 * 5 = 25 条弧。

var inner_chord = d3.svg.chord()
    .radius(innerRadius);
 
svg.append("g")
    .attr("class", "chord")
    .selectAll("path")
    .data(chords)
    .enter()
    .append("path")
    .attr("d", inner_chord )  //
    .style("fill", function(d) { return color20(d.source.index); })
    .style("opacity", 1)
    .on("mouseover",function(d,i){
        d3.select(this)
          .style("fill","yellow");
    })
    .on("mouseout",function(d,i) { 
        d3.select(this)
          .transition()
          .duration(1000)
          .style("fill",color20(d.source.index));
    });

SVG 中没有现成的弦元素(例如圆有 <circle>,但是弦却没有 <chord>),需要用路径元素 <path> 来制作。至于路径值是什么呢?我们不需要手动计算,D3 提供了 d3.svg.chord() ,只需要将弦的对象传递给它,即可得到路径值。

上面还有几句关于交互式操作的代码: mouseover 和 mouseout 。 可参考入门第十一课

结果如下图。

源代码

下载地址:chord.zip

在线演示

委托名片直接发送邮件(需邮箱客户端)点击复制邮箱地址14721230383项目委托、技术支持,欢迎与我们联系。休息日7:00 ~ 11:0012:00 ~ 22:00工作日11:00 ~ 11:4016:00 ~ 22:00

Copyright 2014-2016, DecemberCafe, All Rights Reserved