使用Python制作花式动态节点网络可视化
我有一个网络,它会进行循环,每次循环时,网络中的边会更新它们的权重。有些边的权重会增加,这样就加强了两个节点之间的联系;而有些边的权重会减少,这样就削弱了这些节点之间的关系。
这些权重是作为图的一个属性来收集的,格式是 G[node1][node2]["weight"]
。我想知道有没有办法把这个网络可视化,让每次循环中,那些权重增加的边对应的节点靠得更近(它们彼此移动得更近),而那些权重变弱的边对应的节点则分开,距离变远。
虽然我希望边能够靠近或远离,但节点的位置应该保持不变:除非边的权重发生变化,节点才会保持在最初设定的位置。只有当它们的边权重变化时,节点才会移动(向它们的关联节点靠近或远离)。
也许最后可以把这些变化收集成一个 gif
动画,来看看这些移动效果。
任何帮助都将非常感谢。谢谢!
1 个回答
1
如果我理解得没错,一个可能的选择是使用 matplotlib 的 动画 功能:
init_pos = nx.spring_layout(G, seed=7)
def movedge(pos, p1, p2, distance):
nodes = p1, p2
p1, p2 = itemgetter(p1, p2)(pos)
curr_distance = np.linalg.norm(p2 - p1)
scale = distance / curr_distance
new_p1 = p1 + (p2 - p1) * scale
new_p2 = p2 + (p1 - p2) * scale
return {**pos, **dict(zip(nodes, (new_p1, new_p2)))}
# `drawg()` goes here.. (see full code)
fig, ax = plt.subplots(figsize=(10, 6))
N = 20
frames = {}
H = G.copy(); new_pos = init_pos.copy()
for move, rng in zip(moves, np.arange(1, len(moves) * N + 1).reshape(-1, N)):
p1, p2 = move["p1"], move["p2"]; init = H[p1][p2]["weight"]
for i, j in zip(rng, np.linspace(init, move["distance"], N).round(2)):
H[p1][p2]["weight"] = j; move["distance"] = j-init
new_pos.update(movedge(**move, pos=new_pos))
frames[i] = {"g": H.copy(), "curr_pos": movedge(**move, pos=new_pos)}
def animate(i):
ax.clear()
drawg(**frames[i + 1], ax=ax)
在笔记本中可视化它:
%matplotlib notebook
ani = FuncAnimation(
fig, animate, frames=N * len(moves), interval=150, repeat=True
)
保存为一个 (.gif
) 文件:
writer = PillowWriter(
fps=15, metadata=dict(artist="Me"), bitrate=1800,
)
ani.save("output.gif", writer=writer)
使用的图形 (G
) : 来自 networkx/docs 的示例。
使用的移动:
moves = ( # some random moves
{"p1": "a", "p2": "b", "distance": 0.57},
{"p1": "c", "p2": "d", "distance": 0.12},
{"p1": "c", "p2": "f", "distance": 0.88},
{"p1": "c", "p2": "d", "distance": 0.07},
{"p1": "c", "p2": "e", "distance": 0.68},
{"p1": "a", "p2": "b", "distance": 0.59},
)