【问题标题】:Cartopy figure for high latitude with edges parallel to latitude and longitude, e.g., not rectangular高纬度的 Cartopy 图,边缘与经纬度平行,例如,不是矩形
【发布时间】:2022-10-25 14:00:45
【问题描述】:

我正在尝试为冰岛周围的次极地区创建 Cartopy 地图。我想要的是一个非矩形图形,其中边缘平行于经度和纬度线,就像使用 PyGMT 创建的这个图形:

我尝试了各种 Cartopy 投影,但都产生了一个矩形图形,例如,

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

fig = plt.figure()
proj = ccrs.LambertConformal(central_longitude=-25, central_latitude=58.0)
ax = plt.axes(projection = proj)

ax.set_extent((-45, -5, 45, 70))
ax.gridlines()
ax.add_feature(cartopy.feature.LAND, zorder=1, edgecolor='black')

不使用 PyGMT 是有原因的(我想使用 quiver 绘制表面速度,加上广泛的学习曲线),所以我想知道是否有可能在 cartopy 中获得相同的结果。

谢谢

【问题讨论】:

    标签: projection cartopy


    【解决方案1】:

    为此,您可以使用轴的 set_boundary 方法。当将其指定为 lon/lat 时,对于不同的投影,您应该在边界上采样一些点以近似投影的真实曲率(与 lon/lat 相比)。下面的示例在每条边上取 20 个点。

    请注意,此边界的形状可以是您想要的任何形状,它不必匹配投影或经度/纬度线等。

    import matplotlib.pyplot as plt
    import matplotlib.path as mpath
    import cartopy
    import cartopy.crs as ccrs
    import numpy as np
    
    proj = ccrs.LambertConformal(central_longitude=-25, central_latitude=58.0)
    
    fig, axs = plt.subplots(
        1,2, figsize=(8, 3), facecolor="w", 
        subplot_kw=dict(projection=proj),
    )
    
    n = 20
    aoi = mpath.Path(
        list(zip(np.linspace(-45,-5, n), np.full(n, 70))) + 
        list(zip(np.full(n, -5), np.linspace(70, 45, n))) + 
        list(zip(np.linspace(-5, -45, n), np.full(n, 45))) + 
        list(zip(np.full(n, -45), np.linspace(45, 70, n)))
    )
    
    axs[1].set_boundary(aoi, transform=ccrs.PlateCarree())
        
    for ax in axs:
        ax.set_extent((-45, -5, 45, 70))
        ax.add_feature(cartopy.feature.LAND, zorder=1, edgecolor='k')
        gl = ax.gridlines(
            draw_labels=True, rotate_labels=False,
            x_inline=False, y_inline=False,
        )
    

    【讨论】:

    • 谢谢,我愚蠢地认为这将是一个 cartopy 解决方案,而不是 matplotlib 解决方案。完美运行。
    • 我认为你没有错,它特定于使用 Cartopy 投影初始化的轴。普通的 Matplotlib 轴缺少这种方法。
    • 再次感谢。我注意到的唯一奇怪的行为是,将左侧标签设置为 False 时,我得到一个纬度标签仍然出现。虽然这是一个小烦恼。
    【解决方案2】:

    @Rutger_Kassies 的回答很棒。但是,如果读者想尝试不同的方法,则应考虑另一种方法。

    import cartopy.crs as ccrs
    import cartopy
    import matplotlib.pyplot as plt
    import matplotlib.path as mpath
    
    # The lat-long proj
    noProj = ccrs.PlateCarree()
    # The projection of the map
    myProj = ccrs.LambertConformal(central_longitude=-25, central_latitude=58.0)
    myProj._threshold = myProj._threshold/20.  # Set for higher precision of the projection
    
    ax = plt.axes(projection=myProj)
    
    # This plots parallel and meridian arcs around a target area that will be used ...
    #  as the map boundary
    [ax_hdl] = ax.plot([-45, -5, -5, -45, -45], [45, 45, 70, 70, 45],
             color='black', linewidth=0.5, marker='none',
             transform=noProj)
    # Get the `Path` of the plot
    tx_path = ax_hdl._get_transformed_path()
    path_in_data_coords, _ = tx_path.get_transformed_path_and_affine()
    
    # Use the path's vertices to create a polygon
    polygon = mpath.Path( path_in_data_coords.vertices )
    ax.set_boundary(polygon) #This masks-out unwanted part of the plot
    
    ax.gridlines(draw_labels=True, x_inline=False, y_inline=False)
    ax.add_feature(cartopy.feature.OCEAN, linewidth=.3, color='lightblue')
    ax.add_feature(cartopy.feature.LAND, zorder=1, edgecolor='black')
    ax.title.set_text("Meridians and Parallels as Boundary")
    plt.show()
    

    您可以更改代码中的一些参数,例如,用作地图边界的弧的类型。

    第二个图是通过更改这些代码部分获得的:

    1. `transform=noProj`  to  
       `transform=ccrs.Geodetic()`
    2. `ax.title.set_text("Meridians and Parallels as Boundary")` to
       `ax.title.set_text("Great-circle Arcs as Boundary")`
    

    我认为当地图的上边缘到达高纬度时,使用纬度平行线作为边界不是最佳的。直线可能更好,但在某些情况下应考虑大圆弧。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-31
      • 1970-01-01
      • 2012-10-30
      • 2020-12-08
      • 2016-07-03
      • 2013-09-09
      • 1970-01-01
      相关资源
      最近更新 更多