我想计算沿铁路网从矿山到港口的最短路径。由于矿山和港口不直接在网络上,所以我首先计算出每个矿山和港口最近的铁路点。
但是,我现在正在努力将铁路网络转换为 NetworkX 图,并从那里计算每个矿山和港口之间的最短距离。当我运行代码时,它无法计算出最近的路径,因为所有距离都为零。请参阅下面我迄今为止编写的代码。铁路网络可以从这里下载。如果您能提供任何帮助,我将不胜感激。谢谢你。
# Ports
ports =
[{'port_name': 'Geraldton', 'geometry': POINT (114.59786 -28.77688)},
{'port_name': 'Bunbury', 'geometry': POINT(115.673447 -33.318797)},
{'port_name': 'Albany', 'geometry': POINT(117.895025 -35.032831)},
{'port_name': 'Esperance', 'geometry': POINT(121.897114 -33.871834)}]
# Mine sites
mines =
[{'mine_name': 'Gold', 'geometry': POINT (117.94568 -34.93467),
{'mine_name': 'Silver', 'geometry': POINT (115.16923 -29.65613)},
{'mine_name': 'Bronze', 'geometry': POINT (115.11039 -29.51287)},
{'mine_name': 'Platinum', 'geometry': POINT (115.11130 -29.42621)}]
# Convert to GeoDataFrame
crs = 'EPSG:4326'
ports = gpd.GeoDataFrame(ports, crs=crs, geometry = 'geometry')
mine_sites = gpd.GeoDataFrame(ports, crs=crs, geometry = 'geometry')
# Column for nearest rail point
ports['nearest_rail_point'] = None
mine_sites['nearest_rail_point'] = None
# Nearest rail point
for index, row in ports.iterrows():
port_point = row['geometry']
nearest_point = nearest_points(port_point, rail_network.unary_union)[1]
ports.at[index, 'nearest_rail_point'] = nearest_point
for index, row in mine_sites.iterrows():
mine_site_point = row['geometry']
nearest_point = nearest_points(mine_site_point, rail_network.unary_union)[1]
mine_sites.at[index, 'nearest_rail_point'] = nearest_point
G = momepy.gdf_to_nx(rail_network)
shortest_distances = {}
# Calculate shortest path
for mine_index, mine_row in mines.iterrows():
mine_name = mine_row['mine_name']
mine_point = mine_row['geometry']
shortest_distances[mine_name] = {}
for port_index, port_row in ports.iterrows():
port_name = port_row['port_name']
port_point = port_row['geometry']
try:
shortest_distance = nx.shortest_path_length(G,
source=(mine_point.x, mine_point.y),
target=(port_point.x, port_point.y),
weight='length')
shortest_distances[mine_name][port_name] = shortest_distance
except nx.NetworkXNoPath:
shortest_distances[mine_name][port_name] = float('inf') # No path found
尚不清楚您是否需要每个矿井与其相应端口(同一索引)之间或所有端口之间的最短路径。无论哪种方式,一个选择是使用原始方法(使用
momempy
)来创建图形并计算 shortest_path_length
(或 shortest_path
,具体取决于您的预期输出)。然而,在此之前,您需要将地雷捕捉到最近的铁路边界:
spots = (pd.concat([
ports.rename(columns={"port_name": "spot_name"}),
mine_sites.rename(columns={"mine_name": "spot_name"})])
.to_crs("EPSG:3857"))
import momepy
G = (momepy.gdf_to_nx(
rail_network[["name", "geometry"]].explode(),
approach="primal", multigraph=False, length="dis"))
def nearest_bnd(p, ls, shp=False):
sp, *_, ep = ls.coords
nb = min(map(Point, [sp, ep]), key=p.distance)
return nb if shp else (nb.x, nb.y)
coos = (spots.rename_geometry("geom_sp")
.sjoin_nearest(rail_network.assign(geom_rn=rail_network["geometry"]))
.set_geometry("geom_rn").assign(coo=lambda x: [nearest_bnd(p, ls)
for p, ls in x[["geom_sp", "geom_rn"]].to_numpy()])
.set_index("spot_name")["coo"])
all_spl = {}
for mn in mine_sites["mine_name"]:
for pn in ports["port_name"]:
try:
uv = map(coos.get, [mn, pn])
spl = nx.shortest_path_length(G, *uv, weight="dis")
spl = round(spl / 1000, 2)
except nx.NetworkXNoPath:
spl = float("inf")
all_spl.setdefault(mn, []).append({pn: spl})
{mn: min(d, key=lambda x: list(x.values())[0]) for mn, d in all_spl.items()}
# {
# "Gold": {"Albany": 0.0},
# "Silver": {"Geraldton": 117.85},
# "Bronze": {"Geraldton": 117.85},
# "Platinum": {"Geraldton": 117.85},
# }