数据可视化-等高线-pandas透视图-seaborn热力图-桑基图(Sankey)

matplotlib绘制等高线

ref: https://matplotlib.org/api/_as_gen/matplotlib.pyplot.contour.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
import matplotlib.pyplot as plt


x = np.arange(0, 10.0, 0.1)
y = np.arange(0, 10.0, 0.1)
X, Y = np.meshgrid(x, y) # 生成x-y网格图
Z = X**1.5 + Y**1.5

plt.figure()
CS = plt.contour(X, Y, Z, levels=6) # 设置距离
plt.clabel(CS, inline=1, fontsize=10, fmt='%d ℃') # 设置标签
plt.savefig('Temp.png', dpi=300, bbox_inches='tight')
plt.show()

pandas透视图

1. 创建需要展示的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import itertools

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

# === define paras ==================
para_names = ['layer_n', 'activition', 'seed']

layer_n = [1, 2, 3, 4, 5, 6]
activition = ['tanh', 'sigmod', 'relu']
seed = [11, 17, 19]

# 创建 dataframe
df = pd.DataFrame([], columns=para_names)
for values in itertools.product(layer_n, activition, seed):
newline = pd.DataFrame(list(values), index=para_names)
df = df.append(newline.T, ignore_index=True)

# 伪造一些训练结果,方便展示
# activ_2_num = pd.factorize(df['activition'])[0].astype('int') # 激活函数是字符类型,将其映射成整数形
activ_dict = {'tanh': 2, 'sigmod': 4, 'relu': 6} # 也可以直接定义字典,然后replace
df['results'] = df['layer_n'] + df['activition'].replace(activ_dict) + df['seed'] * 0.1 + np.random.random((54,))
df['results'] = df['results'].astype('float') # 转换成浮点类型
print(df.head())

输出:

  layer_n activition seed   results
0       1       tanh   11  4.261361
1       1       tanh   17  4.822595
2       1       tanh   19  4.929088
3       1     sigmod   11  6.698047
4       1     sigmod   17  7.020531

2. 绘制带误差的折线图展示训练结果

1
2
3
4
5
6
7
# 绘制带误差的折线图,横轴为网络层数,纵轴为训练结果,
# 激活函数采用不同颜色的线型,误差来自于没有指定的列:不同的随机种子seed
plt.figure(figsize=(8, 6))
sns.lineplot(x='layer_n', y='results', hue='activition', style='activition',
markers=True, data=df)
plt.grid(linestyle=':')
plt.show()

3. 使用pandas透视图、seaborn热力图来展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 创建透视图,
# 对于没有指定的列(seed),按最大值进行统计
dt = pd.pivot_table(df, index=['layer_n'], columns=['activition'], values=['results'], aggfunc=[max])
print(dt)
print(dt.columns)

# 找到最大值、最大值所对应的索引
max_value, max_idx = dt.stack().max(), dt.stack().idxmax()
print(f' - the max value is {max_value};\n - the index is {max_idx}...')

# 透视图变成了多重索引(MultiIndex),重新调整一下
new_col = dt.columns.levels[2]
dt.columns = new_col
# dt.index = list(dt.index)
print(dt)

dt.sort_index(axis=0, ascending=False, inplace=True) # 必要时将索引重新排序
dt.sort_index(axis=1, ascending=False, inplace=True) # 必要时将索引重新排序

# 绘制热力图,横轴为网络层数,纵轴为激活函数,
# 栅格的颜色代表训练结果,颜色越深结果越好
plt.figure(figsize=(8, 6))
g = sns.heatmap(dt, vmin=0.0, annot=True, fmt='.2g', cmap='Blues', cbar=True)
plt.show()

ref:


桑基图(Sankey)

1. 桑基图(Sankey)介绍

sankey图可用于数据从一系列节点到另一系列节点流入流出的可视化。

主要有两个基本概念:

  • 节点 (nodes)
  • 连接 (links): 源节点至目标节点之间的关系,每个连接包括三个元素:
    • source: 源节点
    • target: 目标节点
    • value: 数据

ref: https://developers.google.com/chart/interactive/docs/gallery/sankey

2. 绘制桑基图(使用pyecharts)

常用的绘图库 matplotlib, seaborn 好像不支持桑基图, 这里使用了 pyecharts 。

这里 https://gallery.pyecharts.org/#/Sankey/sankey_base 有几个例子。

简单用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import pandas as pd

from pyecharts import options as opts
from pyecharts.charts import Sankey

# 数据
data = [[ 'Brazil', 'Portugal', 5 ],
[ 'Brazil', 'France', 1 ],
[ 'Brazil', 'Spain', 1 ],
[ 'Brazil', 'England', 1 ],
[ 'Canada', 'Portugal', 1 ],
[ 'Canada', 'France', 5 ],
[ 'Canada', 'England', 1 ],
[ 'Mexico', 'Portugal', 1 ],
[ 'Mexico', 'France', 1 ],
[ 'Mexico', 'Spain', 5 ],
[ 'Mexico', 'England', 1 ],
[ 'USA', 'Portugal', 1 ],
[ 'USA', 'France', 1 ],
[ 'USA', 'Spain', 1 ],
[ 'USA', 'England', 5 ],
[ 'Portugal', 'Angola', 2 ],
[ 'Portugal', 'Senegal', 1 ],
[ 'Portugal', 'Morocco', 1 ],
[ 'Portugal', 'South Africa', 3 ],
[ 'France', 'Angola', 1 ],
[ 'France', 'Senegal', 3 ],
[ 'France', 'Mali', 3 ],
[ 'France', 'Morocco', 3 ],
[ 'France', 'South Africa', 1 ],
[ 'Spain', 'Senegal', 1 ],
[ 'Spain', 'Morocco', 3 ],
[ 'Spain', 'South Africa', 1 ],
[ 'England', 'Angola', 1 ],
[ 'England', 'Senegal', 1 ],
[ 'England', 'Morocco', 2 ],
[ 'England', 'South Africa', 7 ],
[ 'South Africa', 'China', 5 ],
[ 'South Africa', 'India', 1 ],
[ 'South Africa', 'Japan', 3 ],
[ 'Angola', 'China', 5 ],
[ 'Angola', 'India', 1 ],
[ 'Angola', 'Japan', 3 ],
[ 'Senegal', 'China', 5 ],
[ 'Senegal', 'India', 1 ],
[ 'Senegal', 'Japan', 3 ],
[ 'Mali', 'China', 5 ],
[ 'Mali', 'India', 1 ],
[ 'Mali', 'Japan', 3 ],
[ 'Morocco', 'China', 5 ],
[ 'Morocco', 'India', 1 ],
[ 'Morocco', 'Japan', 3 ]]

df = pd.DataFrame(data, columns=['source', 'target', 'value'])
print('- data shape: ', df.shape, '\n')

# 生成节点, 先合并源节点和目标节点,然后去除重复的节点,最后输出成 dict 形式
nn = pd.concat([df['source'], df['target']])
nn = nn.drop_duplicates()
nodes = pd.DataFrame(nn, columns=['name']).to_dict(orient='records')
print('- nodes:\n', nodes, '\n')

# 生成连接, dict 形式
links = df.to_dict(orient='records')
print('- links:\n', links, '\n')

# 绘制桑基图
sk =(
Sankey(init_opts=opts.InitOpts(width="800px", height="600px")) # 页面大小
.add(
series_name="legend", # legend
nodes=nodes,
links=links,
# opacity 透明度; curve 弯曲程度; color 色系
linestyle_opt=opts.LineStyleOpts(opacity=0.2, curve=0.5, color="source"),
label_opts=opts.LabelOpts(position="right"), # 节点名称
)
.set_global_opts(title_opts=opts.TitleOpts(title="sankey")) # 标题
.render("sankey.html") # 保存成 html 文件
)

代码说明:

  • pyecharts的桑基图对于原始数据的格式比较啰嗦,这里用 pandas 处理了一下,还可以修改一下去读取 csv 文件。
  • pyecharts直接保存图片也比较麻烦,需要用 selenium 之类的工具,配置一大堆;还不如直接在浏览器截图。

使用 D3 绘制

D3 绘制桑基图貌似更简便一点,可惜不能用 python。

https://github.com/d3/d3-sankey

这里还有个在线可实时编辑版。

https://observablehq.com/@mbostock/flow-o-matic

厉害了!