使用OSMnx绘制小范围Bounding Box时触发ValueError求助
OSMnx+Matplotlib小范围边界框绘图报错解决
问题现象
使用OSMnx结合Matplotlib绘制街区级小范围地理数据时,触发ValueError: aspect must be finite and positive,但切换到较大范围边界框时程序能正常运行。需求是生成包含道路、建筑、水体和铁路轨道的PNG图像。
报错原因定位
从报错堆栈可追踪到核心问题:
- 调用
ox.plot_footprints()时,若传入的featuresGeoDataFrame为空(比如当前小边界范围内没有匹配的水体/道路/铁路要素),gdf.total_bounds会返回全NaN的数组 - 基于NaN值计算
y_coord后,1 / np.cos(y_coord * np.pi / 180)得到非有限值,触发Matplotlib设置轴比例的参数校验错误
修复方案
- 手动初始化Matplotlib画布和轴,避免依赖
ox.plot_footprints()创建绘图环境 - 对每个获取的要素GeoDataFrame做非空检查,仅当存在有效要素时执行绘图
- 提前计算并设置正确的轴比例,确保小范围边界框也能正常渲染
修复后完整代码
import osmnx as ox import matplotlib.pyplot as plt import geopandas as gpd import pandas as pd import os import numpy as np def plot_features_bbox(title="", include_water=True, include_roads=True, include_railways=True, include_buildings=True): # 边界框坐标 north = 50.954088 south = 50.942151 west = 6.913769 east = 6.927888 dpi = 400 figsize = (80, 30) # 手动初始化画布和轴 fig, ax = plt.subplots(figsize=figsize, dpi=dpi) ax.set_facecolor("#FBFBEF") # 设置轴范围 ax.set_xlim(west, east) ax.set_ylim(south, north) # 计算并设置正确的轴比例 y_coord = np.mean([south, north]) ax.set_aspect(1 / np.cos(y_coord * np.pi / 180)) # 颜色和线宽配置 water_color = '#5882FA' road_color = '#688A08' railway_color = '#848484' building_color = '#FE9A2E' road_linewidth = 4.8 railway_linewidth = 2.0 # 绘制水体 if include_water: water = ox.geometries_from_bbox(north, south, east, west, tags={'natural': 'water'}) if not water.empty: water = water[water["geometry"].type.isin({"Polygon", "MultiPolygon"})] water.plot(ax=ax, facecolor=water_color, edgecolor=water_color) # 绘制道路 G = None if include_roads: G = ox.graph_from_bbox(north, south, east, west, network_type='drive', simplify=True, truncate_by_edge=True) if len(G.edges) > 0: ox.plot_graph(G, ax=ax, node_size=0, edge_color=road_color, edge_linewidth=road_linewidth, bgcolor="#FBFBEF", show=False, close=False) # 绘制铁路 railways = None if include_railways: railways = ox.graph_from_bbox(north, south, east, west, network_type='all', simplify=True, retain_all=True, truncate_by_edge=True, clean_periphery=False, custom_filter='["railway"~"rail"]') if len(railways.edges) > 0: ox.plot_graph(railways, ax=ax, node_size=0, edge_color=railway_color, edge_linewidth=railway_linewidth, bgcolor="#FBFBEF", show=False, close=False) # 绘制建筑 if include_buildings: buildings_gdf = ox.geometries_from_bbox(north, south, east, west, tags={'building': True}) if not buildings_gdf.empty: buildings_gdf.plot(ax=ax, facecolor=building_color, alpha=0.7, linewidth=0) # 添加标题文本 ax.text(0.5, 0.1, title, fontsize=10, ha='center', va='center', transform=ax.transAxes, fontname='Courier New', bbox=dict(facecolor='white', edgecolor='black', boxstyle='round,pad=0.6'), color='black') # 添加白色边框 ax.add_patch(plt.Rectangle((west, south), east - west, north - south, fill=False, color='white', linewidth=50)) fig.tight_layout(pad=0) # 保存图像 output_path = r'C:\Users\..' os.makedirs(output_path, exist_ok=True) output_filename = os.path.join(output_path, "ehrenfeld.png") fig.savefig(output_filename, dpi=dpi, format="png", bbox_inches='tight', facecolor=fig.get_facecolor(), transparent=False) plt.close(fig) return output_filename output_filename = plot_features_bbox(title="Hier kann \n dein Text \n stehen.", include_water=True, include_roads=True, include_railways=True, include_buildings=True) print(f"Die Ausgabe wurde in der Datei '{output_filename}' gespeichert.")
关键修复点
- 手动创建画布和轴,直接设置轴范围和比例,规避空GeoDataFrame导致的计算错误
- 对每个地理要素(水体、道路、铁路、建筑)添加非空校验,确保仅在有数据时执行绘图
- 拆分原有的要素合并逻辑,单独处理每个要素的获取与绘制,提升代码健壮性
内容的提问来源于stack exchange,提问作者cc_schr_gis
相关产品推荐
相关产品推荐

