从 grid_2d_graph 一致删除节点

Consistent removal of nodes from grid_2d_graph

假设我有一个由 NxN=100x100 个节点组成的常规二维网格图 G。我通过调用创建这样的网络:

N=100
G=nx.grid_2d_graph(N,N)
pos = dict( (n, n) for n in G.nodes() ) #Dictionary of all positions
labels = dict( ((i, j), i + (N-1-j) * N ) for i, j in G.nodes() )
nx.draw_networkx(G, pos=pos, labels=labels,with_labels=False, node_size=10)

我得到的结果类似于这张图片左侧显示的结果:

现在,假设我的网络经历了一个破坏性事件,导致许多节点发生故障(图片右侧)。我的图 G 不再由相同数量的节点组成:图 G2 现在拥有 K<NxN 个节点。鉴于这种情况,我希望能够通过调用来绘制 G2

G2=G.remove_nodes_from(failed_nodes_dict) #Failed_node_dict holds the disrupted nodes
nx.draw_networkx(G2, pos=pos, labels=labels,with_labels=False, node_size=10)

我的问题。 我该怎么做才能确保位置字典 pos 不被更改? 这意味着:如果节点0(0,0)位置(左上角)在1)的情况下它不失败,则它必须出现在情况 2) 中的相同位置。这样,两个网络就可以比较了,因为第二个网络只是第一个网络的 "transformation"。 谢谢!

您可以通过将 (i,j) 中的节点重新标记为您在标签字典中的数字上看到的数字来实现。然后删除失败的节点。最后,通过简单地反转 labels 字典,调整 pos 字典以将位置映射到节点的新标签。这是我在您的代码后添加的内容:

nx.relabel_nodes(G,labels,False)
G.remove_nodes_from([0,4,12,18])            
pos = {y:x for x,y in labels.iteritems()}
nx.draw_networkx(G, pos=pos, with_labels=True, node_size = 300)

对于 N = 5 和故障节点 [0,4,12,18],这是我在删除故障节点之前(左)和之后(右)得到的结果。

我很难理解您问这个问题的原因 - 代码基本上应该完全按照您的要求工作。但是,您有一个错误,这可能是导致您提出这个问题的原因。

G2= G.remove_nodes_from(failed_nodes_dict) #Failed_node_dict holds the disrupted nodes

这将使 G2 变为 NoneG.remove_nodes_from(L)G 中删除 L 中的节点。它不会创建看起来像 G 但没有这些节点的新图。所以它没有 return 任何东西。因此 G2 没有被赋予任何价值。图 G 已删除这些节点。

所以以下应该有效:

N=100
G=nx.grid_2d_graph(N,N)
pos = dict( (n, n) for n in G.nodes() ) #Dictionary of all positions
labels = dict( ((i, j), i + (N-1-j) * N ) for i, j in G.nodes() )
nx.draw_networkx(G, pos=pos, labels=labels,with_labels=False, node_size=10)

#find failed nodes here

G.remove_nodes_from(failed_nodes_dict) #Failed_node_dict holds the disrupted nodes
nx.draw_networkx(G, pos=pos, labels=labels,with_labels=False, node_size=10)

pos 在此代码中从未更改。

我想扩展一下@AbdallahSobehy 的回答。但是,为了更普遍地重用 networkx 图,我建议将位置和标签信息存储在图结构中,而不是在单独的容器中。

从图表的简化版本开始(N = 5):

N = 5
G = nx.grid_2d_graph(N,N)
pos = dict((n, n) for n in G.nodes())
labels = dict(((i, j), i + (N-1-j) * N) for i, j in G.nodes())

可以将 poslabel 字典存储为图形属性:

nx.set_node_attributes(G, 'pos', pos)
nx.set_node_attributes(G, 'labels', labels)

并将它们用于绘图:

nx.draw_networkx(G, pos=nx.get_node_attributes(G, 'pos'),
                 labels=nx.get_node_attributes(G, 'labels'),
                 with_labels=True, node_size=500)

您稍后可以在图中执行任何操作,例如删除一些节点:

G.remove_nodes_from([(0,0),(0,2),(2,2),(2,1)])

并重新绘制图形,实际上不需要重新计算 poslabel 字典,因为条目会随着图形操作自动更新。下一行与上面的绘图调用完全相同:

nx.draw_networkx(G, pos=nx.get_node_attributes(G, 'pos'),    
                 labels=nx.get_node_attributes(G, 'labels'), 
                 with_labels=True, node_size=500)

但这一次,产生了不同的图像:

简而言之:将所有内容存储在 node/edge 属性中,因为它们会随着图表的变化而自动更新。