[GIS] Create shapefile line from a list of point coordinates in a stand-alone python script

dijkstralinepyqgis

I've used pyqgis to calculate the shortest path through a network between two points. I want to turn this shortest path into a polyline.

I've managed to use the QGIS dijkstra function to calculate a shortest path between two points in a network.
If I print the resulting variable point_route as a string, it prints a list of coordinates.

Where do I go from here?

Is there a(nother) well-documented python library that I can use to turn this list of coordinates into a single polyline shapefile? I can't seem to find/understand the right instructions for pyqgis.

Relevant code
(copied from the shortest path chapter of 'pyqgis developer cookbook'):

(tree, cost) = QgsGraphAnalyzer.dijkstra(graph, startId, 0)

if tree[endId] == -1:
    print "Path not found"
else:
    point_route = []        
    curPos = endId                                                              
    while curPos != startId:                                                    
        point_route.append(graph.vertex(graph.arc(tree[curPos]).inVertex()).point())  
        curPos = graph.arc(tree[curPos]).outVertex()                            
        print "appended " + str(curPos)                                         
    point_route.append(tStart)                                                  

Best Answer

The result of the PyQGIS script is a list of points (point_route)

enter image description here

In this example, the point_route result is (7 points between pStart = QgsPoint(110579.17281126765, 116585.26070464966), point 7, and pStop = QgsPoint(111819.28396552203, 116854.75854462344)), point 22)

[(111819,116855), (111576,116688), (111306,116504), (111145,116599), (111005,116681), (110724,116484), (110579,116585)]

If you want to transform these points in a LineString

line = QgsGeometry.fromPolyline( point_route)
print line.exportToWkt()
LineString (111819.28396552200138103 116854.75854462340066675, 111575.63678446662379429 116688.29510413877142128, 111305.62611302707227878 116503.81972814344044309, 111144.6106812154466752 116598.9506020281551173, 111004.94058255387062673 116681.47026111763261724, 110723.93371811544056982 116483.65621838794322684, 110579.17281126769375987 116585.26070464969961904)
print print line.exportToGeoJSON()
{"type": "LineString", "coordinates": [ [111819.28396552200138103, 116854.75854462340066675], [111575.63678446662379429, 116688.29510413877142128], [111305.62611302707227878, 116503.81972814344044309], [111144.6106812154466752, 116598.9506020281551173], [111004.94058255387062673, 116681.47026111763261724], [110723.93371811544056982, 116483.65621838794322684], [110579.17281126769375987, 116585.26070464969961904]]}

And you can use pyQGIS to save the result to a shapefile (in green).

But if you want a pure Python script you don't need QGIS (standalone script), simply use the module NetworkX (many examples in GIS SE) in combination with the module Shapely

import networkx as nx
G  = nx.read_shp("shapefile.shp")
# transform the directed graph to undirect
G = G.to_undirected()
# check that there is a path between the nodes/points 7 and 22
nx.has_path(G,(110579.17281126765, 116585.26070464966),(111819.28396552203, 116854.75854462344))
True 
# Dijkstra algorithm
nx.dijkstra_path(G,(110579.17281126765, 116585.26070464966),(111819.28396552203, 116854.75854462344))
[(111819,116855), (111576,116688), (111306,116504), (111145,116599), (111005,116681), (110724,116484), (110579,116585)]
# convert to polyline with Shapely
 result = LineString(nx.dijkstra_path(G,(110579.17281126765, 116585.26070464966),(111819.28396552203, 116854.75854462344)))
 print result.wkt
 LineString (111819.28396552200138103 116854.75854462340066675, 111575.63678446662379429 116688.29510413877142128, 111305.62611302707227878 116503.81972814344044309, 111144.6106812154466752 116598.9506020281551173, 111004.94058255387062673 116681.47026111763261724, 110723.93371811544056982 116483.65621838794322684, 110579.17281126769375987 116585.26070464969961904)
 # or specifying a weight
 nx.shortest_path(G,(110579.17281126765, 116585.26070464966),(111819.28396552203, 116854.75854462344),weight='distance')
 [(110579.17281126765, 116585.26070464966), (110723.93371811544, 116483.65621838794), (110996.30352863036, 116292.48585842559), (111305.62611302707, 116503.81972814344), (111575.63678446662, 116688.29510413877), (111819.28396552203, 116854.75854462344)]

enter image description here

And you can use NetworkX, Fiona or pyshp (as Clubdebambos propose) to save the result to a shapefile

Related Question