根据不完整统计,90%想用sankey图的朋友都是因为被它炫酷的外表所吸引,举个例子:
关于sankey图的定义是这样描述的:
下面我们来简单实现一个Sankey图
第一步,我们先收集数据。
这里我在2020意大利新冠肺炎案例统计收集了意大利的患者年龄分布。
我们用pandas库来绘制统计表。当然也可以用excel保存为xlsx文件。
db1 = pd.DataFrame({
'country':['Italy','Italy','Italy','Italy'],
'ages':['18岁以下','19-50岁','50-70岁','70岁以上'],
'confirm':['1677','31394','43617','43139'],
'Deceased':['167','408','4492','34813'],
'Active/Recovered': ['1510','30986','39125','8326']
})
print(db1)
那么打印下统计表得到:
country ages confirm Deceased Active/Recovered
0 Italy 18岁以下 1677 167 1510
1 Italy 19-50岁 31394 408 30986
2 Italy 50-70岁 43617 4492 39125
3 Italy 70岁以上 43139 34813 8326
如果是要读入excel保存的表格那么只要简单的一行命令:
db1 = pd.read_excel('statistik.xlsx)
第二步,我们开始处理数据
画图按照Sankey图的规则,需要定义节点,边,流量。
可以理解为两个数据结构:nodes和links。
在这个案例,所有节点就是:Italy,18岁以下,19-50岁,50-70岁,50-70岁,confirm,Deceased,Active/Recovered
我们用一个字典嵌套的链表来储存:
nodes=[]
for i in range(2):
values = db1.iloc[:,i].unique()
for value in values:
dic={}
dic['name'] = value
nodes.append(dic)
nodes.append({'name':'Deceased'})
nodes.append({'name':'Active/Recovered'})
[{'name': 'Italy'}, {'name': '18岁以下'}, {'name': '19-50岁'},
{'name': '50-70岁'}, {'name': '70岁以上'}, {'name': 'Deceased'},
{'name': 'Active/Recovered'}]
然后定义边和流量,数据从哪里流向哪里,流量为多少,按照source-target-value的格式保存。我们用循环加字典可以轻松搞定
links = []
for i in db1.values:
dic={}
dic['source']=i[0]
dic['target']=i[1]
dic['value']=i[2]
links.append({'source':i[0],'target':i[1],'value':i[2]})
links.append({'source':i[1],'target':db1.keys()[3],'value':i[3]})
links.append({'source':i[1],'target':db1.keys()[4],'value':i[4]})
print(links)
[{'source': 'Italy', 'target': '18岁以下', 'value': '1677'},
{'source': '18岁以下', 'target': 'Deceased', 'value': '167'},
{'source': '18岁以下', 'target': 'Active/Recovered', 'value': '1510'},
{'source': 'Italy', 'target': '19-50岁', 'value': '31394'},
{'source': '19-50岁', 'target': 'Deceased', 'value': '408'},
{'source': '19-50岁', 'target': 'Active/Recovered', 'value': '30986'},
{'source': 'Italy', 'target': '50-70岁', 'value': '43617'},
{'source': '50-70岁', 'target': 'Deceased', 'value': '4492'},
{'source': '50-70岁', 'target': 'Active/Recovered', 'value': '39125'},
{'source': 'Italy', 'target': '70岁以上', 'value': '43139'},
{'source': '70岁以上', 'target': 'Deceased', 'value': '34813'},
{'source': '70岁以上', 'target': 'Active/Recovered', 'value': '8326'}]
nodes和links定义好了之后,就已经完成了80%
第三步,绘图
我们可以使用pyecharts的库来实现,这一段代码几乎是固定的格式
from pyecharts.charts import Sankey
from pyecharts import options as opts
pic = (
Sankey().add('',
nodes,
links,
linestyle_opt=opts.LineStyleOpts(opacity = 0.3, curve = 0.5, color = 'source'),
label_opts=opts.LabelOpts(position = 'top'),
node_gap = 30,
)
.set_global_opts(title_opts=opts.TitleOpts(title = '意大利新冠肺炎病患年龄分布'))
)
pic.render('test.html')
好了,到这来大功告成,运行python文件,最后会生成一个test.html。
用浏览器打开就可以欣赏做出来的的sankey图:
全世界一定会慢慢的战胜疫情,逝者安息。珍惜当下过好自己的每一天。