Search code examples
pythonpython-xarraymetpy

metpy cross_section function gives nan in output


I'm trying to use metpy to take a cross-section of oceanographic data, because I'm not managing with the OceanSpy package and don't know if there are other packages more suitable for doing this. Advice is welcome :-)

I downloaded some sample data from CMEMS manually selecting a small map area and ticking the variables uo, vo and zos from https://data.marine.copernicus.eu/product/GLOBAL_MULTIYEAR_PHY_001_030/download?dataset=cmems_mod_glo_phy_my_0.083_P1M-m

I read the data using xarray and parse through metpy, focussing on a single timestep for simplification:

ds = xr.open_mfdataset('/Users/0448257/Data/cmems_mod_glo_phy-cur_anfc_0.083deg_P1M.nc')
data = ds.isel(time=30).metpy.parse_cf().squeeze()
print(data)
<xarray.Dataset>
Dimensions:    (depth: 35, latitude: 174, longitude: 175)
Coordinates:
  * depth      (depth) float32 0.494 1.541 2.646 3.819 ... 643.6 763.3 902.3
  * latitude   (latitude) float32 -67.33 -67.25 -67.17 ... -53.08 -53.0 -52.92
    time       datetime64[ns] 2023-05-16T12:00:00
  * longitude  (longitude) float32 -72.0 -71.92 -71.83 ... -57.67 -57.58 -57.5
    metpy_crs  object Projection: latitude_longitude
Data variables:
    vo         (depth, latitude, longitude) float32 dask.array<chunksize=(35, 174, 175), meta=np.ndarray>
    uo         (depth, latitude, longitude) float32 dask.array<chunksize=(35, 174, 175), meta=np.ndarray>

Here's a plot of where I'm trying to do the cross-section:

start = (-68, -56) #(-66, -60) 
end = (-64, -64) #(-63, -62) 
fig, ax = plt.subplots()
ax.contourf(data['longitude'], data['latitude'], data['uo'][0,:,:])
ax.plot((start[0],end[0]), (start[1], end[1]), marker='o', color='black')

Plot of u data with cross-section

I calculate the cross-section without errors, but when I print or plot the data there are nan in it...

It makes sense to get some nans deeper down along the coasts as the ocean narrows there, but not in the middle of the cross-section. I've also tried taking a smaller cross-section to make sure I never have NA in the data, but that didn't help. Setting the interpolation type to nearest also didn't help.

Any ideas?

Some sample output:

cross = cross_section(data, start, end).set_coords(('latitude', 'longitude'))
print(cross)
<xarray.Dataset>
Dimensions:    (depth: 35, index: 100)
Coordinates:
  * depth      (depth) float32 0.494 1.541 2.646 3.819 ... 643.6 763.3 902.3
    time       datetime64[ns] 2023-05-16T12:00:00
    metpy_crs  object Projection: latitude_longitude
    longitude  (index) float64 -56.0 -56.09 -56.19 ... -63.86 -63.93 -64.0
    latitude   (index) float64 -68.0 -67.96 -67.92 ... -64.08 -64.04 -64.0
  * index      (index) int64 0 1 2 3 4 5 6 7 8 9 ... 91 92 93 94 95 96 97 98 99
Data variables:
    vo         (depth, index) float32 dask.array<chunksize=(35, 100), meta=np.ndarray>
    uo         (depth, index) float32 dask.array<chunksize=(35, 100), meta=np.ndarray>

print(cross.uo.values)

[[        nan         nan         nan ... -0.00716022  0.01993629
   0.04136517]
 [        nan         nan         nan ... -0.00686111  0.02008043
   0.04135653]
 [        nan         nan         nan ... -0.00662968  0.02014319
   0.04128024]
 ...

Solution

  • This is a case of the horrible cross between normal points being (x, y), but geographically using (latitude, longitude). In MetPy for a lot of cases, we try to adhere (at least for individual function arguments) to longitude, then latitude. HOWEVER, we stuck with (latitude, longitude) points for cross_section. I'm not sure how best to deal with this problem in a way that avoids user problems.

    At any rate, if I change your code to flip the order of the entries in start and end:

    cross = cross_section(data, start[::-1], end[::-1])
    

    I only get nan at the bottom

    array([[0.286874  , 0.29746435, 0.27922769, ..., 0.06116014, 0.03308784,
            0.0225837 ],
           [0.28138065, 0.29160811, 0.27359135, ..., 0.05810829, 0.03002688,
            0.01892148],
           [0.27649769, 0.28672514, 0.26870839, ..., 0.05510405, 0.0275854 ,
            0.01648   ],
           ...,
           [       nan,        nan,        nan, ...,        nan,        nan,
                   nan],
           [       nan,        nan,        nan, ...,        nan,        nan,
                   nan],
           [       nan,        nan,        nan, ...,        nan,        nan,
                   nan]])
    

    and the plot looks reasonable (plt.imshow(cross.uo.values)):

    Corrected cross section image