如何解决绘制networkx.Graph:如何更改节点位置而不是重置每个节点?
我正在一个项目中,需要创建nx.Graph()
的预览,该预览允许更改使用鼠标拖动节点的节点的位置。如果在特定节点上单击鼠标,我的当前代码能够在每次鼠标移动后立即重绘整个图形。但是,这大大增加了等待时间。如何仅更新所需的艺术家,即单击的节点,其标签文本和相邻边缘,而不刷新每个plt.subplots()
的艺术家?我至少可以参考所有需要搬迁的艺术家吗?
我从在networkx
中显示图形的标准方式开始:
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
import scipy.spatial
def refresh(G):
plt.axis((-4,4,-1,3))
nx.draw_networkx_labels(G,pos = nx.get_node_attributes(G,'pos'),bbox = dict(fc="lightgreen",ec="black",boxstyle="square",lw=3))
nx.draw_networkx_edges(G,width=1.0,alpha=0.5)
plt.show()
nodes = np.array(['A','B','C','D','E','F','G'])
edges = np.array([['A','B'],['A','C'],['B','D'],'E'],['C','F'],'G']])
pos = np.array([[0,0],[-2,1],[2,[-3,2],[-1,[1,[3,2]])
G = nx.Graph()
# IG = InteractiveGraph(G) #>>>>> add this line in the next step
G.add_nodes_from(nodes)
G.add_edges_from(edges)
nx.set_node_attributes(G,dict(zip(G.nodes(),pos.astype(float))),'pos')
fig,ax = plt.subplots()
# fig.canvas.mpl_connect('button_press_event',lambda event: IG.on_press(event))
# fig.canvas.mpl_connect('motion_notify_event',lambda event: IG.on_motion(event))
# fig.canvas.mpl_connect('button_release_event',lambda event: IG.on_release(event))
refresh(G) # >>>>> replace it with IG.refresh() in the next step
https://medium.com/@ratheesh.archal/sidebar-menu-in-react-with-material-ui-d99747f90f1f
在下一步中,我更改了上一个脚本的5行(取消注释4行,并替换了1行),并使用了InteractiveGraph
实例使其具有交互性:
class InteractiveGraph:
def __init__(self,G,node_pressed=None,xydata=None):
self.G = G
self.node_pressed = node_pressed
self.xydata = xydata
def refresh(self,show=True):
plt.clf()
nx.draw_networkx_labels(self.G,pos = nx.get_node_attributes(self.G,lw=3))
nx.draw_networkx_edges(self.G,alpha=0.5)
plt.axis('off')
plt.axis((-4,3))
fig.patch.set_facecolor('white')
if show:
plt.show()
def on_press(self,event):
if event.inaxes is not None and len(self.G.nodes()) > 0:
nodelist,coords = zip(*nx.get_node_attributes(self.G,'pos').items())
kdtree = scipy.spatial.KDTree(coords)
self.xydata = np.array([event.xdata,event.ydata])
close_idx = kdtree.query_ball_point(self.xydata,np.sqrt(0.1))
i = close_idx[0]
self.node_pressed = nodelist[i]
def on_motion(self,event):
if event.inaxes is not None and self.node_pressed:
new_xydata = np.array([event.xdata,event.ydata])
self.xydata += new_xydata - self.xydata
#print(d_xy,self.G.nodes[self.node_pressed])
self.G.nodes[self.node_pressed]['pos'] = self.xydata
self.refresh(show=False)
event.canvas.draw()
def on_release(self,event):
self.node_pressed = None
相关来源
解决方法
要扩展我在上面的评论,请在netgraph
中使用以下示例复制您的示例
import numpy as np
import matplotlib.pyplot as plt; plt.ion()
import networkx as nx
import netgraph
nodes = np.array(['A','B','C','D','E','F','G'])
edges = np.array([['A','B'],['A','C'],['B','D'],'E'],['C','F'],'G']])
pos = np.array([[0,0],[-2,1],[2,[-3,2],[-1,[1,[3,2]])
G = nx.Graph()
G.add_nodes_from(nodes)
G.add_edges_from(edges)
I = netgraph.InteractiveGraph(G,node_positions=dict(zip(nodes,pos)),node_labels=dict(zip(nodes,nodes)),node_label_bbox=dict(fc="lightgreen",ec="black",boxstyle="square",lw=3),node_size=12,)
# move stuff with mouse
关于您编写的代码,如果您拥有所有艺术家的句柄,则不需要kd树。通常,matplotlib艺术家具有contains
方法,这样,当您记录按钮按下事件时,您只需检查artist.contains(event)
即可发现按钮按下是否发生在艺术家身上。当然,如果您使用networkx进行绘制,则无法以一种可查询的好形式获得句柄(ax.get_children()
都不是),所以这是不可能的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。