假设我有一个带有起点和终点的点 shapefile。
1) 如何使用 nx.shortest_path 计算每个起点和终点?2)如何将对应的路由保存为shapefile?我已经检查了使用 Python OSMnx 保存路线并保存其曲率,它显示了如何为路线获取 MultiLineString,但没有显示如何导出路线。
假设我有一个带有起点和终点的点 shapefile。
1) 如何使用 nx.shortest_path 计算每个起点和终点?2)如何将对应的路由保存为shapefile?我已经检查了使用 Python OSMnx 保存路线并保存其曲率,它显示了如何为路线获取 MultiLineString,但没有显示如何导出路线。
感谢@gboeing 的步骤。还添加了对我有用的代码片段来实现概述的解决方案。
from shapely.geometry import shape
from shapely.geometry import LineString
from osgeo import ogr, osr
import geopandas as gpd
import pandas as pd
import time
import networkx as nx
import osmnx as ox
G= ox.graph_from_place('Bangalore, India')
fig, ax = ox.plot_graph(G)
#Read the Origin-Destination csv
od_table = 'E:/OD_pairs1.csv'
df = pd.read_csv(od_table)
这是我的输入 CSV 与 Origin (o_long, o_lat) 和 Destination (d_long, d_lat) 点坐标的样子:
df
Out[]: o_id o_long o_lat d_id d_long d_lat
o1 77.548349 12.996800 d1 77.554137 12.995225
o2 77.555820 13.009082 d2 77.570458 12.995690
o3 77.576325 13.014630 d3 77.583616 13.009188
o4 77.564848 12.990121 d4 77.551316 12.988570
o5 77.590529 12.992340 d5 77.598469 12.988289
答案的第 1 部分(计算路线的方法):(在方法shortestpath()
中,您可能希望返回length
变量,而不是total_length
如果您不希望从 O & D 点到最近的网络节点的距离被添加到路线长度中。 )
def nodes_to_linestring(path):
coords_list = [(G.nodes[i]['x'], G.nodes[i]['y']) for i in path ]
#print(coords_list)
line = LineString(coords_list)
return(line)
def shortestpath(o_lat, o_long, d_lat, d_long):
nearestnode_origin, dist_o_to_onode = ox.distance.get_nearest_node(G, (o_lat, o_long), method='haversine', return_dist=True)
nearestnode_dest, dist_d_to_dnode = ox.distance.get_nearest_node(G, (d_lat, d_long), method='haversine', return_dist=True)
#Add up distance to nodes from both o and d ends. This is the distance that's not covered by the network
dist_to_network = dist_o_to_onode + dist_d_to_dnode
shortest_p = nx.shortest_path(G,nearestnode_origin, nearestnode_dest)
route = nodes_to_linestring(shortest_p) #Method defined above
# Calculating length of the route requires projection into UTM system.
inSpatialRef = osr.SpatialReference()
inSpatialRef.ImportFromEPSG(4326)
outSpatialRef = osr.SpatialReference()
outSpatialRef.ImportFromEPSG(32643)
coordTransform = osr.CoordinateTransformation(inSpatialRef, outSpatialRef)
#route.wkt returns wkt of the shapely object. This step was necessary as transformation can be applied
#only on an ogr object. Used EPSG 32643 as Bangalore is in 43N UTM grid zone.
geom = ogr.CreateGeometryFromWkt(route.wkt)
geom.Transform(coordTransform)
length = geom.Length()
#Total length to be covered is length along network between the nodes plus the distance from the O,D points to their nearest nodes
total_length = length + dist_to_network
#in metres
return(route, total_length )
在数据帧上应用上述方法来获取所有 OD 对的最短路径的几何形状和长度:
start_time = time.time()
df['osmnx_geometry'] = df.apply(lambda x: shortestpath(x['o_lat'], x['o_long'], x['d_lat'], x['d_long'])[0] , axis=1)
df['osmnx_length'] = df.apply(lambda x: shortestpath(x['o_lat'], x['o_long'], x['d_lat'], x['d_long'])[1] , axis=1)
print("Time taken: ", (time.time() - start_time), "seconds")
生成的数据框将具有路线的相关几何形状和路线长度(以米为单位):
df
Out[]:
o_id o_long o_lat d_id d_long d_lat osmnx_geometry osmnx_length
o1 77.548349 12.996800 d1 77.554137 12.995225 LINESTRING (77.5482836 12.9966618, 77.54976259... 827.718256
o2 77.555820 13.009082 d2 77.570458 12.995690 LINESTRING (77.555814 13.0090627, 77.5556026 1... 2588.006507
o3 77.576325 13.014630 d3 77.583616 13.009188 LINESTRING (77.57588320000001 13.0146859, 77.5... 1107.137060
o4 77.564848 12.990121 d4 77.551316 12.988570 LINESTRING (77.56473080000001 12.9898858, 77.5... 1744.708360
o5 77.590529 12.992340 d5 77.598469 12.988289 LINESTRING (77.5901456 12.9920295, 77.5905355 ... 1097.493520
答案的第 2 部分。将此数据框保存为 shapefile:
df = df.rename(columns = {'osmnx_geometry': 'geometry'})
gpdf = gpd.GeoDataFrame(df, geometry =df['geometry'])
gpdf.to_file('osmnx_shortestpaths.shp')
我还探索了 OSRM(用于最快路线)和 Gmaps Directions API(用于基于流量的最有效路线)来计算同一组 OD 对的路线,可以在此处找到相同的脚本。
以下步骤将起作用: