- 积分
- 25770
- 贡献
-
- 精华
- 在线时间
- 小时
- 注册时间
- 2017-9-4
- 最后登录
- 1970-1-1
|
登录后查看更多精彩内容~
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
本帖最后由 灭火器 于 2023-11-20 23:08 编辑
指北针的箭头可以用一黑一白两个三角形拼在一起来模拟,再在箭头尖端标注 N 字。
首先确定两个三角形的大小:以箭头的凹陷处为 (0, 0),设箭头初始指向 x 轴正方向,那么上半部分三角形顶点的坐标可以设为 [(0, 0), (2, 0), (-1, 1), (0, 0)],下半部分根据对称性如法炮制。然后用这些顶点构造出两个 matplotlib 的 Path 对象,再打包构造成 PathCollection,就得到了一个代表箭头的 Artist 对象。
我希望箭头的大小比例不受 Axes 或 GeoAxes 的影响,所以选择了跟文字一样的单位:point。同时希望指北针的横纵坐标用 Axes 坐标表示,这样的话 add_compass(ax, 0.5, 0.5) 就能在地图正中间放置指北针。因此为 PathCollection 设计这样的 Transform:
- trans = ax.figure.dpi_scale_trans + rotation + translation
复制代码 第一项表示物理坐标系;第二项是 Affine2D().rotate_deg(angle),决定指北针的角度;第三项是 ScaledTranslation,能将 (0, 0) 处的指北针平移到 Axes 坐标系里 (x, y) 的位置。
指北针的角度可以手动指定,也可以从地图上计算得来,方法是先将 (x, y) 换算成 (lon, lat),再计算出 data 坐标系中 (lon, lat) 和 (lon, lat + 1) 两点间连线的角度,最后将这个角度直接用于物理坐标系。
效果如下面两图所示
具体代码为:
- import math
- from matplotlib.path import Path
- from matplotlib.collections import PathCollection
- from matplotlib.transforms import Affine2D, ScaledTranslation
- from cartopy.crs import PlateCarree
- from cartopy.mpl.geoaxes import GeoAxes
- def add_compass(ax, x, y, angle=None, size=20):
- '''
- 向Axes添加指北针.
- x和y是指北针的横纵坐标, 基于axes坐标系.
- 指北针的方向, 从x轴逆时针方向算起, 单位为度.
- 当ax是GeoAxes时默认自动计算角度, 否则默认表示90度.
- size是指北针的大小, 单位为点(point).
- '''
- if angle is None:
- if isinstance(ax, GeoAxes):
- crs = PlateCarree()
- axes_to_data = ax.transAxes - ax.transData
- x0, y0 = axes_to_data.transform((x, y))
- lon0, lat0 = crs.transform_point(x0, y0, ax.projection)
- lon1, lat1 = lon0, min(lat0 + 1, 90)
- x1, y1 = ax.projection.transform_point(lon1, lat1, crs)
- angle = math.degrees(math.atan2(y1 - y0, x1 - x0))
- else:
- angle = 90
- rotation = Affine2D().rotate_deg(angle)
- translation = ScaledTranslation(x, y, ax.transAxes)
- trans = ax.figure.dpi_scale_trans + rotation + translation
- head = size / 72
- width = axis = head * 2 / 3
- verts1 = [(0, 0), (axis, 0), (axis - head, width / 2), (0, 0)]
- verts2 = [(0, 0), (axis - head, -width / 2), (axis, 0), (0, 0)]
- paths = [Path(verts1), Path(verts2)]
- pc = PathCollection(
- paths,
- facecolors=['k', 'w'],
- edgecolors='k',
- linewidths=1,
- zorder=3,
- clip_on=False,
- transform=trans
- )
- ax.add_collection(pc)
- pad = head / 3
- ax.text(
- axis + pad, 0, 'N',
- fontsize=size / 1.5,
- ha='center', va='center',
- rotation=angle - 90,
- transform=trans
- )
复制代码
|
|