如何从Shapely多边形生成兼容OSMnx的自定义节点NetworkX图
问题描述
我们已有如下Shapely多边形对象:
from shapely import geometry # (纬度, 经度)坐标 p1 = geometry.Point(-96.87,32.88) p2 = geometry.Point(-96.77,33.00) p3 = geometry.Point(-96.67,32.95) p4 = geometry.Point(-96.65,32.84) pointList = [p1, p2, p3, p4, p1] # 创建多边形对象 p = geometry.Polygon([[p.x, p.y] for p in pointList])
通常我们会用OSMnx从该多边形生成真实路网的NetworkX图:
import osmnx as ox G = ox.graph.graph_from_polygon(p, network_type='drive', simplify=False)
但现在需要生成虚拟路网:在多边形内随机分布指定数量的节点,每个节点至少与指定数量的最近邻居相连,生成的图需兼容OSMnx功能(如可视化),需实现如下函数:
def f_generate_plain_polygon(p, number_of_nodes, min_number_of_connection_for_each_node): ...
也可通过指定节点间距替代节点数来实现。
解决方案
实现思路
- 在多边形边界范围内生成随机采样点,筛选出位于多边形内部的节点
- 计算每个节点到其他节点的欧氏距离,选取最近的指定数量邻居
- 构建NetworkX有向图,添加OSMnx兼容的节点/边属性,确保可直接使用OSMnx工具
完整代码实现
import numpy as np import networkx as nx import osmnx as ox import matplotlib.pyplot as plt from shapely.geometry import Point, Polygon def f_generate_plain_polygon(p, number_of_nodes, min_number_of_connection_for_each_node): # 获取多边形的边界范围 min_x, min_y, max_x, max_y = p.bounds # 生成多边形内的随机节点 nodes = [] while len(nodes) < number_of_nodes: # 生成随机坐标 x = np.random.uniform(min_x, max_x) y = np.random.uniform(min_y, max_y) point = Point(x, y) # 验证点是否在多边形内部 if p.contains(point): nodes.append((x, y)) # 初始化兼容OSMnx的有向图 G = nx.DiGraph() # 添加节点并设置OSMnx所需属性 for idx, (x, y) in enumerate(nodes): G.add_node( idx, x=x, y=y, osmid=idx, ref=None, highway=None, node_id=idx ) # 计算节点间距离并添加边 nodes_array = np.array(nodes) for i in range(number_of_nodes): # 计算当前节点到所有其他节点的欧氏距离 distances = np.linalg.norm(nodes_array - nodes_array[i], axis=1) # 按距离排序,排除节点自身 sorted_neighbor_indices = np.argsort(distances)[1:] # 选取前N个最近邻居(N为指定的最小连接数) target_neighbors = sorted_neighbor_indices[:min_number_of_connection_for_each_node] # 添加双向边(模拟路网双向通行) for neighbor_idx in target_neighbors: edge_length = distances[neighbor_idx] # 正向边 G.add_edge( i, neighbor_idx, osmid=f"{i}-{neighbor_idx}", length=edge_length, highway='unclassified', oneway=False ) # 反向边 G.add_edge( neighbor_idx, i, osmid=f"{neighbor_idx}-{i}", length=edge_length, highway='unclassified', oneway=False ) # 移除孤立节点 ox.utils_graph.remove_isolated_nodes(G) return G # 测试示例 if __name__ == "__main__": # 创建示例多边形 p1 = Point(-96.87,32.88) p2 = Point(-96.77,33.00) p3 = Point(-96.67,32.95) p4 = Point(-96.65,32.84) pointList = [p1, p2, p3, p4, p1] p = Polygon([[point.x, point.y] for point in pointList]) # 生成含60个节点、每个节点至少3个连接的虚拟路网 G = f_generate_plain_polygon(p, number_of_nodes=60, min_number_of_connection_for_each_node=3) # 使用OSMnx可视化 fig, ax = ox.plot_graph( G, show=False, close=False, edge_color='black', bgcolor='w', edge_alpha=0.5, node_color='black', node_size=30 ) plt.show()
关键说明
- 节点有效性:通过
p.contains(point)确保所有生成的节点都在目标多边形内部 - OSMnx兼容性:为节点添加
x、y、osmid,为边添加length、highway等属性,完全适配OSMnx的可视化和分析接口 - 双向边设计:生成双向边模拟真实路网的通行逻辑,符合OSMnx对路网图的默认要求
- 节点间距替代方案:若要改用节点间距控制生成,可先按间距生成网格点,再对每个网格点添加随机扰动,最终筛选多边形内的节点即可
内容的提问来源于stack exchange,提问作者illuminato
相关产品推荐
相关产品推荐

