基于Python的OSMnx库查找距离边指定范围的最近点
解决OSMnx中点与边的关联及半径范围统计问题
嘿,我来帮你搞定这个需求!咱们一步步拆解,结合OSMnx和Shapely就能轻松实现你要的功能——把经纬度点关联到指定边,筛选出半径范围内的点,还能可视化统计。
核心思路
你提到已知边连接的节点经纬度,那这条边其实就是两个节点之间的线段(OSMnx里用LineString几何对象表示)。我们需要:
- 用节点坐标创建边的几何对象
- 计算每个点到这条边的距离(转成米为单位更准确)
- 筛选出半径范围内的点并统计数量
- 可视化绘制边、点和半径圆
步骤1:创建边的几何对象
首先,把已知的两个节点经纬度转换成Shapely的LineString。注意Shapely的坐标顺序是**(经度, 纬度)**,和我们常用的(lat, lon)反过来,别搞混了!
from shapely.geometry import LineString # 替换成你实际的节点经纬度 node1_lon, node1_lat = -122.4194, 37.7749 # 节点1:lon在前,lat在后 node2_lon, node2_lat = -122.4074, 37.7817 # 节点2 # 创建边的几何对象 edge_geom = LineString([(node1_lon, node1_lat), (node2_lon, node2_lat)])
如果你的边是从OSMnx的路网图(graph)里来的,其实可以直接提取边的几何,不用手动创建:
import osmnx as ox # 假设你已经有了路网图G,u和v是边的两个节点ID edge_geom = G.edges[(u, v, 0)]['geometry'] # 第三个参数是边的索引,通常为0
步骤2:筛选半径范围内的点
因为WGS84坐标系(经纬度)的距离是度数,没法直接用米来判断,所以我们先把几何对象投影到UTM坐标系(自动适配所在区域,单位是米)。然后遍历所有点,计算到边的距离,筛选出符合条件的点。
import osmnx as ox from shapely.geometry import Point # 替换成你的点列表,格式是[(lat1, lon1), (lat2, lon2), ...] points_list = [(37.776, -122.415), (37.778, -122.412), (37.779, -122.410)] # 把边的几何投影到UTM坐标系,得到米为单位的几何和对应的CRS edge_geom_utm, crs = ox.projection.project_geometry(edge_geom, to_crs=None) # to_crs=None自动选UTM # 设置你的半径(单位:米) radius_x = 50 # 比如50米 # 筛选符合条件的点 nearby_points = [] for lat, lon in points_list: # 创建点的几何对象(注意坐标顺序是lon, lat) point_geom = Point(lon, lat) # 把点投影到同一个UTM坐标系 point_geom_utm, _ = ox.projection.project_geometry(point_geom, to_crs=crs) # 计算点到边的距离(米) distance = point_geom_utm.distance(edge_geom_utm) # 判断是否在半径内 if distance <= radius_x: nearby_points.append((lat, lon)) # 统计数量 print(f"距离目标边{radius_x}米内的点共有:{len(nearby_points)}个")
步骤3:可视化绘制
用Matplotlib把边、所有点、附近的点以及半径圆画出来,直观展示结果:
import matplotlib.pyplot as plt # 把所有点和附近的点转换成UTM坐标 all_points_utm = [ox.projection.project_geometry(Point(lon, lat), to_crs=crs)[0] for lat, lon in points_list] nearby_points_utm = [ox.projection.project_geometry(Point(lon, lat), to_crs=crs)[0] for lat, lon in nearby_points] # 创建画布 fig, ax = plt.subplots(figsize=(10, 10)) # 绘制目标边 x_edge, y_edge = edge_geom_utm.xy ax.plot(x_edge, y_edge, color='darkblue', linewidth=3, label='目标边') # 绘制所有点(灰色) for p in all_points_utm: ax.scatter(p.x, p.y, color='gray', s=15, alpha=0.5) # 绘制附近的点(红色)和对应半径圆 for idx, p in enumerate(nearby_points_utm): ax.scatter(p.x, p.y, color='crimson', s=30, label='范围内的点' if idx == 0 else "") # 绘制半径圆 circle = plt.Circle((p.x, p.y), radius_x, color='crimson', fill=False, linestyle='--', linewidth=1.5) ax.add_patch(circle) # 设置绘图样式 ax.legend() ax.set_aspect('equal') # 保持坐标比例,避免圆变椭圆 plt.title(f"目标边周围{radius_x}米范围内的点分布") plt.show()
小提示
- 如果你的点数量特别多,可以用GeoPandas把点转成GeoDataFrame,然后用空间查询批量计算,效率更高。
- 确保所有几何对象都在同一个坐标系下计算距离,UTM是最适合米级距离计算的选择。
内容的提问来源于stack exchange,提问作者Mateo Valencia
相关产品推荐
相关产品推荐

