networkx 只有一个功能
图.subgraph()
创建从节点诱导的子图。但是如何从边列表构造子图?
谢谢 !
如果你有一个边列表,那么你已经有了子图。只需nx.Graph
在列表上调用,并可选择从原始图中添加(未连接的)节点。从文档
Graph.__init__(data=None, **attr)
使用边、名称、图形属性初始化图形。
用于初始化图形的数据。如果 data=None(默认)创建一个空图。数据可以是边列表,也可以是任何 NetworkX 图形对象。
@larsmans 的答案是正确的。这是一个简单的例子:
In [1]: import networkx as nx
In [2]: G = nx.path_graph(6)
In [3]: G.edges()
Out[3]: [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
In [4]: subgraph_edges = [(1,2), (3,4)]
In [5]: S = nx.Graph(subgraph_edges)
In [6]: S.edges()
Out[6]: [(1, 2), (3, 4)]
如果您想要一个函数具有Graph.subgraph()
从节点创建的子图的属性,但该函数适用于边的迭代器,则需要保留对原始图、边和节点的引用,以便能够传播图中的更改、边或节点数据属性。尤其是来自 的文档字符串Graph.subgraph()
:
图、边或节点属性只是指向原始图。因此对节点或边结构的更改不会反映在原始图中,而对属性的更改会。
要创建具有自己的边/节点属性副本的子图,请使用:nx.Graph(G.subgraph(nbunch))
如果边缘属性是容器,则可以使用以下方法获得深拷贝: G.subgraph(nbunch).copy()
当前提出的方法不会将其属性的变化反映在原始图中,因为它们将从头开始创建一个新图。
没有内置函数/方法可以通过边缘列表来完成此任务。但是这个函数使用节点的基础设施,.subgraph
因此应该适用于 Graph 和 DiGraph。它不适用于非 MultiGraph 和 MultiDiGraph。这是因为 MultiGraph 和 MultiDiGraph 可能需要您参考边缘的键,而当前方法会忽略第二个之后的参数,以便对传入的边缘列表是否具有附加为字典的属性不敏感。此外,即使它是在没有引用的情况下创建的(通过传递ref_back=False
),它也不会使用nx.Graph
or创建新图形nx.DiGraph
类初始值设定项,而是原始图的深层副本。可以将其扩展到涵盖其他情况......但我现在不需要它,直到有人明确要求它,我会假设没有其他人这样做(如果你想查看版本,请参阅github我在实践中使用过)。
def subgraph_from_edges(G,edge_list,ref_back=True):
"""
Creates a networkx graph that is a subgraph of G
defined by the list of edges in edge_list.
Requires G to be a networkx Graph or DiGraph
edge_list is a list of edges in either (u,v) or (u,v,d) form
where u and v are nodes comprising an edge,
and d would be a dictionary of edge attributes
ref_back determines whether the created subgraph refers to back
to the original graph and therefore changes to the subgraph's
attributes also affect the original graph, or if it is to create a
new copy of the original graph.
"""
sub_nodes = list({y for x in edge_list for y in x[0:2]})
edge_list_no_data = [edge[0:2] for edge in edge_list]
assert all([e in G.edges() for e in edge_list_no_data])
if ref_back:
G_sub = G.subgraph(sub_nodes)
for edge in G_sub.edges():
if edge not in edge_list_no_data:
G_sub.remove_edge(*edge)
else:
G_sub = G.subgraph(sub_nodes).copy()
for edge in G_sub.edges():
if edge not in edge_list_no_data:
G_sub.remove_edge(*edge)
return G_sub
诀窍是可以安全地从图中删除任何不存在于边中的节点(给我们我们的节点子集),然后您可以删除任何保留但不在边列表中的边。
注意:我意识到这现在是一个相当古老的问题,但如果解释为提问者想要一个直接引用原始图、边和节点的图(特别是包括它们的数据)的情况,所提供的答案实际上并不能回答这个问题属性)。我需要那个解决方案,所以我想无论如何我都会发布它。
在前面的答案的基础上,保留原始图形及其所有属性的一个非常简单的解决方法可能是:
FG = nx.Graph(fedges)
G = G.subgraph(FG.nodes())
这里,fedges是构建子图的过滤边列表。首先,使用过滤后的边创建一个新的临时图 ( FG )。然后使用节点列表(FG.nodes())从原始图中获取子图。由于您实际上是在原始图形对象上使用subgraph函数,因此您不会从中丢失任何属性。
根据dbn的评论,networkx 现在包含一个功能nx.edge_subgraph
来执行此操作。它保留了原始图表中的属性,但是对这些属性的更改将反映在原始图表中。
G = nx.path_graph(5)
S = G.edge_subgraph([(0, 1), (3, 4)])
list(S.nodes) # [0, 1, 3, 4]
list(H.edges) # [(0, 1), (3, 4)]