如何用GeoDataFrame点与线构建NetworkX图?解决momepy节点异常
问题分析与解决方案
节点异常原因
momepy.gdf_to_nx默认仅提取线要素的起点和终点作为图的节点,不会自动识别线中间的顶点。所以即使你的线由29个点构成,工具只会把首尾两个点当作节点,这就是仅生成2个节点的核心原因。
正确构建方法
根据你的实际需求,分两种场景处理:
场景1:将线的所有顶点作为图节点
如果需要让图包含线的全部顶点,需先把原始线要素拆分成多个首尾衔接的线段(每两个连续顶点组成一条线段),再用momepy转换:
import geopandas as gpd from shapely.geometry import LineString import momepy import networkx as nx # 假设你的公交线路GeoDataFrame名为lines_gdf split_segments = [] for _, row in lines_gdf.iterrows(): coords = list(row.geometry.coords) # 遍历连续坐标对,生成单条线段 for i in range(len(coords) - 1): split_segments.append({ 'geometry': LineString([coords[i], coords[i+1]]), # 保留原线路属性,比如线路ID 'line_id': row['line_id'] }) # 生成拆分后的线段GeoDataFrame split_lines_gdf = gpd.GeoDataFrame(split_segments, crs=lines_gdf.crs) # 转换为NetworkX图 G = momepy.gdf_to_nx(split_lines_gdf)
拆分后,每条线段的首尾顶点会被momepy自动合并为同一个节点,最终图的节点将和线的所有顶点一一对应。
场景2:将站点(点要素)作为图节点(更符合公交网络逻辑)
如果你的需求是构建以站点为节点、公交线路为边的网络,直接基于站点和线路构建更合理:
import geopandas as gpd import networkx as nx # 假设站点GeoDataFrame为stops_gdf(含stop_id字段),线路GeoDataFrame为lines_gdf(含line_id字段) # 1. 空间匹配:给每个站点关联所属线路 stops_gdf = gpd.sjoin(stops_gdf, lines_gdf, how='left', predicate='within') # 2. 按站点在线路上的距离排序,确定站点顺序 def get_distance_along_line(row): line_geom = lines_gdf[lines_gdf['line_id'] == row['line_id']].iloc[0].geometry return line_geom.project(row.geometry) stops_gdf['distance'] = stops_gdf.apply(get_distance_along_line, axis=1) stops_gdf = stops_gdf.sort_values(['line_id', 'distance']) # 3. 构建NetworkX图 G = nx.Graph() # 添加站点节点 for _, row in stops_gdf.iterrows(): G.add_node( row['stop_id'], geometry=row.geometry, stop_name=row.get('stop_name', '') # 可添加其他站点属性 ) # 添加线路边(相邻站点之间创建边) for line_id, group in stops_gdf.groupby('line_id'): stop_ids = group['stop_id'].tolist() for i in range(len(stop_ids) - 1): G.add_edge(stop_ids[i], stop_ids[i+1], line_id=line_id)
这种方式构建的网络完全贴合实际公交站点布局,更符合业务需求。
内容的提问来源于stack exchange,提问作者Lea
相关产品推荐
相关产品推荐

