python - 如何使用 Matplotlib 在不同的投影中绘制 Tissot 指标线?

标签 python matplotlib cartopy

这是我关于堆栈溢出的第一个问题,我希望有人可以帮助我:)

我想使用 PlateCaree 和 Mercator 投影在 matplotlib 中投影地球表面,并向其添加小圆圈以获得天梭指示线。

我查了很多资料,但在网上找不到正确的答案。到目前为止,我可以画出我的圆圈,但它们保持不变,并且没有像预期的那样拉伸(stretch)。这是我到目前为止所拥有的:

import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import math

def main():
    # Setting values
    proj = ccrs.PlateCarree()
    lonW = -90
    lonE = 90
    latS = -90
    latN = 90
    cLat = (latN + latS) / 2
    cLon = (lonW + lonE) / 2
    res = '110m'

    fig = plt.figure(figsize=(11, 8.5))
    ax = plt.subplot(1, 1, 1, projection=proj)
    ax.gridlines( draw_labels=True, linewidth=2, color='gray', alpha=0.5, linestyle='--')
    ax.set_extent([lonW, lonE, latS, latN], crs=proj)
    ax.coastlines(resolution=res, color='black')

    ax.add_feature(cfeature.LAND)
    ax.add_feature(cfeature.OCEAN)
    ax.add_feature(cfeature.BORDERS, linestyle='-', linewidth=0.5)
    ax.add_feature(cfeature.LAKES)

    # Adding a single coordinate
    ax.scatter(24.3, 61.83, color='red', marker='o', s=6, transform=proj, label='Hyytiälä')

    # Adding first circle
    center_lon, center_lat = 0, 0
    r = 10
    ax.add_patch(mpatches.Circle(xy=[center_lon, center_lat], radius=r, color='red', alpha=0.3, transform=proj, zorder=30))

    # Adding a second circle
    center_lon, center_lat = 0, 30
    r = 10
    ax.add_patch(mpatches.Circle(xy=[center_lon, center_lat], radius=r, color='red', alpha=0.3, transform=proj, zorder=30))

    # Adding a third circle
    center_lon, center_lat = 0, 60
    r = 10
    ax.add_patch(mpatches.Circle(xy=[center_lon, center_lat], radius=r, color='red', alpha=0.3, transform=proj, zorder=30))

    # Adding a last circle
    center_lon, center_lat = 0, 90
    r = 10
    ax.add_patch(mpatches.Circle(xy=[center_lon, center_lat], radius=r, color='red', alpha=0.3, transform=proj, zorder=30))

非常感谢:)

最佳答案

Cartopy 已经将此内置函数作为任何轴上的专用方法,因此更简单的方法是:

import matplotlib.pyplot as plt
import matplotlib as mpl
import cartopy.crs as ccrs

config = {
    "Plate Carree": dict(projection=ccrs.PlateCarree()),
    "Mercator": dict(projection=ccrs.Mercator()),
}

layout = [[name] for name in config.keys()]

fig, axs = plt.subplot_mosaic(
    layout, figsize=(6,9), facecolor="w", dpi=100, 
    layout="compressed", per_subplot_kw=config, height_ratios=[1.2,2],
)

for name, ax in axs.items():
    
    ax.coastlines()
    ax.set_title(name)
    ax.tissot(alpha=.3, fc="C3")

enter image description here

我不确定这是否是您想要的,您可以通过绘制圆圈来手动完成,如下所示。为此,您可以使用以下代码替换 ax.tissot() ,或多或少地使用您已定义的点:

from shapely.geometry import Polygon
from cartopy.geodesic import Geodesic
    # in the axes loop:
    for lon, lat, r in [
        (0,0,10*110000),
        (0,30,10*110000),
        (0,60,10*110000),
        (0,89,10*110000), # 90° has a height of 0
    ]:

        circle_points = Geodesic().circle(lon=lon, lat=lat, radius=r)
        ax.add_geometries(
            (Polygon(circle_points),), facecolor='C3', alpha=.5,
            crs=ccrs.PlateCarree(),
        )

半径应以米为单位,我使用 10 度的半径粗略地定义为每度 110000 米。

enter image description here

编辑:这是 Cartopy 使用的自动和更多手动方法的示例:

from shapely.geometry import Polygon
from cartopy.geodesic import Geodesic
import matplotlib.pyplot as plt
import matplotlib as mpl
import cartopy.crs as ccrs
import cartopy
from pyproj import geod

fig, ax = plt.subplots(figsize=(4,4), facecolor="w", dpi=100, layout="compressed", subplot_kw=dict(projection=ccrs.PlateCarree()))

radius = 300 # km
n_samples = 80
lons = (0, 0, 0, 0)
lats = (20, 40, 60, 80)

# auto
ax.tissot(rad_km=radius, lons=lons, lats=lats, n_samples=n_samples, fc='none', ec="C3", lw=2)

# manual
for lon, lat in zip(lons,lats):
    circle = Geodesic().circle(lon, lat, radius*1000., n_samples=n_samples)
    feature = cartopy.feature.ShapelyFeature([Polygon(circle)], ccrs.Geodetic(), fc='none', ec="C0", lw=2, linestyle="--")
    ax.add_feature(feature)


ax.coastlines(alpha=.5, lw=0.4)
ax.set_extent((-45,45,0,90), crs=ccrs.PlateCarree())

enter image description here

关于python - 如何使用 Matplotlib 在不同的投影中绘制 Tissot 指标线?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76826132/

相关文章:

python - Tensorflow:从 TFRecords 文件中提取图像和标签

python - 在 Keras 中舍入激活函数

python - Pandas:将秒数转换为时间增量或时间

python - matplotlib imshow 从光标位置格式化

python - 气泡图标题和颜色

python - 将包含 unicode 的字符串传递给 RESTful API

python - 使用 Python Pandas 读取 excel 并隔离列/行以进行绘图

python - 使用 cartopy 在其他投影中绘制投影数据

python - 光栅图像不适合 folium map (leaflet.js)

python - imshow 和 cartopy 中的图像交叉日期线问题