使用 networkx 和 matplotlib (Python) 添加图形边缘的工具提示

问题描述

我在 matplotlib 中绘制了一个网络图,并希望有一个工具提示,当我将鼠标悬停在边缘上时显示信息。

当鼠标悬停在节点 (adding tooltip for nodes in python networkx graph) 上时,有一个生成工具提示解决方案。这可以适用于悬停在边缘上吗?

import matplotlib.pyplot as plt
import networkx as nx

G = nx.path_graph(5)
attrs = {0: {'attr1': 20,'attr2': 'nothing'},1: {'attr2': 3},2: {'attr1': 42},3: {'attr3': 'hello'},4: {'attr1': 54,'attr3': '33'}}
nx.set_node_attributes(G,attrs)

fig,ax = plt.subplots()
pos = nx.spring_layout(G)
nodes = nx.draw_networkx_nodes(G,pos=pos,ax=ax)
nx.draw_networkx_edges(G,ax=ax)

annot = ax.annotate("",xy=(0,0),xytext=(20,20),textcoords="offset points",bBox=dict(Boxstyle="round",fc="w"),arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)

def update_annot(ind):
    node = ind["ind"][0]
    xy = pos[node]
    annot.xy = xy
    node_attr = {'node': node}
    node_attr.update(G.nodes[node])
    text = '\n'.join(f'{k}: {v}' for k,v in node_attr.items())
    annot.set_text(text)

def hover(event):
    vis = annot.get_visible()
    if event.inaxes == ax:
        cont,ind = nodes.contains(event)
        if cont:
            update_annot(ind)
            annot.set_visible(True)
            fig.canvas.draw_idle()
        else:
            if vis:
                annot.set_visible(False)
                fig.canvas.draw_idle()

fig.canvas.mpl_connect("motion_notify_event",hover)

plt.show()

解决方法

是的,这个例子可以很容易地适应边缘而不是节点。

首先,让我们将属性应用于边而不是节点,

import matplotlib.pyplot as plt
import networkx as nx

G = nx.path_graph(5)
attrs = {(0,1): {'attr1': 20,'attr2': 'nothing'},(1,2): {'attr2': 3},(2,3): {'attr1': 42},(3,4): {'attr3': 'hello'},(4,5): {'attr1': 54,'attr3': '33'}}
nx.set_edge_attributes(G,attrs)

现在,我们想在绘制图形时记录边的位置,而不是节点:

fig,ax = plt.subplots()
pos = nx.spring_layout(G)
nx.draw_networkx_nodes(G,pos=pos,ax=ax)
edges = nx.draw_networkx_edges(G,ax=ax)

annot = ax.annotate("",xy=(0,0),xytext=(20,20),textcoords="offset points",bbox=dict(boxstyle="round",fc="w"),arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)

现在,我们只需要更改 update_annothover 函数以查看图形的边缘而不是节点。因为 pos 只保存节点的位置,所以我们求边两端节点位置的平均值,从而找到边的中点。

def update_annot(ind):
    edge = list(G.edges)[ind["ind"][0]]
    xy = (pos[edge[0]] + pos[edge[1]])/2
    annot.xy = xy
    node_attr = {'edge': edge}
    node_attr.update(G.edges[edge])
    text = '\n'.join(f'{k}: {v}' for k,v in node_attr.items())
    annot.set_text(text)

def hover(event):
    vis = annot.get_visible()
    if event.inaxes == ax:
        cont,ind = edges.contains(event)
        if cont:
            update_annot(ind)
            annot.set_visible(True)
            fig.canvas.draw_idle()
        else:
            if vis:
                annot.set_visible(False)
                fig.canvas.draw_idle()

fig.canvas.mpl_connect("motion_notify_event",hover)

plt.show()

结果

enter image description here