最近在写网络方面的东西,在测试阶段需要有办法将内存中的图结构数据绘制出来以直观的判断算法执行结果的对错
c++在做可视化这一块真的弟弟,然后找到了python中的networkx + matplotlib两个神器可以方便的实现我的需求
库的安装方法就略去不说了(内网离线环境装这个还是挺麻烦的,matplotlib有巨多依赖库要一个个手动下载安装)
主要讲一下用networkx构图时几个需要特殊处理的地方
我的需求是这样的:
在一张有向图中有每条边有一个版本号,有些边虽然存在但实际上表示断开的连接,需要与正常的连接区分开
每条边由4个数字描述:
x y version iscon
对应到图上就是:
1.每个节点要有节点编号
2.边是有向边,并且每条边有一个表示版本号的数字
3.边需要着色以区分是正常连接还是断开的连接
网络图.png对应的处理方法
首先导入库
import networkx as nx
import matplotlib.pyplot as plt
1.节点编号用draw()的时候自带
2.有向边通过设置图为有向图解决
G = nx.DiGraph()
3.边的版本号用过设置边的label解决
label = {} #一个字典,key是边(例如('x','y')),val是对应的值
nx.draw_networkx_edge_labels(G, pos, edge_labels = labels, font_size = 10)
4.给边着色
colors = [] #一个数组,从下标0开始按顺序表示图内的每条边的颜色
nx.draw_networkx_edges(G, pos, edge_color = colors)
注意networkx中边的顺序并不是按调用G.add_edge()的先后循序来的,要colors数组与边的顺序对应,需要通过G.edges()得到networkx存的所有边,遍历一遍然后对应起来
5.固定节点的坐标
nx.draw(G)会随机绘图,这样画出来的图会很丑。。
可以加一个pos参数来描述图的布局让图看起来正常一点
networkx中有几种布局:
circular_layout:节点在一个圆环上均匀分布
random_layout:节点随机分布
shell_layout:节点在同心圆上分布
spring_layout: 用Fruchterman-Reingold算法排列节点
spectral_layout:根据图的拉普拉斯特征向量排列节点
比如pos = nx.spring_layout(G)
但是用了布局依然有一个问题,哪怕图结构不变,每次运行时画出来的图也不是一样的(带有一定随机性)
这就让对比测试变的比较麻烦
后来找到了一个方法:可以事先将节点的坐标全部写死,这样每次画出来的图位置就一样了
fix_pos = {'1':[3,4],'2':[2,3],'3':[3.5,3]}
nx.draw(G,fix_pos)
注意fix_pos必须要包含所有图中的节点
完整代码如下(注意是python2)
import networkx as nx
import matplotlib.pyplot as plt
G = nx.DiGraph() #设置为有向图
labels = {} #存放每条边的标签
colormap = {} #存放边的颜色的映射关系
colors = [] #根据networkx存储边的顺序填写颜色数组的值
f = open("in.txt","r")
line = f.readline() #按行读取文件,每一行表示一条边的信息
while line:
nums = line.split(' ')
x = nums[0]
y = nums[1]
lb = nums[2]
d = int(nums[3])
G.add_edge(x,y) #新增一条有向边
labels[(x,y)] = lb
if d == 1:
colormap[(x,y)] = 'blue' #正常连接是蓝色
else:
colormap[(x,y)] = 'red' #异常连接是红色
line = f.readline() #继续读下一条边
f.close()
for v in G.edges():
colors.append(colormap[v]) #按network存储边的顺序给colors数组赋值
fix_pos = {'1':[3,4],'2':[2,3],'3':[3.5,3]}
nx.draw(G,fix_pos)
nx.draw_networkx_edges(G, fix_pos, edge_color = colors)
nx.draw_networkx_edge_labels(G, fix_pos, edge_labels = labels, font_size = 10)
plt.show()
网友评论