如何将 MetPy 的横截面分析应用于具有二维纬度和经度的数据集?

How to apply MetPy's cross section analysis to a data set with 2-dimensional lat and lon?

我有 4 维数据(时间、深度、y 和 x),但纬度和经度都是二维数组。 y 和 x 只是索引,所以只是从 0、1...end 等开始的整数。 非常类似于MetPy提供的示例数据集:

https://unidata.github.io/MetPy/latest/examples/cross_section.html

不幸的是,这不是最可重现的,因为它非常特定于数据本身。但是我在横截面部分遇到了麻烦。我可以根据metpy解析数据,但是取横截面的时候报错:

data = ds.metpy.parse_cf().squeeze()

print(data)

<xarray.Dataset>
Dimensions:               (y: 1347, x: 1379, deptht: 46, axis_nbounds: 2, time_counter: 12)
Coordinates:
    nav_lat               (y, x) float32 20.92 20.92 20.92 ... 68.49 68.49 68.48
    nav_lon               (y, x) float32 -78.95 -78.9 -78.85 ... -3.614 -3.546
  * deptht                (deptht) float32 3.047 9.454 ... 5.625e+03 5.875e+03
    time_centered         (time_counter) datetime64[ns] 1993-01-16T12:00:00 ....
  * time_counter          (time_counter) datetime64[ns] 1993-01-16T12:00:00 ....
Dimensions without coordinates: y, x, axis_nbounds
Data variables: (12/17)
    deptht_bounds         (deptht, axis_nbounds, y, x) float32 0.0 0.0 ... nan
    time_centered_bounds  (time_counter, axis_nbounds, y, x) datetime64[ns] 1...
    time_counter_bounds   (time_counter, axis_nbounds, y, x) datetime64[ns] 1...
    votemper              (time_counter, deptht, y, x) float32 26.63 ... nan
    vosaline              (time_counter, deptht, y, x) float32 35.88 ... nan
    sosstsst              (time_counter, y, x) float32 26.63 26.58 ... nan nan
    ...                    ...
    sohefldo              (time_counter, y, x) float32 -50.02 -45.85 ... nan nan
    somixhgt              (time_counter, y, x) float32 19.84 19.76 ... nan nan
    sowindsp              (time_counter, y, x) float32 5.591 5.48 ... nan nan
    sohefldp              (time_counter, y, x) float32 nan nan nan ... nan nan
    sowafldp              (time_counter, y, x) float32 3.94e-06 ... nan
    sobowlin              (time_counter, y, x) float32 20.04 20.04 ... nan nan
Attributes:
    name:                      1_VIKING20X.L46-KKG36107B_1d_19930101_19930704...
    description:               ocean T grid variables
    title:                     ocean T grid variables
    Conventions:               CF-1.6
    timeStamp:                 2019-Sep-11 21:02:06 GMT
    uuid:                      a091f081-2943-4c66-aa77-0917f654b802
    history:                   Thu Sep 12 22:15:40 2019: ncrcat -O -F /gfs1/w...
    NCO:                       4.4.8
    nco_openmp_thread_number:  1

然后我尝试横截面部分(还要注意,二维纬度和经度标记为 'nav_lat' 和 'nav_lon',而不是纬度和经度):

 start = (40, -40)
 end = (50, -30)
    
 cross = cross_section(data, start, end).set_coords(('nav_lon', 'nav_lat'))
 print(cross)

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/metpy/interpolate/slices.py in cross_section(data, start, end, steps, interp_type)
    165         try:
--> 166             crs_data = data.metpy.pyproj_crs
    167             x = data.metpy.x

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/metpy/xarray.py in pyproj_crs(self)
    252         """Return the coordinate reference system (CRS) as a pyproj object."""
--> 253         return self.crs.to_pyproj()
    254 

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/metpy/xarray.py in crs(self)
    232             return self._data_array.coords['metpy_crs'].item()
--> 233         raise AttributeError('crs attribute is not available.')
    234 

AttributeError: crs attribute is not available.

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
/tmp/ipykernel_2676704/3597335100.py in <module>
----> 1 cross = cross_section(data, start, end).set_coords(('nav_lon', 'nav_lat'))
      2 print(cross)

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/metpy/interpolate/slices.py in cross_section(data, start, end, steps, interp_type)
    154     if isinstance(data, xr.Dataset):
    155         # Recursively apply to dataset
--> 156         return data.map(cross_section, True, (start, end), steps=steps,
    157                         interp_type=interp_type)
    158     elif data.ndim == 0:

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/xarray/core/dataset.py in map(self, func, keep_attrs, args, **kwargs)
   5106         if keep_attrs is None:
   5107             keep_attrs = _get_keep_attrs(default=False)
-> 5108         variables = {
   5109             k: maybe_wrap_array(v, func(v, *args, **kwargs))
   5110             for k, v in self.data_vars.items()

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/xarray/core/dataset.py in <dictcomp>(.0)
   5107             keep_attrs = _get_keep_attrs(default=False)
   5108         variables = {
-> 5109             k: maybe_wrap_array(v, func(v, *args, **kwargs))
   5110             for k, v in self.data_vars.items()
   5111         }

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/metpy/interpolate/slices.py in cross_section(data, start, end, steps, interp_type)
    167             x = data.metpy.x
    168         except AttributeError:
--> 169             raise ValueError('Data missing required coordinate information. Verify that '
    170                              'your data have been parsed by MetPy with proper x and y '
    171                              'dimension coordinates and added crs coordinate of the '

ValueError: Data missing required coordinate information. Verify that your data have been parsed by MetPy with proper x and y dimension coordinates and added crs coordinate of the correct projection for each variable.

我尝试了替代方案,因为可能 parse_cf 导致了问题:

data = ds.metpy.assign_latitude_longitude(force=True).squeeze()

但是我在应用横截面时仍然出现同样的错误。

关于如何解决这个问题有什么想法吗? 再次抱歉缺乏可重复性,但任何想法都会有很大帮助:) 可能跟投影有关?

这是一个示例图像,说明数据如何看待一个时间和深度实例(观察温度):

metpy.interpolate.cross_section requires that your data include both x and y dimension coordinates and the added metpy_crs coordinate (from either parse_cf or assign_crs). In this situation where these x and y dimension coordinates are missing, but you do have 2D latitude and longitude coordinates, these dimension coordinates can be calculated and added with .metpy.assign_y_x()(而不是你说你试过的 assign_latitude_longitude,它的作用恰恰相反——从 y/x 维度坐标添加 lat/lon 辅助坐标)。

因此,如果您的数据集具有与您的数据投影相对应的有效 CF 网格映射,您将拥有:

data = ds.metpy.parse_cf()
data = data.metpy.assign_y_x()

start = (40, -40)
end = (50, -30)
    
cross = cross_section(data, start, end).set_coords(('nav_lon', 'nav_lat'))

如果没有:

data = ds.metpy.assign_crs({
    "grid_mapping_name": "lambert_conformal_conic",
    "standard_parallel": 25.0,
    "longitude_of_central_meridian": 265.0,
    "latitude_of_projection_origin": 25.0,
})
data = data.metpy.assign_y_x()

start = (40, -40)
end = (50, -30)
    
cross = cross_section(data, start, end).set_coords(('nav_lon', 'nav_lat'))

(变化 the projection attributes to those needed for your given projection