matplotlib用plt.axis('equal')后如何自动适配坐标轴至数据
问题根源
当前出现坐标轴内大量留白、需要手动调整尺寸匹配数据的问题,是两个机制叠加导致的:
- 你手动通过
fig.add_axes([.1, .1, .465, .8])硬指定了axes外框的宽高比,这个比例和你读取的卫星数据实际覆盖的经纬度范围的地理比例不匹配 - 开启等比例坐标轴设置后,matplotlib会强制保证横纵轴刻度的1:1显示比例,不会拉伸图形变形,因此会在你硬指定的axes外框内,将实际绘图区域收缩到刚好满足等比例要求的大小,周围就会留下大量无意义的空白,也就是你看到的效果
自动适配的可落地方案
方案1:放弃硬编码axes位置,使用自动布局(最推荐)
完全不需要手动计算、试错调整轴的尺寸,只需要把手动创建axes的代码替换为常规子图创建,配合自动布局即可:
- 用
fig, ax = plt.subplots()替代硬写坐标的add_axes,只需要给一个大概的画布尺寸即可 - 用
ax.set_aspect('equal')替代全局的plt.axis('equal'),功能完全一致 - 最后调用
fig.tight_layout(),matplotlib会自动计算满足等比例要求的最优边距,消除多余留白
对应调整后的代码:
src = rasterio.open('imagem_teste.tif') red = src.read(1) fig, ax = plt.subplots(figsize=(8, 6)) ax.pcolor(lon_mtx, lat_mtx, red, cmap='jet', shading='auto') ax.set_aspect('equal') ax.set_xlabel('Longitude') ax.set_ylabel('Latitude') fig.tight_layout()
方案2:必须使用自定义axes时,通过数据范围计算匹配的宽高比
如果有特殊需求必须保留add_axes的自定义位置,不需要手动试错调整尺寸,可以先根据影像的实际经纬度范围,计算出匹配的axes宽高比,让坐标轴区域刚好适配等比例要求:
- 先读取经纬度网格的极值,计算数据覆盖的横向、纵向范围差值
- 让axes的宽高比和这个范围差值的比例完全一致,开启等比例时绘图区域就会完全填满axes,不会出现收缩留白
对应代码逻辑:
# 计算影像的实际坐标范围 x_min, x_max = lon_mtx.min(), lon_mtx.max() y_min, y_max = lat_mtx.min(), lat_mtx.max() data_aspect = (x_max - x_min) / (y_max - y_min) # 固定axes的纵向起始位置、底部边距、纵向高度,根据数据比例自动计算横向宽度 ax = fig.add_axes([left=0.1, bottom=0.1, width=0.8 * data_aspect, height=0.8]) ax.pcolor(lon_mtx, lat_mtx, red, cmap='jet', shading='auto') ax.set_aspect('equal') ax.set_xlabel('Longitude') ax.set_ylabel('Latitude')
方案3:针对rasterio读入影像的最优实践
因为你的数据是rasterio读取的卫星影像,完全不需要手动生成lon_mtx/lat_mtx坐标网格,可以直接使用rasterio自带的绘图接口,它已经内置了坐标自动匹配、等比例适配的逻辑,从根源上避免手动调整的问题:
import rasterio.plot src = rasterio.open('imagem_teste.tif') fig, ax = plt.subplots(figsize=(8, 6)) # 直接读取影像的变换矩阵生成坐标范围,自动开启等比例 rasterio.plot.show(src, ax=ax, cmap='jet') ax.set_xlabel('Longitude') ax.set_ylabel('Latitude') fig.tight_layout()
小提示:如果你使用的是经纬度地理坐标系,高纬度区域1度经度对应的实际地表距离和1度纬度的距离存在偏差,常规的等比例设置会按1:1的刻度比例显示,如果需要更准确的地理投影比例,可以配合cartopy设置对应投影,普通可视化场景不需要额外处理。
内容的提问来源于stack exchange,提问作者Guto Schettini
相关产品推荐
相关产品推荐

