Как установить имена узлов в networkxgraph от 0 до len (G.nodes) - PullRequest
0 голосов
/ 18 сентября 2018

Надеюсь, вы можете помочь мне со следующим, вероятно, очень простым, но я просто не могу этого понять.

Я хочу установить имена узлов для моих узлов в моем графе, чтобы я мог использовать их позжедля алгоритма Дейкстры из пакета networkx.Шейп-файл имеет узлы, основанные на длинном lat, как показано ниже:

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})

Но Дейкстра не может прочитать этот ввод, если я скажу:

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

Но, как сказал @ zohar.kom, это дало мне больше пониманияизменяет атрибут , а не имя самого узла;который необходим для алгоритма dijkstra в сети x.

Есть мысли о том, как мне изменить / добавить имя или метку для каждого узла?Так что мой ввод для 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

Но я решил эту последнюю часть с помощью следующего, добавив данные= 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, у меня уже есть атрибуты для каждого ребра в шейп-файле.Так что все, что мне нужно было сделать, это добавить их.Большое спасибо !!

1 Ответ

0 голосов
/ 19 сентября 2018

Правильный способ использования 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 - это словарь, который отображает каждую пару широты (то есть, каждый узел) в словарьс одним свойством, с ключом "name" и значением, равным соответствующему индексу.

Прочтите документацию для подробного объяснения того, как правильно использовать 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 вам необходимо указать вес ребер графа (которые определяются в соответствии с входным файлом).В основном, есть 2 варианта определения весов:

  1. Использование свойства ребра - это можно сделать, вызвав что-то вроде nx.dijkstra_path(G, 1, 20, weight='cost'), где 1 и 20 - это узлы, а «стоимость» - это имясвойство краев.
  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)

Опять же, для более подробной информации просто посмотрите документацию и примеры здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...