将 Basemap 转换为 Cartopy,是否有 Basemap 的 shiftgrid() 等等效函数?

Converting Basemap to Cartopy, are there quivalent functions such as Basemap's shiftgrid()?

我正在将一个使用 matplotlib 工具包 Basemap 的应用程序转换为使用 Cartopy,以准备从 Python 2 迁移到 Python 3。 我在 Cartopy 中为底图的 'addcyclic()' 和 'maskoceans()' 找到了类似的功能, 但是,对于底图的 shiftgrid() 函数,我在 numpy 或 Cartopy 中找不到类似的东西。

这是使用底图的代码: '''

    import matplotlib.pyplot as plt
    from mpl_toolkits.basemap import Basemap
    import cartopy
    import cartopy.crs as ccrs
    import cartopy.feature as cfeature
    import numpy as np
    from mpl_toolkits.basemap import shiftgrid

    bmap = Basemap(projection='ortho', lat_0=0, lon_0=0)
    lons = np.arange(30, 410, 30)
    lons[1] = 70
    lats = np.arange(0, 100, 10)

    data = np.indices((lats.shape[0], lons.shape[0]))
    data = data[0] + data[1]

    data, lons = shiftgrid(180., data, lons, start=False)

    llons, llats = np.meshgrid(lons, lats)
    x, y = bmap(llons, llats)
    bmap.contourf(x, y, data)
    bmap.drawcoastlines()

'''

初始数据: 数据 '''

    [[ 0  1  2  3  4  5  6  7  8  9 10 11 12]
     [ 1  2  3  4  5  6  7  8  9 10 11 12 13]
     [ 2  3  4  5  6  7  8  9 10 11 12 13 14]
     [ 3  4  5  6  7  8  9 10 11 12 13 14 15]
     [ 4  5  6  7  8  9 10 11 12 13 14 15 16]
     [ 5  6  7  8  9 10 11 12 13 14 15 16 17]
     [ 6  7  8  9 10 11 12 13 14 15 16 17 18]
     [ 7  8  9 10 11 12 13 14 15 16 17 18 19]
     [ 8  9 10 11 12 13 14 15 16 17 18 19 20]
     [ 9 10 11 12 13 14 15 16 17 18 19 20 21]]

     lons

     [ 30  70  90 120 150 180 210 240 270 300 330 360 390]

     After the 'data, lons = shiftgrid(180., data, lons, start=False)':
     data

     [[ 5  6  7  8  9 10 11 12  1  2  3  4  5]
      [ 6  7  8  9 10 11 12 13  2  3  4  5  6]
      [ 7  8  9 10 11 12 13 14  3  4  5  6  7]
      [ 8  9 10 11 12 13 14 15  4  5  6  7  8]
      [ 9 10 11 12 13 14 15 16  5  6  7  8  9]
      [10 11 12 13 14 15 16 17  6  7  8  9 10]
      [11 12 13 14 15 16 17 18  7  8  9 10 11]
      [12 13 14 15 16 17 18 19  8  9 10 11 12]
      [13 14 15 16 17 18 19 20  9 10 11 12 13]
      [14 15 16 17 18 19 20 21 10 11 12 13 14]]

      lons

      [-180 -150 -120  -90  -60  -30    0   30   70   90  120  150  180]

''' 我尝试了以下 cartopy 代码来重新创建 Basemap shiftgrid 所做的事情。 这是 Cartopy 代码,有些东西在我一次尝试时被注释掉了: '''

    DATA_CRS = ccrs.PlateCarree()
    lons = np.arange(30, 410, 30)
    lons[1] = 70
    lats = np.arange(0, 100, 10)

    data = np.indices((lats.shape[0], lons.shape[0]))
    data = data[0] + data[1]
    # data2 = np.roll(data, -5)
    # lons2 = np.mod(lons2 - 180.0, 360.0) - 180.0
    cm_lon = 0
    #llons, llats = np.meshgrid(lons2, lats)
    llons, llats = np.meshgrid(lons, lats)
    PROJECTION = ccrs.Orthographic(central_longitude=cm_lon)
    fig1 = plt.figure(num=1, figsize=(11, 8.5), dpi=150)
    ax = plt.axes(projection=PROJECTION)
    ax.add_feature(cfeature.COASTLINE, linewidths=0.7)
    ax.add_feature(cfeature.BORDERS, edgecolor='black', linewidths=0.7)
    ax.contourf(llons, llats, data, transform=ccrs.PlateCarree())

'''

原始数据和经度,我只是在投影中使用了 'central_longitude'。 Basemap 图像显示整个地球,但 Cartopy 图像仅显示赤道以上。 除了最右侧外,数据的颜色看起来很相似,所以我担心数据在 Cartopy 中的映射与在 Basemap 中的映射不一样。

所以,问题是...是否有任何与 Basemap 的 shiftgrid() 等效的东西,或者我是否需要找出类似于 Basemap 的 shiftgrid() 的东西,或者只在投影中使用 'central_longitude'? 我似乎无法粘贴 .png 文件。 非常感谢任何帮助。 我在网上搜索了等效函数,但没有找到适用于 shiftgrid() 的函数。 谢谢。

我不知道有任何 shiftgrid 等效项。在请求此类功能的 CartoPy issue tracker 上开一个问题可能是值得的。提及一个可靠的用例来帮助推动功能将有助于这样做。

找到basemap的shiftgrid函数 here 您可以将它作为一个单独的函数与 cartopy 一起调用。

import numpy as np
import numpy.ma as ma
def shiftgrid(lon0,datain,lonsin,start=True,cyclic=360.0):
    """
    Shift global lat/lon grid east or west.
    .. tabularcolumns:: |l|L|
    ==============   ====================================================
    Arguments        Description
    ==============   ====================================================
    lon0             starting longitude for shifted grid
                     (ending longitude if start=False). lon0 must be on
                     input grid (within the range of lonsin).
    datain           original data with longitude the right-most
                     dimension.
    lonsin           original longitudes.
    ==============   ====================================================
    .. tabularcolumns:: |l|L|
    ==============   ====================================================
    Keywords         Description
    ==============   ====================================================
    start            if True, lon0 represents the starting longitude
                     of the new grid. if False, lon0 is the ending
                     longitude. Default True.
    cyclic           width of periodic domain (default 360)
    ==============   ====================================================
    returns ``dataout,lonsout`` (data and longitudes on shifted grid).
    """
    if np.fabs(lonsin[-1]-lonsin[0]-cyclic) > 1.e-4:
        # Use all data instead of raise ValueError, 'cyclic point not included'
        start_idx = 0
    else:
        # If cyclic, remove the duplicate point
        start_idx = 1
    if lon0 < lonsin[0] or lon0 > lonsin[-1]:
        raise ValueError('lon0 outside of range of lonsin')
    i0 = np.argmin(np.fabs(lonsin-lon0))
    i0_shift = len(lonsin)-i0
    if ma.isMA(datain):
        dataout  = ma.zeros(datain.shape,datain.dtype)
    else:
        dataout  = np.zeros(datain.shape,datain.dtype)
    if ma.isMA(lonsin):
        lonsout = ma.zeros(lonsin.shape,lonsin.dtype)
    else:
        lonsout = np.zeros(lonsin.shape,lonsin.dtype)
    if start:
        lonsout[0:i0_shift] = lonsin[i0:]
    else:
        lonsout[0:i0_shift] = lonsin[i0:]-cyclic
    dataout[...,0:i0_shift] = datain[...,i0:]
    if start:
        lonsout[i0_shift:] = lonsin[start_idx:i0+start_idx]+cyclic
    else:
        lonsout[i0_shift:] = lonsin[start_idx:i0+start_idx]
    dataout[...,i0_shift:] = datain[...,start_idx:i0+start_idx]
    return dataout,lonsout

这一定是最不优雅的解决方案,但我一直在为 Basemap 的几个有用功能做的(还没有?)在 cartopy 中,只是从 Basemap 的源代码中复制函数定义。它工作正常。例如,shiftgrid:

def shiftgrid(lon0,datain,lonsin,start=True,cyclic=360.0):
"""
Shift global lat/lon grid east or west.
.. tabularcolumns:: |l|L|
==============   ====================================================
Arguments        Description
==============   ====================================================
lon0             starting longitude for shifted grid
                 (ending longitude if start=False). lon0 must be on
                 input grid (within the range of lonsin).
datain           original data with longitude the right-most
                 dimension.
lonsin           original longitudes.
==============   ====================================================
.. tabularcolumns:: |l|L|
==============   ====================================================
Keywords         Description
==============   ====================================================
start            if True, lon0 represents the starting longitude
                 of the new grid. if False, lon0 is the ending
                 longitude. Default True.
cyclic           width of periodic domain (default 360)
==============   ====================================================
returns ``dataout,lonsout`` (data and longitudes on shifted grid).
"""
if np.fabs(lonsin[-1]-lonsin[0]-cyclic) > 1.e-4:
    # Use all data instead of raise ValueError, 'cyclic point not included'
    start_idx = 0
else:
    # If cyclic, remove the duplicate point
    start_idx = 1
if lon0 < lonsin[0] or lon0 > lonsin[-1]:
    raise ValueError('lon0 outside of range of lonsin')
i0 = np.argmin(np.fabs(lonsin-lon0))
i0_shift = len(lonsin)-i0
if ma.isMA(datain):
    dataout  = ma.zeros(datain.shape,datain.dtype)
else:
    dataout  = np.zeros(datain.shape,datain.dtype)
if ma.isMA(lonsin):
    lonsout = ma.zeros(lonsin.shape,lonsin.dtype)
else:
    lonsout = np.zeros(lonsin.shape,lonsin.dtype)
if start:
    lonsout[0:i0_shift] = lonsin[i0:]
else:
    lonsout[0:i0_shift] = lonsin[i0:]-cyclic
dataout[...,0:i0_shift] = datain[...,i0:]
if start:
    lonsout[i0_shift:] = lonsin[start_idx:i0+start_idx]+cyclic
else:
    lonsout[i0_shift:] = lonsin[start_idx:i0+start_idx]
dataout[...,i0_shift:] = datain[...,start_idx:i0+start_idx]
return dataout,lonsout