You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于OSMnx批量计算海量Quadkey 14瓦片街道密度的技术咨询

批量计算Quadkey 14瓦片街道密度的可行方案

一、先下载Quadkey 9大图再提取子瓦片的方案完全可行

这种"一次性下载大区域路网+本地切割子图"的思路,能直接解决你原方案中500万次请求的效率问题,同时完全契合你想用官方basic_stats()的需求。

二、具体操作步骤

1. 把Quadkey转换为地理边界

用quadkey库将Quadkey编码转成经纬度范围,9级或14级瓦片都适用:

import quadkey

# 转换单个Quadkey 9为边界(示例)
qk9 = quadkey.QuadKey("你的Quadkey9编码")
bbox9 = qk9.to_geo()  # 返回格式:(min_lon, min_lat, max_lon, max_lat)

# 批量转换所有Quadkey 14的边界
all_qk14_bboxes = []
for qk_str in 你的Quadkey14列表:
    qk = quadkey.QuadKey(qk_str)
    all_qk14_bboxes.append((qk_str, qk.to_geo()))

2. 下载Quadkey 9范围的路网并提前投影

一次性下载大区域路网,然后投影到墨卡托CRS(和basic_stats()默认使用的坐标系一致),避免后续重复投影浪费时间:

import osmnx as ox

# 下载路网,按需设置network_type(比如drive/walk/bike)
G = ox.graph_from_bbox(bbox9[3], bbox9[1], bbox9[2], bbox9[0], network_type="drive")
# 投影到墨卡托CRS
G_proj = ox.project_graph(G)

3. 批量裁剪子图并计算密度

遍历所有Quadkey 14的边界,从已投影的大图中裁剪出对应子图,直接调用basic_stats():

stats_results = []
for qk_str, bbox14 in all_qk14_bboxes:
    # 裁剪子图
    G_sub = ox.truncate.truncate_graph_bbox(G_proj, bbox14[3], bbox14[1], bbox14[2], bbox14[0])
    # 计算统计值,空图会返回默认值,可按需过滤
    sub_stats = ox.basic_stats(G_sub)
    sub_stats["quadkey14"] = qk_str
    stats_results.append(sub_stats)

三、关于OSMnx多请求的问题

这个方案只需要发起1次(或少量几次,如果你需要覆盖多个Quadkey9区域)下载请求,后续全是本地操作,完全不需要处理多请求的频率限制。如果确实需要下载多个大区域,提前配置OSMnx的请求参数即可:

ox.config(requests_timeout=120, retry_delay=5, max_retries=10)

四、解释GeoDataFrame方法的差异问题

你之前遇到的length列和墨卡托长度不符的问题,是因为OSMnx边的length字段是WGS84球面距离,而墨卡托下的几何长度是平面距离,两者本身就有差异。basic_stats()里的street_density_km是用投影后的平面长度计算的,所以如果想用GeoDataFrame方法对齐结果,必须统一用墨卡托的平面长度和面积:

import geopandas as gpd
from shapely.geometry import box

# 把大图转成边的GeoDataFrame(已投影)
edges_proj = ox.graph_to_gdfs(G_proj, nodes=False, edges=True)

for qk_str, bbox14 in all_qk14_bboxes:
    # 把子瓦片边界转成GeoDataFrame并投影到同一CRS
    bbox_poly = box(bbox14[0], bbox14[1], bbox14[2], bbox14[3])
    bbox_gdf = gpd.GeoDataFrame({"geometry": [bbox_poly]}, crs="EPSG:4326").to_crs(G_proj.graph["crs"])
    # 筛选和子瓦片相交的边
    edges_sub = edges_proj[edges_proj.intersects(bbox_gdf.iloc[0]["geometry"])]
    # 计算总长度(转千米)和面积(转平方千米)
    total_length_km = edges_sub["geometry"].length.sum() / 1000
    area_km2 = bbox_gdf["geometry"].area.iloc[0] / 10**6
    # 密度计算
    density = total_length_km / area_km2

不过还是推荐你用子图裁剪+basic_stats()的方式,完全贴合官方实现,不用手动处理细节,误差更小。

内容的提问来源于stack exchange,提问作者Luca Ceribelli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 00:27:03