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

在带投影的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:45:34