如何在networkxgraph中将节点名称从0设置为len(G.nodes)

时间:2018-09-18 19:10:37

标签: python nodes networkx

希望您可以在以下方面为我提供帮助,这可能非常简单,但我似乎无法理解。

我想将节点名设置为图形中的节点,因此以后可以将它们用于networkx包中dijkstra的算法。 shapefile具有基于长纬度的节点,如下所示:

crossings = list(G.nodes(data = True))
print(crossings)

礼物:

[((4.8703865, 52.364651), {}), ((4.8719547, 52.3651758), {}), ((4.9264105, 52.3695602), {}), ((4.9289823, 52.3711744), {}), ((4.9259642, 52.3692824), {}), ((4.877608, 52.3752153), {}), ((4.8847629, 52.3765112), {}), ((4.8701251, 52.3757447), {}), ((4.8738594, 52.3804434), {}), ((4.8866343, 52.3574955), {}), ((4.8873865, 52.3602753), {}), ((4.8792688, 52.3649914), {}), ((4.8775365, 52.366768), {}), ((4.879805, 52.3667268), {}), ((4.8824711, 52.3674209), {}), ((4.8790738, 52.3677393), {}), ((4.8771909, 52.3704447), {}) .....

现在,我想设置节点名称,作为以下代码的输入:

print(nx.dijkstra_path(weighted_G, "1" , "20", weight='cost'))

但是我似乎无法弄清楚如何为每个节点设置名称作为数字,因此节点1获得名称“ 1”,节点“ 2”获得名称“ 2”,直到节点n获得“ n”

 G=nx.read_shp('shapefile.shp', simplify=True) # shapefile from OSM
 crossings = list(G.nodes(data = True))
 weighted_G = nx.Graph()
 j = 0
 for i in crossings:
   nx.set_node_attributes(weighted_G, values = "none" ,name = j)
   j = j + 1
 print(crossings)

但是此输出给出:

[((4.8703865, 52.364651), {}), ((4.8719547, 52.3651758), {}), ((4.9264105, 52.3695602), {}), ((4.9289823, 52.3711744), {}), ((4.9259642, 52.3692824), {}), ((4.877608, 52.3752153),.......

如您所见,没有添加任何数字作为节点名,有人知道如何解决此问题吗?

预先感谢

编辑和更新----------------------------------------- ---------------------

所以我昨晚将代码更改为:

weighted_G=nx.read_shp('shapefile.shp', simplify=True) # shapefile from OSM
     c = list(weighted_G.nodes(data=True))
    j = 0 
    for i in weighted_G.nodes:
        weighted_G.node[i]['name']= j
        j = j + 1 
    print (c[0])

与提供的@ zohar.kom代码具有相同的输出。现在,每个节点都包含以下内容:

((4.8703865, 52.364651), {'name': 0})

但是,如果我说:Dijkstra无法读取此输入内容

print(nx.dijkstra_path(weighted_G, {'name': 1} , {'name': 20}, weight='cost'))

但是就像@ zohar.kom所说的那样,它给了我更多的见解,它改变了节点本身的属性,而不是节点本身的名称;这是networkx中dijkstra算法所需要的。

是否有关于如何为每个节点更改/添加名称标签的想法? 因此,我对Dijkstra的输入是

print(nx.dijkstra_path(weighted_G, 'node 1' , 'node 20', weight='cost'))

,每个节点将如下所示:

(node 1, (4.8719547, 52.3651758))

代替:

((4.8703865, 52.364651), {'name': 0})

希望你能帮我这个忙!

更新2 -------------------------------------- ----------------------------

在@ zohar.kom的帮助下,我终于解决了它。 当我直接使用@ zohar.kom中的代码时,

仍然出现错误
for edge in G.edges():
    w_G.add_edge(lat_lon_to_index[edge[0]], lat_lon_to_index[edge[1]], cost=edge[2]['cost_property_name'])

说:

IndexError: tuple index out of range

但是我通过添加data = True解决了最后一部分:

for edge in G.edges(data=True):
        w_G.add_edge(lat_lon_to_index[edge[0]], lat_lon_to_index[edge[1]], cost=edge[2]['cost_property_name'])

完全解决了!! 所以这是任何人的最终代码!

    G=nx.read_shp('path/shapefile.shp', simplify=False) # use simplify is false otherwise chart get shifted
w_G = nx.DiGraph()
lat_lon_to_index = {}
for i, node in enumerate(G.nodes()):
    w_G.add_node(i, lat_lon= node)
    lat_lon_to_index[node] = i

for edge in G.edges(data=True):
    w_G.add_edge(lat_lon_to_index[edge[0]], lat_lon_to_index[edge[1]], weight=edge[2]['cost'])
c =list(w_G.nodes(data = True))
j = list(w_G.edges(data = True))
print(c[1])
print (j[2])

给予:

    (1, {'lat_lon': (4.8716933, 52.3650215)})
(1, 2, {'weight': 122.826431079961})

因为,就像@ zohar.kom所说的那样,我已经对shapefile中的每个边都有属性。因此,我要做的就是添加它们。非常感谢!

1 个答案:

答案 0 :(得分:1)

正确使用set_node_attributes的正确方法是:

G=nx.read_shp('shapefile.shp', simplify=True)
crossings = list(G.nodes(data=True))
names_dict = {val[0]: {"name":i} for i, val in enumerate(crossings)}
nx.set_node_attributes(G, values=names_dict)

在此实现中,names_dict是一个字典,该字典将每个纬长对(即每个节点)映射到具有单个属性,键为“名称”且值等于相应索引的字典。

阅读documentation,以获得有关如何正确使用set_node_attributes的深入说明。

在实现过程中有2个错误:

  1. weighted_G是一个新的空有向图,而不是nx.read_shp返回的有向图
  2. 您使用set_node_attributes参数是错误的。更具体地说,name是一个可选参数,它引用节点的属性的名称,而不是节点本身的名称。

编辑:

首先,要构建图以使lat_lon是一个属性,并使用索引定义节点,您可以编写:

w_G = nx.DiGraph()
lat_lon_to_index =  {}
for i, node in enumerate(G.nodes()):
    w_G.add_node(i, lat_lon=node)
    lat_lon_to_index[node] = i

for edge in G.edges():
    w_G.add_edge(lat_lon_to_index[edge[0]], lat_lon_to_index[edge[1]], cost=edge[2]['cost_property_name'])

请注意,这里我根据从输入文件读取的边缘定义了边缘。

要使用nx.dijkstra_path,需要指定图形边缘的权重(根据输入文件定义)。基本上,有两个选项可以定义权重:

  1. 使用edge属性-可以通过调用nx.dijkstra_path(G, 1, 20, weight='cost')之类的东西来完成,其中1和20是节点,'cost'是edge属性的名称。
  2. 另一个选择是将距离定义为一个函数。假设您想要欧几里得距离,您可以定义一个距离函数:

    def distance_func(u, v, d): return math.sqrt( ((w_G.nodes[u]['lat_lon'][0] - w_G.nodes[v ['lat_lon'][0]) ** 2) + ((w_G.nodes[u]['lat_lon'][1] - w_G.nodes[v]['lat_lon'][1]) ** 2))

    并最终如下使用它:path = nx.dijkstra_path(w_G, 1, 20, distance_func)

同样,有关更多详细信息,只需查看文档和示例here