参考资料:基于networkx实现图可视化 - 知乎 (zhihu.com)
同构图可以直接调用networkx的函数实现可视化,网络上的教程有很多,但是networkx不能直接实现对异构图的可视化,基于上述参考资料,这里简要介绍一下如何利用networkx绘制异构图。
由于networkx中没有同构图与异构图的定义,为了绘制异构图,我们可将不同类型的节点归并在一起创建DiGraph,渲染时按类型分组,然后每组单独配置渲染参数即可。
本次实验选择的异构图如下
graph2 = dgl.heterograph(
{('drug', 'interacts1', 'drug'): (torch.tensor([0, 1]), torch.tensor([1, 2])),
('drug', 'interacts2', 'gene'): (torch.tensor([0, 1]), torch.tensor([2, 3])),
('drug', 'treats', 'disease'): (torch.tensor([1]), torch.tensor([2]))})
print("medicine:",graph2)
输入的结果为:
medicine: Graph(num_nodes={'disease': 3, 'drug': 3, 'gene': 4},
num_edges={('drug', 'interacts1', 'drug'): 2, ('drug', 'interacts2', 'gene'): 2, ('drug', 'treats', 'disease'): 1},
metagraph=[('drug', 'drug', 'interacts1'), ('drug', 'gene', 'interacts2'), ('drug', 'disease', 'treats')])
可视化实现过程
"""
生成pos,用来配置layout,其格式为{0: [-0.95, -0.8],1: [-0.95, -0.48]}
"""
def gen_pos(node_type_num, node_num_array):
step = round(1.6 / (node_type_num - 1), 2)
xs = []
for i in range(node_type_num):
xs.append(round(-0.95 + i * step, 2))
ys = []
for node_num in node_num_array:
cstep = round(1.6 / (node_num - 1), 2)
result = []
for j in range(node_num):
result.append(round(-0.8 + j * cstep, 2))
ys.append(result)
# construct pos
pos = []
for aa, bb in zip(xs, ys):
for b in bb:
pos.append([aa, b])
final_pos = {}
for i, e in enumerate(pos):
final_pos[i] = e
return final_pos
pos = gen_pos(3, [3, 4, 3])
## 创建图对象,并添加节点,添加边
GG2 = nx.DiGraph()
# add nodes
GG2.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# add edges
res1=[(0, 1),(1,2)]
res2 = [(0,4),(2,6)]
res3 = [(1,9)]
GG2.add_edges_from(res1)
GG2.add_edges_from(res2)
GG2.add_edges_from(res3)
# nodes, 把节点分为三个组(相当于三种类型),每组独立编号与染色
plt.figure(figsize=(7, 5))
nx.draw_networkx_nodes(GG2, pos, nodelist=[0, 1, 2], node_color="red", label="drug")
nx.draw_networkx_nodes(GG2, pos, nodelist=[3,4,5,6], node_color="green", label="gene")
nx.draw_networkx_nodes(GG2, pos, nodelist=[7,8,9], node_color="blue", label="disease")
# edges,把边分为两个组(相当于两种边类型),每组独立设置样式
nx.draw_networkx_edges(GG2, pos, edgelist=res1, width=1,label="interacts1")
nx.draw_networkx_edges(GG2, pos, edgelist=res2, width=1,style="-.",label="interacts2")
nx.draw_networkx_edges(GG2, pos, edgelist=res3, width=1, style="dashed",label="treats")
# node labels,每类节点从0开始编号
labels = {0: "0", 1: "1", 2: "2", 3: "0", 4: "1", 5: "2",
6: "3", 7: "0", 8: "1", 9: "2",}
nx.draw_networkx_labels(GG2, pos, labels, font_size=12, font_color="whitesmoke")
# legend1:渲染节点类型,labelspacing设置节点间距离(垂直方向)、borderpad设置节点与边界间距离(垂直方向)
l1 = plt.legend(bbox_to_anchor=(1, 0.85), labelspacing=1, borderpad=0.7)
plt.gca().add_artist(l1) # 这条语句可使plt添加多个legend
# legend2:渲染边类型
from matplotlib.lines import Line2D
handles = [Line2D([], [], color="black", label="interacts1", linewidth=1),
Line2D([], [], color="black", label="interacts2", linewidth=1, ls="-."),
Line2D([], [], color="black", label="treats", linewidth=1, ls="dashed")]
plt.legend(handles=handles, bbox_to_anchor=(1, 0.6))
# dpi设置清晰度、bbox_inches='tight'保证图片能被完整保存
plt.savefig("e:\\hetero", dpi=1000, bbox_inches='tight')
最终生成的图为