GeoDataFrame中构建100米分辨率可顺序索引米制网格的实现方法
100m分辨率米制空间网格实现方案
核心逻辑说明
经纬度坐标系(EPSG:4326)以角度为单位,既无法精准换算100m对应的实际边长,也不符合“不依托经纬度构建网格”的要求。整套实现流程完全基于米制投影坐标系完成,全程不涉及经纬度间隔的换算逻辑。
步骤1:转换为米制投影坐标系
osmnx内置了自动匹配UTM投影的工具,无需手动计算研究区域对应的投影带号,直接将路网节点转换为米制单位的投影坐标系:
# 自动将经纬度格式的路网节点转换为匹配研究区域的UTM投影 nodes_proj = ox.projection.project_gdf(nodes) # 获取投影后的整体空间边界(单位:米) xmin, ymin, xmax, ymax = nodes_proj.total_bounds
转换完成后,所有坐标的数值单位为米,后续网格计算全部基于该坐标系开展,完全脱离经纬度单位的约束。
步骤2:生成100m×100m均匀网格
直接在投影坐标系的空间边界内,按100m的固定边长切分网格:
grid_resolution = 100 # 网格边长,单位米 # 生成x、y方向的网格线坐标序列 x_lines = np.arange(xmin, xmax + grid_resolution, grid_resolution) y_lines = np.arange(ymin, ymax + grid_resolution, grid_resolution) # 批量生成网格面要素 grid_geoms = [] for x_start in x_lines: for y_start in y_lines: # 构建单个100m×100m的矩形网格 grid_poly = Polygon([ (x_start, y_start), (x_start + grid_resolution, y_start), (x_start + grid_resolution, y_start + grid_resolution), (x_start, y_start + grid_resolution) ]) grid_geoms.append(grid_poly) # 构建网格GeoDataFrame,与路网节点保持一致的投影坐标系 grid_gdf = gpd.GeoDataFrame(geometry=grid_geoms, crs=nodes_proj.crs)
步骤3:按规则分配连续Cell_ID
编号逻辑严格匹配需求:最左上角的网格Cell_ID为1,同一排内从左到右ID依次递增,排完最上方一整排后,向下一排继续延续连续编号。
实现排序时以两个维度为依据:
- 第一优先级:网格中心点的y值,按从大到小排序(UTM投影坐标系中y值越大,位置越靠北,对应可视化视图中越靠上的位置)
- 第二优先级:网格中心点的x值,按从小到大排序(UTM投影坐标系中x值越小,位置越靠西,对应可视化视图中越靠左的位置)
对应代码:
# 计算每个网格的中心点坐标作为排序依据 grid_gdf["center_x"] = grid_gdf.geometry.centroid.x grid_gdf["center_y"] = grid_gdf.geometry.centroid.y # 按指定规则排序 grid_gdf = grid_gdf.sort_values( by=["center_y", "center_x"], ascending=[False, True] # y值降序、x值升序 ).reset_index(drop=True) # 生成连续唯一ID,从1开始计数 grid_gdf["Cell_ID"] = grid_gdf.index + 1
效果校验:排序结果中第一个单元格就是位置最靠上、最靠左的网格,即左上角单元格,ID为1;它右侧相邻的同排网格为第二个排序项,ID为2,与需求示例完全一致。
步骤4:可视化验证
将网格与路网节点叠合展示,可选择在网格中心标注Cell_ID,检查排序逻辑是否符合预期:
fig, ax = plt.subplots(figsize=(12, 8)) # 绘制半透明红色虚线边框的网格 grid_gdf.plot(ax=ax, facecolor="none", edgecolor="tab:red", linestyle="--", lw=0.5) # 绘制黑色路网节点 nodes_proj.plot(ax=ax, color="tab:black", markersize=4) # 可选:在网格中心标注Cell_ID for _, cell in grid_gdf.iterrows(): ax.text( cell["center_x"], cell["center_y"], str(cell["Cell_ID"]), fontsize=7, ha="center", va="center" ) ax.set_title("100m分辨率空间网格(带连续编号)") plt.tight_layout() plt.show()
原有实现的问题说明:之前直接通过经纬度间隔切分网格的逻辑,本质仍依托经纬度坐标开展计算,且不同纬度下经纬度1度对应的实际地面距离差异极大,无法精准实现100m×100m的网格尺寸要求。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

