如何在 Networkx 和 matplotlib 中标记多重图的边缘?

问题描述 投票:0回答:3

我有一个无向多重图,我想用标签绘制边缘,有什么建议吗?我遵循建议,但仍然没有边缘标签。 通过atomh33ls使用networkx

在两个节点之间绘制多条边
G=nx.MultiGraph ()
G.add_edge(1,2,weight=7)
G.add_edge(1,2,weight=2)
G.add_edge(1,2,weight=3)
G.add_edge(3,1,weight=2)
G.add_edge(3,2,weight=3)

node_label = nx.get_node_attributes(G,'id')
pos = nx.spring_layout(G)
nx.draw_networkx_nodes(G, pos, label=node_label)
nx.draw_networkx_labels(G, pos, label=node_label)
edge_labels=nx.get_edge_attributes(G,'weight')
ax = plt.gca()
for e in G.edges:
    ax.annotate("",
                xy=pos[e[0]], xycoords='data',
                xytext=pos[e[1]], textcoords='data',
                arrowprops=dict(arrowstyle="-", color="0.5",
                                shrinkA=5, shrinkB=5,
                                patchA=None, patchB=None,
                                connectionstyle="arc3,rad=rrr".replace('rrr',str(0.3*e[2])
                                ),
                                ),
                )
#nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels)
plt.axis('off')
plt.show()

无向多图示例

python graph label networkx
3个回答
4
投票

nx.get_edge_attributes
返回的字典具有结构
(source, dest, enum):attr
,其中第三个字段仅枚举每条边的出现次数。第三个字段是必需的,因为键在字典中必须是唯一的。然而,这意味着它不能在
nx.draw_networkx_edge_labels
中使用,因为它需要一个
(source, dest):attr
结构化字典。

nx.get_edge_attributes(G,'weight')
# {(1, 2, 0): 7, (1, 2, 1): 2, (1, 2, 2): 3, (1, 3, 0): 2, (2, 3, 0): 3}

所以这实际上不适用于多图。您可以做的事情,遵循与这里相同的想法,就是使用权重值对边进行

label
,然后使用
dot
将图形导出到
nx.write_dot
,这将使用这些
labels
关于可视化。


4
投票

感谢@yatu。这是迄今为止无向多图标记的优雅解决方案。 请给我更多改进风格的建议!

import networkx as nx
import matplotlib.pyplot as plt
from IPython.display import Image

G=nx.MultiGraph ()
G.add_edge(1,2,weight=1)
G.add_edge(1,2,weight=2)
G.add_edge(1,2,weight=3)
G.add_edge(3,1,weight=4)
G.add_edge(3,2,weight=5)
for edge in G.edges(data=True): edge[2]['label'] = edge[2]['weight']
node_label = nx.get_node_attributes(G,'id')
pos = nx.spring_layout(G)
node_label = nx.get_node_attributes(G,'id')
pos = nx.spring_layout(G)
p=nx.drawing.nx_pydot.to_pydot(G)
p.write_png('multi.png')
Image(filename='multi.png')


0
投票

您可以通过两次调用

ax.annotate(...)
来分割边缘的绘制:一次绘制线条,另一次绘制边缘标签。请参阅下面的代码。

这个解决方案远非完美:我仍然需要弄清楚如何根据索引来替换边缘的标签

e[2]
,但这是朝着正确方向迈出的一步。

此外,自循环边未正确渲染:由于 pos[e[0]] 和 pos[e[1]] 相同,标签将渲染在节点本身上。

无论如何,这是代码,希望其他人可以帮助改进它:

import networkx as nx
import matplotlib.pyplot as plt

G=nx.MultiGraph ()
G.add_edge(1,2,weight=1)
G.add_edge(1,2,weight=2)
G.add_edge(1,2,weight=3)
G.add_edge(3,1,weight=4)
G.add_edge(3,2,weight=5)

nx.draw_networkx_nodes(g, pos=pos, node_size=300, node_color=palette)
nx.draw_networkx_labels(g, pos=pos)

f = 0.3
ax = plt.gca()
for e in g.edges:
    # draw the edge
    init = - f * (len(g[e[0]][e[1]]) - 1) / 2
    ax.annotate(
        "",
        xy=pos[e[0]], xycoords='data',
        xytext=pos[e[1]], textcoords='data',
        arrowprops=dict(
             arrowstyle="-", color="0.0",
             shrinkA=10, shrinkB=10,
             patchA=None, patchB=None,
             connectionstyle="arc3,rad=rrr".replace('rrr',str(init + e[2] * f)),
        ),
    )
    # render the label
    pt = (pos[e[0]] + pos[e[1]]) / 2
    ax.annotate(
        g[e[0]][e[1]][0]["relation"],
        xy=pt, xycoords='data', 
        xytext=pt, textcoords='offset fontsize',
        arrowprops=dict(
            arrowstyle="-", color="1.0",
            shrinkA=10, shrinkB=10,
            patchA=None, patchB=None,
            connectionstyle="arc3,rad=rrr".replace('rrr',str(-0.3 * e[2])),    
        ),
    )
plt.axis('off')
plt.show()
© www.soinside.com 2019 - 2024. All rights reserved.