Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ v1.2.2
======
Added
-----
* ``ArrayList.from_dataset`` (and consecutively all plotmethods) now support
different input types for the decoder. You can pass an instance of the
``CFDecoder`` class, a sub class of ``CFDecoder``, or keyword arguments
that are used to initialize the decoder,
see `#20 <https://github.com/psyplot/psyplot/pull/20>`__
* `psyplot.data.open_dataset` now decodes grid_mappings attributes,
see `#17 <https://github.com/psyplot/psyplot/pull/17>`__
* psyplot projects now support the with syntax, e.g. something like::
Expand All @@ -20,6 +25,8 @@ Changed
are ignored
* If a given variable cannot be found in the provided coords to ``CFDecoder.get_variable_by_axis``,
we fall back to the ``CFDecoder.ds.coords`` attribute, see `#19 <https://github.com/psyplot/psyplot/pull/19>`__
* A bug has been fixed for initializing a ``CFDecoder`` with ``x, y, z`` and
``t`` parameters (see `#20 <https://github.com/psyplot/psyplot/pull/20>`__)


v1.2.1
Expand Down
42 changes: 27 additions & 15 deletions psyplot/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,9 +550,9 @@ def logger(self, value):
def __init__(self, ds=None, x=None, y=None, z=None, t=None):
self.ds = ds
self.x = rcParams['decoder.x'].copy() if x is None else set(x)
self.y = rcParams['decoder.y'].copy() if x is None else set(y)
self.z = rcParams['decoder.z'].copy() if x is None else set(z)
self.t = rcParams['decoder.t'].copy() if x is None else set(t)
self.y = rcParams['decoder.y'].copy() if y is None else set(y)
self.z = rcParams['decoder.z'].copy() if z is None else set(z)
self.t = rcParams['decoder.t'].copy() if t is None else set(t)

@staticmethod
def register_decoder(decoder_class, pos=0):
Expand Down Expand Up @@ -599,7 +599,7 @@ def can_decode(cls, ds, var):

@classmethod
@docstrings.dedent
def get_decoder(cls, ds, var):
def get_decoder(cls, ds, var, *args, **kwargs):
"""
Class method to get the right decoder class that can decode the
given dataset and variable
Expand All @@ -615,8 +615,8 @@ def get_decoder(cls, ds, var):
`var`"""
for decoder_cls in cls._registry:
if decoder_cls.can_decode(ds, var):
return decoder_cls(ds)
return CFDecoder(ds)
return decoder_cls(ds, *args, **kwargs)
return CFDecoder(ds, *args, **kwargs)

@staticmethod
@docstrings.get_sectionsf('CFDecoder.decode_coords', sections=[
Expand Down Expand Up @@ -3568,8 +3568,14 @@ def from_dataset(cls, base, method='isel', default_slice=None,
Index (e.g. 0 if `method` is 'isel') that shall be used for
dimensions not covered by `dims` and `furtherdims`. If None, the
whole slice will be used.
decoder: CFDecoder
The decoder that shall be used to decoder the `base` dataset
decoder: CFDecoder or dict
Arguments for the decoder. This can be one of

- an instance of :class:`CFDecoder`
- a subclass of :class:`CFDecoder`
- a dictionary with keyword-arguments to the automatically
determined decoder class
- None to automatically set the decoder
squeeze: bool, optional
Default True. If True, and the created arrays have a an axes with
length 1, it is removed from the dimension list (e.g. an array
Expand Down Expand Up @@ -3634,12 +3640,17 @@ def ds2arr(arr):
arr.attrs.update(attrs)
return arr

if decoder is not None:
def get_decoder(arr):
return decoder
else:
def get_decoder(arr):
decoder_input = decoder

def get_decoder(arr):
if decoder_input is None:
return CFDecoder.get_decoder(base, arr)
elif isinstance(decoder_input, CFDecoder):
return decoder_input
elif isinstance(decoder_input, dict):
return CFDecoder.get_decoder(base, arr, **decoder_input)
else:
return decoder_input(base)

def add_missing_dimensions(arr):
# add the missing dimensions to the dataset. This is not anymore
Expand Down Expand Up @@ -3678,7 +3689,8 @@ def sel_method(key, dims, name=None):
ret = squeeze_array(arr.isel(**dims))
# delete the variable dimension for the idims
dims.pop('variable', None)
ret.psy.init_accessor(arr_name=key, base=base, idims=dims)
ret.psy.init_accessor(arr_name=key, base=base, idims=dims,
decoder=decoder)
return maybe_load(ret)
else:
def sel_method(key, dims, name=None):
Expand Down Expand Up @@ -3706,7 +3718,7 @@ def sel_method(key, dims, name=None):
ret = squeeze_array(arr.sel(**dims))
else:
ret = squeeze_array(arr.sel(method=method, **dims))
ret.psy.init_accessor(arr_name=key, base=base)
ret.psy.init_accessor(arr_name=key, base=base, decoder=decoder)
return maybe_load(ret)
if 'name' not in kwargs:
default_names = list(
Expand Down
28 changes: 28 additions & 0 deletions tests/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,34 @@ def test_from_dataset_12_list_and_2_vars(self):
self.assertEqual(len(l[0]), 2)
self.assertEqual(len(l[1]), 2)

def test_from_dataset_13_decoder_class(self):
ds = xr.Dataset(*self._from_dataset_test_variables)

class MyDecoder(psyd.CFDecoder):
pass

l = self.list_class.from_dataset(ds, name="v2", decoder=MyDecoder)
self.assertIsInstance(l[0].psy.decoder, MyDecoder)

def test_from_dataset_14_decoder_instance(self):
ds = xr.Dataset(*self._from_dataset_test_variables)

class MyDecoder(psyd.CFDecoder):
pass

decoder = MyDecoder(ds)

l = self.list_class.from_dataset(ds, name="v2", decoder=decoder)
self.assertIs(l[0].psy.decoder, decoder)

def test_from_dataset_15_decoder_kws(self):
ds = xr.Dataset(*self._from_dataset_test_variables)

l = self.list_class.from_dataset(ds, name="v2",
decoder=dict(x={'myx'}))
self.assertEqual(l[0].psy.decoder.x, {'myx'})


def test_array_info(self):
variables, coords = self._from_dataset_test_variables
variables['v4'] = variables['v3'].copy()
Expand Down