【问题标题】:Cartopy projection scale not consistentCartopy投影比例不一致
【发布时间】:2021-02-25 04:10:53
【问题描述】:

我正在使用cartopy 来显示覆盖在世界地图上的 KDE。最初,我使用ccrs.PlateCarree 投影没有问题,但是当我尝试使用另一个投影时,它似乎爆炸了投影的比例。作为参考,我在下面提供了一个示例,您可以在自己的机器上进行测试(只需注释掉两行 projec 即可在投影之间切换)

from scipy.stats import gaussian_kde
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature

projec = ccrs.PlateCarree()
#projec = ccrs.InterruptedGoodeHomolosine()


fig = plt.figure(figsize=(12, 12))



ax = fig.add_subplot(projection=projec)

np.random.seed(1)

discrete_points = np.random.randint(0,10,size=(2,400))

kde = gaussian_kde(discrete_points)
x, y = discrete_points
# https://www.oreilly.com/library/view/python-data-science/9781491912126/ch04.html
resolution = 1
x_step = int((max(x)-min(x))/resolution)
y_step = int((max(y)-min(y))/resolution)
xgrid = np.linspace(min(x), max(x), x_step+1)
ygrid = np.linspace(min(y), max(y), y_step+1)
Xgrid, Ygrid = np.meshgrid(xgrid, ygrid)
Z = kde.evaluate(np.vstack([Xgrid.ravel(), Ygrid.ravel()]))
Zgrid = Z.reshape(Xgrid.shape)

ext = [min(x)*5, max(x)*5, min(y)*5, max(y)*5]
earth = plt.cm.gist_earth_r

ax.add_feature(cfeature.NaturalEarthFeature('physical', 'land', '50m', 
                                                edgecolor='black', facecolor="none"))

ax.imshow(Zgrid,
    origin='lower', aspect='auto',
    extent=ext,
    alpha=0.8,
    cmap=earth, transform=projec)

ax.axis('on')
ax.get_xaxis().set_visible(True)
ax.get_yaxis().set_visible(True)

ax.set_xlim(-30, 90)
ax.set_ylim(-60, 60)

plt.show()

您会注意到,使用ccrs.PlateCarree() 投影时,KDE 很好地放置在非洲上空,但是使用ccrs.InterruptedGoodeHomolosine() 投影时,您根本看不到世界地图。这是因为世界地图的规模很大。下面是两个示例的图片:

Plate Carree 投影:

中断的 Goode Homolosine 投影(标准缩放):

中断的Goode Homolosine投影(缩小):

如果有人能解释为什么会发生这种情况,以及如何解决它,以便我可以在不同的投影上绘制相同的数据,那将不胜感激。

编辑:

我还想说明我尝试在我包含的示例中将transform=projec 添加到第 37 行,即:

ax.add_feature(cfeature.NaturalEarthFeature('physical', 'land', '50m', 
                                                edgecolor='black', facecolor="none", transform=projec))

但这并没有帮助。事实上,添加这个后,世界地图似乎根本不再出现。

编辑:

响应 JohanC 的回答,这是我使用该代码时得到的情节:

并缩小:

【问题讨论】:

    标签: python matplotlib scipy kde cartopy


    【解决方案1】:

    对你的情节的评论:

    Plot1:(参考图)

    • 投影:PlateCarree 投影
    • (Zgrid)图像范围覆盖(大约)正方形区域,每边约 40 度
    • 图片的左下角是纬度/经度:(0,0)

    情节2

    问:为什么地图上没有显示地形特征?

    A:情节涵盖的区域非常小,不包括其中任何一个。

    • 投影:InterruptedGoodeHomolosine
    • 图像数据,Zgrid 被声明为适合网格(mapprojection)坐标(单位:米)
    • 地图绘制在 x 和 y 方向上几米的小范围内,纵横比不相等。

    情节3

    问:为什么在地图上看不到 Zgrid 图像?

    A:绘图覆盖了非常大的区域,图像变得太小而无法绘图。

    • 投影:InterruptedGoodeHomolosine 投影
    • (Zgrid)图像范围非常小,在此比例下不可见
    • 地图绘制范围大,纵横比不等。

    补救措施(情节 2 和 3)

    • Zgrid 需要从 lat/long 到坐标轴投影坐标的适当转换
    • 地图的范围也需要适当地转换和设置
    • 必须将纵横比设置为“相等”,以防止 x 和 y 的拉伸不相等

    关于“网格线”图

    • 对位置参考很有用
    • 纬度/平行:在这种情况下可以使用 InterruptedGoodeHomolosine
    • 经度/经线:有问题(不知道如何解决!!)

    这是运行并生成所需地图的修改后的代码。

    # proposed code
    
    from scipy.stats import gaussian_kde
    import numpy as np
    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    import cartopy.feature as cfeature
    
    fig = plt.figure(figsize=(7, 12))
    ax = plt.axes(projection=ccrs.InterruptedGoodeHomolosine())
    
    np.random.seed(1)
    discrete_points = np.random.randint(0,10,size=(2,400))
    
    kde = gaussian_kde(discrete_points)
    x, y = discrete_points
    # https://www.oreilly.com/library/view/python-data-science/9781491912126/ch04.html
    resolution = 1
    x_step = int((max(x)-min(x))/resolution)
    y_step = int((max(y)-min(y))/resolution)
    xgrid = np.linspace(min(x), max(x), x_step+1)
    ygrid = np.linspace(min(y), max(y), y_step+1)
    Xgrid, Ygrid = np.meshgrid(xgrid, ygrid)
    Z = kde.evaluate(np.vstack([Xgrid.ravel(), Ygrid.ravel()]))
    Zgrid = Z.reshape(Xgrid.shape)
    
    ext = [min(x)*5, max(x)*5, min(y)*5, max(y)*5]
    earth = plt.cm.gist_earth_r
    
    
    ocean110 = cfeature.NaturalEarthFeature('physical', 'ocean', \
            scale='110m', edgecolor='none', facecolor=cfeature.COLORS['water'])
    ax.add_feature(ocean110, zorder=-5)
    
    land110 = cfeature.NaturalEarthFeature('physical', 'land', '110m', \
            edgecolor='black', facecolor="silver")
    ax.add_feature(land110, zorder=5)
    
    # extents used by both Zgrid and axes
    ext = [min(x)*5, max(x)*5, min(y)*5, max(y)*5]
    
    # plot the image's data array
    # note the options: `extent` and `transform`
    ax.imshow(Zgrid,
        origin='lower', aspect='auto',
        extent=ext,  #set image's extent
        alpha=0.75,
        cmap=earth, transform=ccrs.PlateCarree(),
        zorder=10)
    
    # set the plot's extent with proper coord transformation
    ax.set_extent(ext, ccrs.PlateCarree())
    
    ax.coastlines()
    #ax.add_feature(cfeature.BORDERS) #uncomment if you need
    
    ax.gridlines(linestyle=':', linewidth=1, draw_labels=True, dms=True, zorder=30, color='k')
    ax.set_aspect('equal')  #make sure the aspect ratio is 1
    
    plt.show()
    

    输出地图:

    【讨论】:

    • 感谢您的深入回答!这在大多数情况下都有效,我遇到的唯一问题是 KDE 比它应该的大 10 倍左右。在我的编辑中,我包含了一个示例。除了 ax.gridlines 行之外,我直接复制并粘贴了您的代码,因为使用我的 cartopy 版本,除了 PlateCarree 或 Mercator 之外,它似乎无法在任何投影上绘制它们。
    猜你喜欢
    • 2019-11-07
    • 2017-02-17
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多