0

这是对我之前的问题的跟进。

问题在于创建无向图时节点在边列表中的保存顺序。我有一个使用下面的代码创建的图表。创建一个简单的图,并在两个已经存在的节点之间添加新的节点和边。

import networkx as nx
import matplotlib.pyplot as plt
from pprint import pprint

G = nx.OrderedGraph()
head_nodes = range(0, 9)
tail_nodes = range(1, 10)
edge_ls = list(zip(head_nodes, tail_nodes))
G.add_nodes_from(range(0, 10))
G.add_edges_from(edge_ls)

head = 0
tail = 1
G.remove_edge(head, tail)
Nnodes = G.number_of_nodes()
newnodes = [head, Nnodes+1, Nnodes+2, Nnodes+3, tail] # head and tail already exists
newedges = [(x, y) for x, y in zip(newnodes[0:len(newnodes)-1], newnodes[1:len(newnodes)])]
G.add_edges_from(newedges)
I = nx.incidence_matrix(G)
pprint(I)
pprint(G.edges())
nx.draw(G, with_labels=True)
plt.show()

使用无向图的输出是:

EdgeView([(0, 11), (1, 2), (1, 13), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (11, 12), (12, 13)])

从输出中,我们可以观察到使用 G.add_edge(13,1) 创建的边显示为 (1,13)。我理解这是因为图表是无向的。

当使用有向图(G.OrderedDiGraph)时,输出为:

EdgeView([(0, 11), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (11, 12), (12, 13), (13, 1)])

(13, 1) 与我预期的结果一样。

但是,我很想知道是否有一种特定的方式可以命名节点,以便避免 Networkx 将节点从 (u,v) (用户输入)重新排序到 (v,u)一个无向图。

编辑:我避免使用有向图,因为有这样的输入有向图会产生以下结果 在此处输入图像描述

在这个有向图中,节点 24 和 28 的入度和出度之和为 1。但是,我希望箭头从节点 24 指向 28,类似于交通网络中可能有不同路线的单向流从点 24 流向点 28 的流量。由 Networkx 的 diGraph 创建的方向并不代表我的真实系统。因此,我不想使用有向图。

4

2 回答 2

3

不,这对于 networkx 是不可能的。即使您尝试使用 a OrderedGraph,您会得到的最好的结果是

一致的顺序不是特定的顺序。

当您选择使用 aGraph而不是 aDiGraph时,您明确声明它是无向的,因此方向无关紧要,并且 networkx 保存有关方向的信息效率低下。在底层数据结构中,它不保存边列表。相反,它保存了一个字典,说明每个节点的邻居是什么(因此没有存储有关用户输入顺序的信息)。当它重建一个EdgeView时,它使用这个字典,所以关于用户如何输入它的所有信息都已经丢失了。

如果您需要这样做,我建议您使用DiGraph. 如果您需要它是有向的(跟踪边的顺序)的混合体,但仍然是无向的(将每条边视为具有两个方向),我建议将边方向与 networkx 图分开存储。

于 2019-09-15T05:27:10.490 回答
2

正如我之前所说和乔尔在他的回答中所说,您需要将边缘存储在适合您需要的数据结构中,而不是依赖于图表。选择一个数据结构并定义一些add_edge添加到该数据结构和您的图形的函数,并且只使用该函数来添加边。如果你只是想记住你曾经拥有的所有优势,这将是:

edges = set()

def add_edge(u, v):
    G.add_edge(u, v)
    edges.add((u, v))

如果您想根据图形的更改检索原始边的某些子集(例如,您想查看删除节点后保留哪些边),则使用将每个边的两个排序都映射到原始边的字典:

edges = {}

def add_edge(u, v):
    G.add_edge(u, v)
    edges[(u, v)] = (u, v)
    edges[(v, u)] = (u, v)

然后,在更改图形后,您可以像这样获得原始边缘:

{edges[edge] for edge in G.edges()}
于 2019-09-15T08:09:04.747 回答