Networkx 和 Matplotlib:如何访问节点属性并将它们显示为注释
Networkx and Matplotlib: how to access node attributes and show them as annotation
我正在尝试让悬停功能适用于此 networkx matplotlib 图,但我遇到了一个关键错误问题。我想创建一个键名作为字符串的节点,并将其作为标签。但是,它看起来像在 xy=pos[node]
部分被称为中断的悬停功能。这是其中一些内容的一些输出:
- 此输出中的 obj 是我打印节点键。
- ind是我悬停在节点上。
- node 是我试图找出节点键和 hover 正在寻找的内容之间的 link。
pos: {'A': array([-0.88308537, -0.21952651]), 'B': array([ 0.70105714, -0.78047349]), 'C': array([0.18202824, 1. ])}
obj: A
obj: B
obj: C
ind: {'ind': array([], dtype=int32)}
ind: {'ind': array([2], dtype=int32)}
node: 2
ind: {'ind': array([2], dtype=int32)}
node: 2
ind: {'ind': array([2], dtype=int32)}
代码如下:
import networkx as nx
import matplotlib.pyplot as plt
from networkx.readwrite import edgelist
import numpy as np
G = nx.DiGraph()
G.add_node("A", attr1=20)
G.add_node("B", attr1=25)
G.add_node("C", attr1=30)
fig, ax = plt.subplots()
pos = nx.spring_layout(G)
print('pos:', pos)
nodes = nx.draw_networkx_nodes(G, pos, node_size=500)
for obj in G.nodes:
print('obj:', obj)
nx.draw_networkx_edges(G, pos, edgelist=G.edges(), edge_color='black')
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]
print('node:',node)
xy = pos[node]
print('here:', xy)
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)
print('ind:',ind)
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()
错误:
xy = pos[node]
KeyError: 2
它似乎在尝试查找带有数字而不是字母的键。这就是我遇到关键错误的原因。但我不确定为什么我不能让它接受字符串。
node_index = ind["ind"][0]
是节点列表中的整数索引。 Networkx 使用节点名称将其节点存储在字典中。 G.nodes[2]
给出错误,因为 G.nodes
是一个由节点名称索引的字典。
您可以将 G.nodes
转换为列表,并在 node_index
处找到名称:node_name = list(G.nodes)[node_index]
。使用该名称,您可以找到属性:node_attr = G.nodes[node_name]
.
要使用悬停注释,我建议使用 mplcursors 库,它隐藏了许多内部簿记。
这是更新后的示例:
import matplotlib.pyplot as plt
import networkx as nx
import mplcursors
G = nx.DiGraph()
G.add_node("A", attr1=20)
G.add_node("B", attr1=25)
G.add_node("C", attr1=30)
fig, ax = plt.subplots()
pos = nx.spring_layout(G)
nodes = nx.draw_networkx_nodes(G, pos, node_size=500, node_color='dodgerblue')
nx.draw_networkx_labels(G, pos, font_color='yellow')
nx.draw_networkx_edges(G, pos, edgelist=G.edges(), edge_color='black')
def update_annot(sel):
node_index = sel.target.index
node_name = list(G.nodes)[node_index]
node_attr = G.nodes[node_name]
text = node_name + ' ' + '\n'.join(f'{k}: {v}' for k, v in node_attr.items())
sel.annotation.set_text(text)
cursor = mplcursors.cursor(nodes, hover=True)
cursor.connect('add', update_annot)
plt.show()
我正在尝试让悬停功能适用于此 networkx matplotlib 图,但我遇到了一个关键错误问题。我想创建一个键名作为字符串的节点,并将其作为标签。但是,它看起来像在 xy=pos[node]
部分被称为中断的悬停功能。这是其中一些内容的一些输出:
- 此输出中的 obj 是我打印节点键。
- ind是我悬停在节点上。
- node 是我试图找出节点键和 hover 正在寻找的内容之间的 link。
pos: {'A': array([-0.88308537, -0.21952651]), 'B': array([ 0.70105714, -0.78047349]), 'C': array([0.18202824, 1. ])}
obj: A
obj: B
obj: C
ind: {'ind': array([], dtype=int32)}
ind: {'ind': array([2], dtype=int32)}
node: 2
ind: {'ind': array([2], dtype=int32)}
node: 2
ind: {'ind': array([2], dtype=int32)}
代码如下:
import networkx as nx
import matplotlib.pyplot as plt
from networkx.readwrite import edgelist
import numpy as np
G = nx.DiGraph()
G.add_node("A", attr1=20)
G.add_node("B", attr1=25)
G.add_node("C", attr1=30)
fig, ax = plt.subplots()
pos = nx.spring_layout(G)
print('pos:', pos)
nodes = nx.draw_networkx_nodes(G, pos, node_size=500)
for obj in G.nodes:
print('obj:', obj)
nx.draw_networkx_edges(G, pos, edgelist=G.edges(), edge_color='black')
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]
print('node:',node)
xy = pos[node]
print('here:', xy)
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)
print('ind:',ind)
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()
错误:
xy = pos[node]
KeyError: 2
它似乎在尝试查找带有数字而不是字母的键。这就是我遇到关键错误的原因。但我不确定为什么我不能让它接受字符串。
node_index = ind["ind"][0]
是节点列表中的整数索引。 Networkx 使用节点名称将其节点存储在字典中。 G.nodes[2]
给出错误,因为 G.nodes
是一个由节点名称索引的字典。
您可以将 G.nodes
转换为列表,并在 node_index
处找到名称:node_name = list(G.nodes)[node_index]
。使用该名称,您可以找到属性:node_attr = G.nodes[node_name]
.
要使用悬停注释,我建议使用 mplcursors 库,它隐藏了许多内部簿记。
这是更新后的示例:
import matplotlib.pyplot as plt
import networkx as nx
import mplcursors
G = nx.DiGraph()
G.add_node("A", attr1=20)
G.add_node("B", attr1=25)
G.add_node("C", attr1=30)
fig, ax = plt.subplots()
pos = nx.spring_layout(G)
nodes = nx.draw_networkx_nodes(G, pos, node_size=500, node_color='dodgerblue')
nx.draw_networkx_labels(G, pos, font_color='yellow')
nx.draw_networkx_edges(G, pos, edgelist=G.edges(), edge_color='black')
def update_annot(sel):
node_index = sel.target.index
node_name = list(G.nodes)[node_index]
node_attr = G.nodes[node_name]
text = node_name + ' ' + '\n'.join(f'{k}: {v}' for k, v in node_attr.items())
sel.annotation.set_text(text)
cursor = mplcursors.cursor(nodes, hover=True)
cursor.connect('add', update_annot)
plt.show()