使用Python制作花式动态节点网络可视化

0 投票
1 回答
52 浏览
提问于 2025-04-14 16:49

我有一个网络,它会进行循环,每次循环时,网络中的边会更新它们的权重。有些边的权重会增加,这样就加强了两个节点之间的联系;而有些边的权重会减少,这样就削弱了这些节点之间的关系。

这些权重是作为图的一个属性来收集的,格式是 G[node1][node2]["weight"]。我想知道有没有办法把这个网络可视化,让每次循环中,那些权重增加的边对应的节点靠得更近(它们彼此移动得更近),而那些权重变弱的边对应的节点则分开,距离变远。

虽然我希望边能够靠近或远离,但节点的位置应该保持不变:除非边的权重发生变化,节点才会保持在最初设定的位置。只有当它们的边权重变化时,节点才会移动(向它们的关联节点靠近或远离)。

也许最后可以把这些变化收集成一个 gif 动画,来看看这些移动效果。

任何帮助都将非常感谢。谢谢!

1 个回答

1

如果我理解得没错,一个可能的选择是使用 动画 功能:

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},
)

完整代码

撰写回答