如何使用用户定义的 class 对象作为 networkx 节点?

How to use user-defined class object as a networkx node?

Class点定义为(里面也有一些方法,属性之类的东西,但这是最小的部分):

class point():
    def ___init___(self, x, y):
        self.x = x
        self.y = y

所以,我看到了 this question,但是当我尝试应用它时,它 returns 出现错误:

G = nx.Graph()
p = point(0,0)
G.add_node(0, p)

NetworkXError: attr_dict 参数必须是字典。

如果我使用

G = nx.Graph()
p = point(0,0)
G.add_node(0, data = p)

我没有收到错误,但是当我尝试访问 x 坐标时,结果发现它没有将其保存为一个点。

G[0].x

returns: AttributeError: 'dict' 对象没有属性 'x'

正在做

G = nx.Graph()
G.add_node(0, data = point(0,0))
G[0]

returns: {}

这意味着它仍将其保存为字典。

我看到我可以使我的点可散列,并将这些对象用作节点,所以我添加了属性 id,因为点会移动。我将其添加到 class 和 __repr__ 中以便更好地绘制图形:

def __hash__(self):
    return self.id_n
def __cmp__(self, p):
    if self.id_n < p.id_n: return -1
    elif self.id_n == p.id_n: return 0
    else: return 1
def __eq__(self, p):
    if p.id_n == self.id_n: return True
    else: return False
def __repr__(self):
    return str(self.id_n) 

但这有点奇怪,因为我不知道如何 select 一个节点,

G[<what should i put here?>]

所以,问题是,执行此操作的正确方法是什么?

我希望能够使用类似

的东西
G[node_id].some_method(some_args)

您已经添加了一个 node,因此,您可以检查 nodes,它是一个 set-like 视图。引用文档:

These are set-like views of the nodes, edges, neighbors (adjacencies), and degrees of nodes in a graph. They offer a continually updated read-only view into the graph structure.

举个例子:

mynodes = list(G.nodes())
print(mynodes)

您现在应该也可以:

mynode = mynodes[0]  # because we have converted the set-like view to a list

查看教程:https://networkx.github.io/documentation/stable/tutorial.html

编辑 - 在下面,将 G.node[] 替换为 G.nodes[] - 在版本 2.4 中 G.node 已被弃用。

您正在查看 G[0]。但这不是你想要的。 G[0]包含节点0的邻居信息和边的属性,但不包含节点0的属性。

class point():
    def __init__(self, x, y):
        self.x = x
        self.y = y

import networkx as nx
G = nx.Graph()
p0 = point(0,0)
p1 = point(1,1)

G.add_node(0, data=p0)
G.add_node(1, data=p1)
G.add_edge(0,1, weight=4)
G[0]
> AtlasView({1: {'weight': 4}})  #in networkx 1.x this is actually a dict. In 2.x it is an "AtlasView"

对于 networkx,期望一个节点可能有大量与之关联的数据。在您的情况下,您只有一条数据,即点。但是您也可以指定颜色、重量、时间、年龄等。因此 networkx 将把所有属性存储在另一个字典中,但是该字典是通过 G.node[0] 而不是 G[0].

G.node[0]
> {'data': <__main__.point at 0x11056da20>}
G.node[0]['data'].x
> 0

请注意,您输入的 data 变为字符串 'data'

输入 G.add_node(0, x=0, y=0) 这样的节点可能会更好,然后您可以访问 G.node[0]['x'].

的条目

我想我明白你的问题了。

您想使用已定义为节点的 class 实例,并能够轻松访问实例属性或方法。

当您在 networkx 中使用类似以下内容创建图形时:

G = nx.DiGraph() # create graph
G.add_nodes_from([node0, node1, node2]) # add 3 nodes
G.nodes[node0]["node_attribute0"] = "value0"
G.add_edges_from([(node0, node1), (node0, node2)]) # add 2 edges
G[node0][node1]["edge_attribute0"] = "value1" # add one attribute to edge
G[node0][node1]["edge_attribute1"] = 10 # add another attribute to same edge

networkx 创建嵌套的 python 字典,例如在有向图的情况下,3 个嵌套的字典如下:

'''
   G = {
        node0 : {
                 node1 : {
                          "edge_attribute0" : "value1",
                          "edge_attribute1" : 10
                         },
                 node2 : {}
                 },
        node1 : {},
        node2 : {}
        }
'''

这就是为什么您使用连续的 [key]

访问每个
G[node0]                    # = output dict of dict, with neighbours on top layer
G[node0][node1]             # = output dict with edge attributes
G[node0][node1][attribute0] # = output value

现在,节点属性不会存储在那些嵌套字典的任何位置。 它们位于一个单独的嵌套字典中,您可以通过 G.nodes:

访问
'''
    G.nodes = {
               node0 : {
                        "node_attribute0" : "value0"
                       }
               }
'''

您可以像这样使用 G.nodes 来访问其他字典:

G.nodes[node0]["node_attribure0"]  # = value assigned to key

如您所见,2 个字典嵌套中的任何一个都无法将节点作为对象本身来访问,因为在所有情况下它们都只是字典“键”。

解决方法是将节点对象本身存储为节点属性,为此您可以使用“self”作为方便的键:

for node in G: # iterate over all nodes in G
    G.nodes[node]["self"] = node # create new node attribute = node

现在,如果 node0、node1、node2 是您之前定义的 class 的所有实例,假设有一个名为“variable”的变量和一个名为“method”的方法,您现在可以访问这些通过使用:

G.nodes[node0]["self"].variable
G.nodes[node0]["self"].method()