Skip to content

Commit

Permalink
Attempt xarray backend entrypoint
Browse files Browse the repository at this point in the history
  • Loading branch information
nawendt committed May 15, 2024
1 parent 80f11b3 commit 7b14664
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 24 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies = [

[project.entry-points."xarray.backends"]
gini = "metpy.io.gini:GiniXarrayBackend"
area = "metpy.io.mcidas:AreaFileXarrayBackend"

[project.optional-dependencies]
doc = [
Expand Down
82 changes: 58 additions & 24 deletions src/metpy/io/mcidas.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
from matplotlib.transforms import Affine2D
import numpy as np
import pyproj
from xarray import DataArray
from xarray import DataArray, Dataset, Variable

Check failure on line 15 in src/metpy/io/mcidas.py

View workflow job for this annotation

GitHub Actions / Flake8

[ruff] reported by reviewdog 🐶 F401 [*] `xarray.DataArray` imported but unused Raw Output: src/metpy/io/mcidas.py:15:20: F401 [*] `xarray.DataArray` imported but unused
from xarray.backends import BackendEntrypoint
from xarray.backends.common import AbstractDataStore

from ._tools import IOBuffer, NamedStruct, open_as_needed
from ..package_tools import Exporter
Expand Down Expand Up @@ -269,7 +271,7 @@ def repeat_format(*names, binary_format, repeat=1, call=None):
return fmt


class AreaFile:
class AreaFile(AbstractDataStore):
"""McIDAS AREA decoder class."""

directory_format = [
Expand Down Expand Up @@ -403,31 +405,51 @@ def _get_data(self):
buffer = self._buffer.read_array(nx, data_dtype)
data[j, :] = buffer

# Store image in xarray.Dataset
da = DataArray(
data=data[np.newaxis, ...],
coords={
'time': [self._timestamp],
'x': self._x,
'y': self._y,
'longitude': (('y', 'x'), self._lons),
'latitude': (('y', 'x'), self._lats),
'metpy_crs': CFProjection(self._crs.to_cf())
},
dims=['time', 'y', 'x'],
name='image'
)
self._image = data

def _make_time_var(self):
return 'time', Variable('time', [self._timestamp])

def _make_coord_vars(self):
x_var = Variable(('x',), self._x, {
'units': 'm' if self.is_projected else None,
'long_name': 'x coordinate of projection',
'standard_name': 'projection_x_coordinate'
})

y_var = Variable(('y',), self._y, {
'units': 'm' if self.is_projected else None,
'long_name': 'y coordinate of projection',
'standard_name': 'projection_y_coordinate'
})

lon_var = Variable(('y', 'x'), self._lons, {
'units': 'degrees_east',
'long_name': 'longitude',
'standard_name': 'longitude'
})

lat_var = Variable(('y', 'x'), self._lats, {
'units': 'degrees_north',
'long_name': 'latitude',
'standard_name': 'latitude'
})

if self.is_projected:
da['x'].attrs['units'] = 'meters'
da['y'].attrs['units'] = 'meters'
return [('x', x_var), ('y', y_var), ('lon', lon_var), ('lat', lat_var),
('metpy_crs', CFProjection(self._crs.to_cf()))]

da['longitude'].attrs['units'] = 'degrees_east'
da['longitude'].attrs['standard_name'] = 'longitude'
da['latitude'].attrs['units'] = 'degrees_north'
da['latitude'].attrs['standard_name'] = 'latitude'
def _make_data_var(self):
data_var = Variable(('time', 'y', 'x'), self._image[np.newaxis, ...])

self._image = da
return 'image', data_var

def get_variables(self):
"""Get variables in AREA file."""
variables = [self._make_time_var()]
variables.extend(self._make_coord_vars())
variables.extend(self._make_data_var())

return dict(variables)

@staticmethod
def _get_navigation_format(navigation_type):
Expand Down Expand Up @@ -806,3 +828,15 @@ def _swap_bytes(self, binary):
else:
self.prefmt = ''
self.endian = sys.byteorder


class AreaFileXarrayBackend(BackendEntrypoint):
""""Entry point for the direct reacding of McIDAS AREA files."""

def open_dataset(self, filename_or_obj, *, drop_variables=None):
"""Open the McIDAS AREA file as an Xarray dataset."""
area = AreaFile(filename_or_obj)
coords = dict(area._make_coord_vars() + [area._make_time_var()])
data_name, data_var = area._make_data_var()

return Dataset({data_name: data_var}, coords)

0 comments on commit 7b14664

Please sign in to comment.