在带投影的Matplotlib Basemap中渲染椭圆失败的问题求助
在Basemap投影地图上渲染椭圆的问题
我使用以下代码通过Matplotlib绘制椭圆:
lat = float(ellipse['cy']) lng = float(ellipse['cx']) width = float(ellipse['rx']) / 111111.0 height = float(ellipse['ry']) / 111111.0 rot = float(ellipse['rotation']) # + 180? xpt, ypt = lng, lat if m != None: xpt, ypt = m(lng, lat) ell = Ellipse(xy=(xpt, ypt), width=width*2, height=height*2, angle=rot, edgecolor='black', facecolor='none') ax.add_patch(ell) ax.annotate(ellipse['label'], (xpt, ypt))
用以下代码创建Basemap:
# setup Lambert Conformal basemap. m = Basemap(width=12000000, height=9000000, projection='lcc', resolution='c', lat_1=45., lat_2=55, lat_0=50, lon_0=-107.) # m.shadedrelief() m.drawlsmask(land_color='coral', ocean_color='aqua', lakes=True)
当前椭圆无法渲染显示,但如果不使用Basemap(将m设为None),椭圆可以正常显示。请问在投影地图上渲染椭圆是否需要特殊处理?我使用的环境是Python 3.11.0(Windows 11)、Matplotlib 3.6.2。我曾参考过一篇11年前的相关帖子,但不确定其代码是否仍适用。
解决方案
是的,在Basemap投影地图上渲染椭圆需要特殊处理,核心原因是:地理经纬度上的椭圆经过非线性投影(比如你用的LCC兰伯特投影)后,在地图平面上不再是标准的Matplotlib Ellipse(笛卡尔坐标系下的二次曲线),直接转换中心坐标并使用Ellipse无法正确匹配投影后的形状。
正确的做法是先在经纬度坐标系下生成椭圆的顶点集合,再将这些点转换为Basemap的投影坐标,最后用多边形或路径来绘制:
修改后的代码示例
import numpy as np from matplotlib.patches import Polygon # 读取椭圆参数 lat = float(ellipse['cy']) lng = float(ellipse['cx']) rx_m = float(ellipse['rx']) # 原始单位是米 ry_m = float(ellipse['ry']) rot_deg = float(ellipse['rotation']) # 1. 将米转换为经纬度单位(近似,基于赤道处1度≈111111米) rx_deg = rx_m / 111111.0 ry_deg = ry_m / 111111.0 rot_rad = np.deg2rad(rot_deg) # 2. 在经纬度空间生成椭圆的顶点 theta = np.linspace(0, 2*np.pi, 100) # 取100个点保证平滑 # 椭圆参数方程(考虑旋转) lng_points = lng + rx_deg * np.cos(theta) * np.cos(rot_rad) - ry_deg * np.sin(theta) * np.sin(rot_rad) lat_points = lat + rx_deg * np.cos(theta) * np.sin(rot_rad) + ry_deg * np.sin(theta) * np.cos(rot_rad) # 3. 将经纬度点转换为Basemap投影坐标 if m is not None: x_points, y_points = m(lng_points, lat_points) else: x_points, y_points = lng_points, lat_points # 4. 用Polygon绘制投影后的椭圆形状 ell_poly = Polygon(np.column_stack((x_points, y_points)), edgecolor='black', facecolor='none') ax.add_patch(ell_poly) ax.annotate(ellipse['label'], m(lng, lat) if m is not None else (lng, lat))
关键说明
- 先在经纬度空间生成椭圆顶点:避免投影扭曲导致的形状失真,因为投影是对点的转换,而非对椭圆参数的直接转换。
- 使用足够多的顶点(比如100个):保证投影后的曲线平滑,接近椭圆的真实形状。
- 替换
Ellipse为Polygon:因为投影后的形状不再是标准椭圆,而是由多个顶点连接成的闭合曲线。
内容的提问来源于stack exchange,提问作者Mike Stoddart
相关产品推荐
相关产品推荐

