问题描述
我在 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_annot
和 hover
函数以查看图形的边缘而不是节点。因为 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()