桑基图(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、样式配置

系列列表seriesitemStyle用来设置节点的样式,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要求的数据集,并逐个添加自己的样式。
节点的处理主要是构造节点对象,包括nameitemStyle两个键,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>

---------------其实很简单,其实并不难!------------------