桑基图(Echarts)——自定义风格
桑基图绘制——使用Echarts
桑基图(Sankey diagram),即桑基能量分流图,也叫桑基能量平衡图。它是一种特定类型的流程图,图中延伸的分支的宽度对应数据流量的大小,通常应用于能源、材料成分、金融等数据的可视化分析。
数据要求: 桑基图理论上只支持有向无环图(DAG, Directed Acyclic Graph),所以要确保可视化数据中的边是无环的。
本篇以北京、上海的移民统计为例,参照Echarts官方提供的示例代码,介绍如何定制自己风格的桑基图。
一、节点和边设置统一风格
第一种样式主要是统一对节点和边进行了风格设置,城市节点统一为深蓝色#1b6199,边为一个渐变效果,效果如下图:

1、数据格式
数据包括城市节点和两城市间的移民统计:
var citylist = [
{name: '北京'},
{name: '上海'},
{name: '广州'},
{name: '深圳'},
{name: '香港'}
];
var population=[
{source: "广州", target: "北京", value: 4567},
{source: "广州", target: "上海", value: 2060},
{source: "深圳", target: "北京", value: 1234},
{source: "深圳", target: "上海", value: 124},
{source: "香港", target: "北京", value: 3714},
{source: "香港", target: "上海", value: 3234}
];
2、样式配置
系列列表series中itemStyle用来设置节点的样式,lineStyle用来设置边的样式。注意:在series中设置的样式应用于所有数据的渲染。具体代码如下:
itemStyle: {
borderWidth: 1, //设置节点的边界宽度
color:'#1b6199', //设置节点颜色
borderColor: '#fff' //设置节点的边界颜色色
},
lineStyle: {
//线性渐变,前四个参数分别是 x0, y0, x2, y2, 范围从 0 - 1,相当于在图形包围盒中的百分比
color:new echarts.graphic.LinearGradient(0, 0, 1, 0, [{ //设置边为水平方向渐变
offset: 0,
color: '#136bff'
},{
offset: 1,
color: '#87ffd6'
}]),
curveness: 0.5, //设置边的曲度
opacity:0.5 //设置边的透明度
}
二、自定义风格
第二种情况是我们根据数据进行自定义风格,每个节点、边可以设置自己的风格属性,这也是我们经常需要的效果。这里我们对每个节点进行了颜色区分,边则是依赖于两边节点的渐变效果,如下图所示:

1、数据格式
(1)城市节点和颜色:城市名称作为key,颜色作为value
var city={
'北京':'#c23531',
'上海':'#2f4554',
'广州':'#61a0a8',
'深圳':'#d48265',
'香港':'#749f83'
}
(2)移民统计情况:
var population=[
{source: "广州", target: "北京", value: 4567},
{source: "广州", target: "上海", value: 2060},
{source: "深圳", target: "北京", value: 1234},
{source: "深圳", target: "上海", value: 124},
{source: "香港", target: "北京", value: 3714},
{source: "香港", target: "上海", value: 3234}
];
2、数据处理
为了实现对单独数据的样式设置,我们需要对上述数据进行遍历,生成满足echarts要求的数据集,并逐个添加自己的样式。
节点的处理主要是构造节点对象,包括name和itemStyle两个键,itemStyle里边有包含了颜色信息。
注意:这里的颜色只对当前的节点对象有作用,并且要优先于series中的样式。
//定义一个数组
var citylist=[];
//遍历city
for(var key in city){
citylist.push(
{name: key,itemStyle: {color:city[key]}} //构造节点对象,包括name和itemStyle
)
}
边与节点类似,需要在population的每个对象中添加lineStyle,这里同样使用了线性渐变色。代码如下:
//定义一个数组
var data=[];
for(var i=0;i<population.length;i++){
var color = new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
offset: 0,
color: city[population[i].source] //获取起始节点的颜色属性
},{
offset: 1,
color: city[population[i].target] //获取结尾节点的颜色属性
}]
)
data.push({
source: population[i].source,
target: population[i].target,
value: population[i].value,
lineStyle: { //添加样式配置
color:color
}
}
)
}
3、统一样式的配置
在第二步中我们主要对颜色进行了自定义配置,其他统一的样式还是在series中进行配置:
series: [
{
type: 'sankey',
data: citylist,
links: data,
focusNodeAdjacency: 'allEdges', //鼠标悬停到节点或边上,相邻接的节点和边高亮显示
itemStyle: {
borderWidth: 1,
borderColor: '#fff'
},
lineStyle: {
curveness: 0.5,
opacity:0.5
}
}
]
当然,自定义样式不仅仅修改颜色,大家可以根据官方配置文档试试其他样式的设置,这里就不多介绍了。
三、自定义完整代码
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>桑基图demo</title>
<style>
*{
margin:0;
padding:0;
}
html,body {
height:100%;
}
#main{
height:100%;
}
</style>
</head>
<body>
<div id="main"></div>
<script type="text/javascript" src="echarts.min.js"></script>
<script>
var myChart = echarts.init(document.getElementById('main'));
var city={
'北京':'#c23531',
'上海':'#2f4554',
'广州':'#61a0a8',
'深圳':'#d48265',
'香港':'#749f83'
}
var population=[
{source: "广州", target: "北京", value: 4567},
{source: "广州", target: "上海", value: 2060},
{source: "深圳", target: "北京", value: 1234},
{source: "深圳", target: "上海", value: 124},
{source: "香港", target: "北京", value: 3714},
{source: "香港", target: "上海", value: 3234}];
var data=[];
var citylist=[];
for(var key in city){
citylist.push(
{name: key,itemStyle: {color:city[key]}}
)
}
for(var i=0;i<population.length;i++){
var color=new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
offset: 0,
color: city[population[i].source]
},{
offset: 1,
color: city[population[i].target]
}]
)
data.push(
{source: population[i].source,
target: population[i].target,
value: population[i].value,
lineStyle: {
color:color
}
}
)
}
option = {
title: {
text: '桑基图之城市移民人口统计',
subtext: 'By 佯佯DESIGNER',
top: 'top',
left: '35%'
},
tooltip: {
trigger: 'item',
triggerOn: 'mousemove'
},
series: [
{
type: 'sankey',
data: citylist,
links: data,
focusNodeAdjacency: 'allEdges',
itemStyle: {
borderWidth: 1,
color:'#1b6199',
borderColor: '#fff'
},
lineStyle: {
curveness: 0.5,
opacity:0.5
}
}
]
}
myChart.setOption(option);
</script>
</body>
</html>