合并(连接)networkx图形

70

假设我有两个networkx图,GH:

G=nx.Graph()
fromnodes=[0,1,1,1,1,1,2]
tonodes=[1,2,3,4,5,6,7]
for x,y in zip(fromnodes,tonodes):
    G.add_edge(x,y)

H=nx.Graph()
fromnodes=range(2,8)
tonodes=range(8,14)
for x,y in zip(fromnodes,tonodes):
    H.add_edge(x,y)

如何最佳方式将两个networkx图连接起来?

我希望保留节点名称(请注意,节点2到7是公共的)。当我使用nx.disjoint_union(G,H)时,这并没有发生:

>>> G.nodes()
[0, 1, 2, 3, 4, 5, 6, 7]
>>> H.nodes()
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
>>> Un= nx.disjoint_union(G,H)
>>> Un.nodes()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
# 

节点标签H被更改了(不是我想要的)。我想将具有相同编号的节点连接到一起。

注意。这不是在NetworkX中合并两个加权图的重复问题。


3
如果两者之间存在一条边,你想要做什么?它应该变成双向边还是单向边? - Joel
1
@Joel 嗯,我对两种情况都感兴趣。不过,我们假设是单边的情况。 - Lee
1
你编写的代码已经很好地处理了单边缘情况。对于多边缘情况,你只需要使用 U=nx.MultiGraph() 即可。 - Joel
1
对于你的例子,可以进行简化:for x,y in zip(fromnodes,tonodes): G.add_edge(x,y) 可以写成 G.add_edges_from(zip(fromnodes,tonodes)) - Joel
3个回答

94

你要找的函数是compose,它可以生成一个包含两个图中所有边和节点的新图。如果两个图中有同名节点,则只保留一个节点在新图中。类似地,如果两个图中存在相同的边,则只保留一条边在新图中。下面是一个包括边/节点属性的示例:

import networkx as nx

G=nx.Graph()
G.add_node(1, weight = 2)
G.add_node(2, weight = 3)
G.add_edge(1,2, flux = 5)
G.add_edge(2,4)

H=nx.Graph()
H.add_node(1, weight = 4)
H.add_edge(1,2, flux = 10)
H.add_edge(1,3) 

F = nx.compose(G,H)
#F has all nodes & edges of both graphs, including attributes
#Where the attributes conflict, it uses the attributes of H.

G.nodes(data=True)
> NodeDataView({1: {'weight': 2}, 2: {'weight': 3}, 4: {}})
H.nodes(data=True)
> NodeDataView({1: {'weight': 4}, 2: {}, 3: {}})
F.nodes(data=True)
> NodeDataView({1: {'weight': 4}, 2: {'weight': 3}, 4: {}, 3: {}})

G.edges(data=True)
> EdgeDataView([(1, 2, {'flux': 5}), (2, 4, {})])
H.edges(data=True)
> EdgeDataView([(1, 2, {'flux': 10}), (1, 3, {})])
F.edges(data=True)
EdgeDataView([(1, 2, {'flux': 10}), (1, 3, {}), (2, 4, {})])

这些保留了属性,但显然如果存在冲突则不可能。 H 的属性优先。

还有其他选项可以执行对称差异、交集等操作...

如果您有多个图需要合并,可以使用compose_all,它只是在compose周围包装了一个循环。


如何在使用 nx.draw_networkx(G) nx.draw_networkx(H) nx.draw_networkx(F) plt.show() 绘制所有图形时,强制所有具有相同标签的节点共享相同位置?我的意思是,所有3个图形中节点1的坐标应该相同。 - Sigur
@Sigur 绘图命令接受一个可选的输入参数 pos,例如 nx.draw_networkx(G, pos=pos)pos 是一个字典,其键为节点,值为它们的 (x,y) 坐标。你可以自己定义它,或通过一些 layout 命令来定义。例如,pos = nx.spring_layout(F) - Joel
我想先使用布局来获得良好的显示效果,然后在添加新边缘并在其他窗口中再次绘制时使用相同的坐标。或多或少地说,我想生成一系列图形,以展示图表的时间线。 - Sigur
@Joel - 非常棒的答案!谢谢。你知道这是否适用于图形的图形吗?在我的情况下,一些节点实际上是图形对象,并且这些图形包含其他节点(可能更多的图形)。组合函数最终会将所有内容组合在一起。我想这归结于哈希值或类似的东西。只是想知道你以前尝试过这个吗? - Yani

11

这样就行了。

   U=nx.Graph()
   U.add_edges_from(G.edges()+H.edges())
   U.add_nodes_from(G.nodes()+H.nodes()) #deals with isolated nodes

或者,保留边缘属性:

   U.add_edges_from(G.edges(data=True)+H.edges(data=True))

同时保留节点属性:

   U.add_nodes_from(G.nodes(data=True)+H.nodes(data=True))

在 NetworkX 2.2 中,需要将 G.edges() 转换为列表后再添加。尤其是在需要 MultiGraph 时。 - Traxidus Wolf
这个问题如何处理我有一个类似于 G: Node1 [label="L1x"], Node2 [label="L2x"]; H: Node1 [label="L1y"], Node2 [label="L2x"] 的图形,其中 Node1 表示连接图中不同的节点,但是 Node2 是公共的。 - jxramos

0
如果你想将图H添加到G中,然后返回G,可以使用update方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接