Xarray Roll and Cartopy add_cyclic_point functions conflicting

二次信任 提交于 2021-02-05 11:12:58

问题


Recently I tried to make a simple plot of the Pacific and Atlantic Oceans together, from 180W-20E. To cross the 0 degree line I used the roll method as follows:

import matplotlib.pyplot   as plt
import cartopy.crs         as ccrs
import cartopy.feature     as cf
import cartopy             as cartopy
import numpy               as np
import xarray              as xr

from cartopy.mpl.ticker    import LongitudeFormatter, LatitudeFormatter
from cartopy.util          import add_cyclic_point


dset  =  xr.open_dataset('sst.mnmean.nc')
var   =  dset['sst'][:,:,:]
lat   =  dset['lat'][:]
lon   =  dset['lon'][:]

Using the roll method:

lonr = lon.roll(lon=300)

This will give me the following longitude array:

[ 120.  122.  124.  126.  128.  130.  132.  134.  136.  138.  140.  142.
  144.  146.  148.  150.  152.  154.  156.  158.  160.  162.  164.  166.
  168.  170.  172.  174.  176.  178.  180.  182.  184.  186.  188.  190.
  192.  194.  196.  198.  200.  202.  204.  206.  208.  210.  212.  214.
  216.  218.  220.  222.  224.  226.  228.  230.  232.  234.  236.  238.
  240.  242.  244.  246.  248.  250.  252.  254.  256.  258.  260.  262.
  264.  266.  268.  270.  272.  274.  276.  278.  280.  282.  284.  286.
  288.  290.  292.  294.  296.  298.  300.  302.  304.  306.  308.  310.
  312.  314.  316.  318.  320.  322.  324.  326.  328.  330.  332.  334.
  336.  338.  340.  342.  344.  346.  348.  350.  352.  354.  356.  358.
    0.    2.    4.    6.    8.   10.   12.   14.   16.   18.   20.   22.
   24.   26.   28.   30.   32.   34.   36.   38.   40.   42.   44.   46.
   48.   50.   52.   54.   56.   58.   60.   62.   64.   66.   68.   70.
   72.   74.   76.   78.   80.   82.   84.   86.   88.   90.   92.   94.
   96.   98.  100.  102.  104.  106.  108.  110.  112.  114.  116.  118.]

Then I proceed to extract the area I want with the 'sel' method:

lonr = lonr.sel(lon=slice(180,12))
lonr = lonr.roll(lon=104)

This last line was applied to avoid the weird horizontal lines over the plot as was discussed here. That is to say my sliced longitude array now looks like this:

[   0.    2.    4.    6.    8.   10.   12.  180.  182.  184.  186.  188.
  190.  192.  194.  196.  198.  200.  202.  204.  206.  208.  210.  212.
  214.  216.  218.  220.  222.  224.  226.  228.  230.  232.  234.  236.
  238.  240.  242.  244.  246.  248.  250.  252.  254.  256.  258.  260.
  262.  264.  266.  268.  270.  272.  274.  276.  278.  280.  282.  284.
  286.  288.  290.  292.  294.  296.  298.  300.  302.  304.  306.  308.
  310.  312.  314.  316.  318.  320.  322.  324.  326.  328.  330.  332.
  334.  336.  338.  340.  342.  344.  346.  348.  350.  352.  354.  356.
  358.]

Now the problem is: this solves the area selection issue but it gives me the weird white line around the 0 longitude values when plotting, as the one you can see here. To solve it we would think of using the "add_cyclic_point" method, but this gives the following error:

var  =  var.sel(lat=slice(-30,30),
                lon=lonr)

lon_idx = var.dims.index('lon')
var_c, lon_c = add_cyclic_point(var.values, 
                                coord=lonr, axis=lon_idx)

(...)in add_cyclic_point
    raise ValueError('The coordinate must be equally spaced.')
ValueError: The coordinate must be equally spaced.

As it says, I can't add the point to the array because it is not equally spaced. From the method's manual it looks clear why I can't use it, but of course I wouldn't like to live with that weird white line all over my plot (an example of what I did can be seen here).

Sorry for the rather lengthy question, but anyone knows how to solve this? Any help would be appreciated.


回答1:


Given we don't have access to your code to reproduce the problem, I'm going to invent some numbers to illustrate the problem with rolling in the way that you have:

In [1]: import numpy as np

In [2]: lons = np.arange(0, 360, 10)

In [3]: lons
Out[3]: 
array([  0,  10,  20,  30,  40,  50,  60,  70,  80,  90, 100, 110, 120,
       130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250,
       260, 270, 280, 290, 300, 310, 320, 330, 340, 350])

Now, if we roll this as you have done:

In [4]: lons = np.roll(lons, -list(lons).index(100))

In [5]: lons
Out[5]: 
array([100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220,
       230, 240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350,
         0,  10,  20,  30,  40,  50,  60,  70,  80,  90])

The problem with these numbers is that they are fine if you consider them to be spherical (where 350 is just 10 degrees from 0), but if consider them to be Cartesian then there is a point where the distance between two of your datapoints is 350 degrees. When plotting your data, if you tell cartopy that your data is in the PlateCarree projected coordinate system, this is precisely what is happening.

In this case, there are many ways of fixing your numbers so that you don't have such a distance between some of your points. One way:

In [6]: np.diff(lons) < -180
Out[6]: 
array([False, False, False, False, False, False, False, False, False,
       False, False, False, False, False, False, False, False, False,
       False, False, False, False, False, False, False,  True, False,
       False, False, False, False, False, False, False, False], dtype=bool)

In [7]: np.cumsum(np.diff(lons) < -180)
Out[7]: 
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])

In [8]: new_lons = lons.copy()

In [8]: new_lons[1:] += np.cumsum(np.diff(lons) < -180) * 360

In [9]: new_lons
Out[9]: 
array([100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220,
       230, 240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350,
       360, 370, 380, 390, 400, 410, 420, 430, 440, 450])

You are now back in the territory of equidistant coordinates in projected space, and should have a lot more luck with things like add_cyclic_point.



来源:https://stackoverflow.com/questions/48265694/xarray-roll-and-cartopy-add-cyclic-point-functions-conflicting

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!