1

I have a added a length table in every line of my shapefile which contains lines that represent roads, and I want to create a weighted graph with this data using the length table as weights.

My table

I have used this answer to load my shapefile and create the graph with NetworkX.

My graph

I am wondering how can I get the weights defined in the table "length", so I can show in my graph.

Edited Result after using @gene 's solution to draw the graph.

pos = {v:v for v in weighted_G.nodes()}

labels = nx.get_edge_attributes(weighted_G,'weight')


nx.draw_networkx_nodes(weighted_G,pos, node_size=10,node_color='r')
nx.draw_networkx_edges(weighted_G, pos)
nx.draw_networkx_edge_labels(G,pos,edge_labels=labels)
# plt.xlim(577000, 579500) #This changes and is problem specific
# plt.ylim(9718500, 9721000) #This changes and is problem specific
plt.xlabel('X [m]')
plt.ylabel('Y [m]')
plt.title('From shapefiles to NetworkX')
plt.show()
plt.savefig('graph.eps', format='eps', rasterized=False)

Graph with weights

1
  • You need from and to nodes, see add_edge in networkx help. – FelixIP Sep 28 '17 at 19:26
4

There are many other solutions proposed in GIS SE to convert a shapefile into a graph with Networkx..

If you use the Networkx solution (nx.read_shp()), the original geometry and the field values are still present in the edge data (see How to calculate edge length in Networkx)

Open the shapefile with GeoPandas for example

import geopandas as gpd
graph = gpd.read_file('egdge.shp')
graph.head()
  FID    length                     geometry
0  0.0  139.7458  LINESTRING (750.9195417696708 -225.09097935036...
1  1.0  173.8602  LINESTRING (169.9697833632519 -134.27610827609...
2  2.0  183.0633  LINESTRING (10.24390243902439 -273.31707317073...
3  3.0   33.3517  LINESTRING (750.9195417696708 -225.09097935036...
4  4.0   74.5553  LINESTRING (232.6829268292683 -113.31707317073...
# first element
print graph.iloc[0]['length']
139.7458

Now, the same shapefile with Networxk

import networkx as nx
G = nx.read_shp('edges.shp')
# first edges
first = G.edges()[0]
print first
((750.9195417696708, -225.0909793503697), (782.9268292682925, -361.1219512195121)

but with data=True

first = G.edges(data=True)[0]
print first
((750.9195417696708, -225.0909793503697), (782.9268292682925, -361.1219512195121), {'ShpName': 'edges', 'Json': '{ "type": "LineString", "coordinates": [ [ 750.919541769670786, -225.090979350369707 ], [ 782.926829268292522, -361.121951219512084 ] ] }', 'FID': 0.0, 'Wkb': '\x00\x00\x00\x00\x02\x00\x00\x00\x02@\x87w[8\xb7 V\xc0l"\xe9M\x86\xce`@\x88wj%v\xa2V\xc0v\x91\xf3\x83\x1f80', 'length': 139.7458, 'Wkt': 'LINESTRING (750.919541769670786 -225.090979350369707,782.926829268292522 -361.121951219512084)'})
print first[0] # first node
(750.9195417696708, -225.0909793503697)
print first[1] # second node
(782.9268292682925, -361.1219512195121)
print first[2] # properties
{'ShpName': 'edges', 'Json': '{ "type": "LineString", "coordinates": [ [ 750.919541769670786, -225.090979350369707 ], [ 782.926829268292522, -361.121951219512084 ] ] }', 'FID': 0.0, 'Wkb': '\x00\x00\x00\x00\x02\x00\x00\x00\x02@\x87w[8\xb7 V\xc0l"\xe9M\x86\xce`@\x88wj%v\xa2V\xc0v\x91\xf3\x83\x1f80', 'length': 139.7458, 'Wkt': 'LINESTRING (750.919541769670786 -225.090979350369707,782.926829268292522 -361.121951219512084)'}
print first[2]['length']
139.7458

Therefore

weighted_G = nx.Graph()
for data in G.edges(data=True):
   weighted_G.add_edge(data[0],data[1],weight=data[2]['length'])
2
  • Thanks, I didn't knew about GeoPandas, seems like a easier solution. – Rkanehisa Sep 29 '17 at 14:45
  • It worked, and a could even draw the graph. – Rkanehisa Sep 29 '17 at 15:20
2

This didn;t actually work for me (maybe because of updates), but below is the code that worked for me. Updated from the answers above.

I post this as a followup from How to load a weighed shapefile in networkX

So I have created a network with QGIS and OSM (openstreetmaps), and exported it into two files: nodes and edges using of shapefiles.

However, I have a lot of trouble converting this into an actual networkx graph, which I will use for my simulation model. After reviewing the post(s) like this How to load a weighed shapefile in networkX

I wanted to create a network using the geolocations of the nodes, and connect them with edges with source-target pair and add attributes such as distance, cost, width.

I still have a lot of trouble actually adding weight and labels to the edges. If I follow that post, every step of the way should give the same results.

To figure out if there was something different with my shapefile than theirs, I used the following code:

  import geopandas as gpd
graph = gpd.read_file('/Users/01/Downloads/edge_data_length.shp')
print(graph.head())   

Which gave the following results:

edge_id  start_node  end_node  next_left_  abs_next_l  next_right  \
0       45          63        64          50          50          45   
1       54          78        56         -54          54         -39   
2       39          55        78         -55          55          39   
3        6          11        12        -101         101          43   
4      110         121        60         -41          41         110   

   abs_next_r  left_face  right_face        cost  \
0          45          0           0  122.826431   
1          39          0           0  250.869815   
2          39          0           0   43.350826   
3          43          4           5  516.143133   
4         110          0           0  584.250999   

                                            geometry  
0  LINESTRING (4.8703865 52.364651, 4.8716933 52....  
1  LINESTRING (4.9264105 52.3695602, 4.9289823 52...  
2  LINESTRING (4.9259642 52.3692824, 4.9264105 52...  
3  LINESTRING (4.877608 52.3752153, 4.8778622 52....  
4  LINESTRING (4.8701251 52.3757447, 4.8706393 52...  

Which looked good enough, but then I tried their code step for step but with no results. Their code:

import networkx as nx
G = nx.read_shp('edges.shp')
# first edges
first = G.edges()[0]
print first
((750.9195417696708, -225.0909793503697), (782.9268292682925, -361.1219512195121)

My code

  import networkx as nx
import matplotlib.pyplot as plt
G = nx.read_shp('/Users/01/Downloads/edge_data_length.shp')
# first edges
first = G.edges(data = True)[1]

gives:

    --------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-be0a4d56d7fb> in <module>()
      3 G = nx.read_shp('/Users/01/Downloads/edge_data_length.shp')
      4 # first edges
----> 5 first = G.edges(data = True)[1]

TypeError: 'OutEdgeDataView' object does not support indexing

So I tried putting it in a list:

first = list(G.edges(data=True))
print(first[1])

And it gave the following result:

((4.8719547, 52.3651758), (4.8716814, 52.365598), {'edge_id': 50, 'start_node': 64, 'end_node': 70, 'next_left_': -50, 'abs_next_l': 50, 'next_right': -135, 'abs_next_r': 135, 'left_face': 0, 'right_face': 0, 'cost': 50.5301293256479, 'ShpName': 'edge_data_lengte', 'Wkb': b'\x00\x00\x00\x00\x02\x00\x00\x00\x02@\x13|\xe1\xb1`_\xbc@J.\xbe\x14\xa3%4@\x13|\x9a\x0c\x86 @@J.\xcb\xeaN\xbd\xd3', 'Wkt': 'LINESTRING (4.8719547 52.3651758,4.8716814 52.365598)', 'Json': '{ "type": "LineString", "coordinates": [ [ 4.8719547, 52.3651758 ], [ 4.8716814, 52.365598 ] ] }'})

Then I tried adding it to the graph, like the post was doing as well:

weighted_G = nx.Graph()
for data in first:
    weighted_G.add_edge(data[0],data[1],weight=data[2]['cost'])

pos = {v:v for v in weighted_G.nodes()}
labels = nx.get_edge_attributes(weighted_G,'cost')

nx.draw_networkx_nodes(weighted_G,pos, node_size=2,node_color='r')
nx.draw_networkx_edges(weighted_G, pos)
nx.draw_networkx_edge_labels(G,pos,edge_labels=labels)
# plt.xlim(577000, 579500) #This changes and is problem specific
# plt.ylim(9718500, 9721000) #This changes and is problem specific
plt.xlabel('X [m]')
plt.ylabel('Y [m]')
plt.title('From shapefiles to NetworkX')
plt.show()
#plt.savefig('graph.eps', format='eps', rasterized=False)

It gave no errors this time, but it still got a graph without the weight "cost" for each edge. So now I changed this

labels = nx.get_edge_attributes(weighted_G,'cost')

to: labels = nx.get_edge_attributes(weighted_G,'weight')

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.