Xarray: координаты среза без размеров

У меня проблемы с этой темой, хотя кажется, что она должна быть довольно простой.

Я хочу разрезать набор данных xarray, используя набор координат широты и долготы.

Вот как выглядит мой набор данных:

In [31]: data = xr.open_mfdataset(open_file, decode_cf=True)

In [32]: data
Out[32]: 
<xarray.Dataset>
Dimensions:  (time: 108120, x: 349, y: 277)
Coordinates:
    lons     (y, x) float64 -145.5 -145.3 -145.1 -144.9 -144.8 -144.6 -144.4 ...
    lats     (y, x) float64 1.0 1.104 1.208 1.312 1.416 1.519 1.621 1.724 ...
  * time     (time) datetime64[ns] 1980-01-01 1980-01-01T03:00:00 ...
Dimensions without coordinates: x, y
Data variables:
    stp      (time, y, x) float64 0.1235 0.0867 0.07183 0.05389 0.05901 ...

Вот что я делаю, чтобы нарезать:

In [48]: lat_bnd = [25,30]
    ...: lon_bnd = [-80,-75]

In [49]: r = data.sel(y=slice(*lat_bnd),x=slice(*lon_bnd))

И вроде все отлично:

In [50]: r
Out[50]: 
    <xarray.Dataset>
    Dimensions:  (time: 108120, x: 5, y: 5)
    Coordinates:
        lons     (y, x) float64 -82.52 -82.28 -82.05 -81.81 -81.57 -82.44 -82.2 ...
        lats     (y, x) float64 13.54 13.46 13.38 13.3 13.22 13.77 13.69 13.61 ...
      * time     (time) datetime64[ns] 1980-01-01 1980-01-01T03:00:00 ...
    Dimensions without coordinates: x, y
    Data variables:
        stp      (time, y, x) float64 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ...

Но мои значения широты и долготы неверны:

In [53]: r.lats.values
Out[53]: 
array([[ 13.53542397,  13.45647916,  13.37686013,  13.296571  ,
         13.21561592],
       [ 13.76719053,  13.6878189 ,  13.60776989,  13.52704767,
         13.44565641],
       [ 13.99938176,  13.91958109,  13.83909988,  13.75794233,
         13.67611265],
       [ 14.2319952 ,  14.15176326,  14.07084762,  13.98925249,
         13.90698214],
       [ 14.46502833,  14.3843629 ,  14.30301059,  14.22097564,
         14.13826236]])

In [54]: r.lons.values
Out[54]: 
array([[-82.52229969, -82.28438922, -82.0469968 , -81.8101255 ,
        -81.57377834],
       [-82.44118948, -82.20260881, -81.96455096, -81.72701901, -81.490016  ],
       [-82.3595596 , -82.12030558, -81.8815792 , -81.64338357,
        -81.40572174],
       [-82.27740522, -82.03747469, -81.79807668, -81.55921433,
        -81.32089068],
       [-82.19472148, -81.95411126, -81.71403851, -81.47450637, -81.2355179 ]])

Конечно, если я попытаюсь разрезать, используя координаты lats / lons, я получаю сообщение об ошибке, потому что размеры не совпадают.

    In [55]: r = data.sel(lats=slice(*lat_bnd),lons=slice(*lon_bnd))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-55-7c6237be5f22> in <module>()
----> 1 r = data.sel(lats=slice(*lat_bnd),lons=slice(*lon_bnd))

/lib/anaconda2/lib/python2.7/site-packages/xarray/core/dataset.pyc in sel(self, method, tolerance, drop, **indexers)
   1204         """
   1205         pos_indexers, new_indexes = indexing.remap_label_indexers(
-> 1206             self, indexers, method=method, tolerance=tolerance
   1207         )
   1208         result = self.isel(drop=drop, **pos_indexers)

/lib/anaconda2/lib/python2.7/site-packages/xarray/core/indexing.pyc in remap_label_indexers(data_obj, indexers, method, tolerance)
    275     new_indexes = {}
    276 
--> 277     dim_indexers = get_dim_indexers(data_obj, indexers)
    278     for dim, label in iteritems(dim_indexers):
    279         try:

/lib/anaconda2/lib/python2.7/site-packages/xarray/core/indexing.pyc in get_dim_indexers(data_obj, indexers)
    243     if invalid:
    244         raise ValueError("dimensions or multi-index levels %r do not exist"
--> 245                          % invalid)
    246 
    247     level_indexers = defaultdict(dict)

ValueError: dimensions or multi-index levels ['lons', 'lats'] do not exist

Есть ли что-то, чего мне не хватает в моем понимании из-за того, что это набор данных NARR?


person Maria Molina    schedule 04.08.2017    source источник


Ответы (3)


Обновление 2020-04-30

Если вы хотите выбрать данные на основе широты и долготы, вы можете использовать _ 1_, чтобы сделать что-то вроде:

data.where((data.lats > 25) & (data.lats < 30) & (data.lons > -80) & (data.lons < -75))

Вы можете добавить drop=True для возврата набора данных меньшего размера вместо заполнения несовпадающих значений с помощью NA.


Исходный ответ

В вашем первом примере вы индексируете не по широте и долготе, а по каждому числовому индексу x и y. То есть вы делаете нарезку между 25-м и 30-м y и -80-м и -75-м x значением. Это объясняет, почему значения широты и долготы не имеют смысла в вашем выводе.

Вы можете связать свои координаты с размерами, используя xr.Dataset.set_index(), например так:

data = data.set_index(y='lats')
data = data.set_index(x='lons')
person Dan    schedule 25.09.2017
comment
К сожалению, я получаю следующую ошибку: NotImplementedError: ›1 ndim Категориальные в настоящее время не поддерживаются. У меня xarray версии 0.9.6. Моя проблема в том, что широта и долгота NARR имеют два измерения (x и y). Есть еще какие-нибудь идеи? - person Maria Molina; 07.10.2017
comment
@MariaMolina Я не знаком с данными NARR и у меня нет аналогичного набора данных для тестирования, но вы можете попробовать передать список в set_index: что-то вроде data.set_index(y=['lats', 'lons'], inplace=True) - person Dan; 09.10.2017
comment
inplace устарел, как показано здесь: github.com/pydata/xarray/issues/1756. Если вы попробуете set_index по двумерным координатам, это приведет к следующей ошибке: ValueError: данные индекса должны быть одномерными. Если вы попытаетесь упаковать новые индексы в список, возникает ошибка NotImplementedError: ›1 ndim Категориальные значения не поддерживаются в настоящее время, а ValueError: Buffer имеет неправильное количество измерений (ожидалось 1, получено 2). - person Irene; 02.03.2020
comment
@Dan, вы нашли здесь решение этой проблемы? Я все еще борюсь с той же самой процедурой. - person clifgray; 30.04.2020
comment
@clifgray проверьте мой обновленный ответ. Решает ли это вашу проблему? Если нет, укажите неверный набор данных и / или опубликуйте новый вопрос. - person Dan; 01.05.2020
comment
Да, Дэн, делает именно то, что мне нужно! Спасибо, что добавили обновленный ответ. - person clifgray; 01.05.2020

Один из способов - разрезать на основе самих координат x, y. Чтобы проверить, соответствует ли это требованиям вашего домена, вы можете взглянуть на быстрые графики и настроить значения x, y для соответствующего среза. Но лучшим методом было бы преобразовать ваши координаты широты в координаты x, y, а затем срезать на основе соответствующих x, y.

person user11683337    schedule 21.06.2019
comment
Уважаемый user1168337, ваше предложение имеет большое значение. Тем не менее, как можно преобразовать координаты широты и долготы в netcdf_xarray x, y? Не могли бы вы опубликовать практический пример? Искренне Ваш. - person Philipe Riskalla Leal; 23.07.2020

Возможно, кому-то может быть интересно - используя where, вы не можете извлечь выгоду из приятной функции интерполяции ближайшего соседства xarray. У меня была аналогичная проблема - криволинейная сетка с 2-мерными массивами в виде координат lons / lats. Более того, я искал координаты, которые были ближайшими к заданной точке. Я использовал следующую дополнительную функцию для перевода любой пары долгота / широта в кортеж (x, y):

def find_nearest(lons, lats, lon0,lat0):
   idx = ((lons - lon0)**2+(lats - lat0)**2).argmin()
   value_lat =  lats.flat[idx]
   return tuple(np.squeeze(np.where(lats2d == value_lat)))

а затем используйте его как:

find_nearest(tmp.longitude.values,tmp.latitude.values, -22.16,32.3)
person Marcin Kawka    schedule 18.06.2021