From 903192a9e57959c7800a63317a98b15a5f577ed8 Mon Sep 17 00:00:00 2001 From: "Philipp S. Sommer" Date: Tue, 7 Apr 2020 13:34:40 +0200 Subject: [PATCH 1/4] decode the grid_mapping attribute following the CF-conventions at http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html, variables stored in a grid_mappings attribute are decoded as coordinates --- psyplot/data.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/psyplot/data.py b/psyplot/data.py index ee2d881..cd56c37 100755 --- a/psyplot/data.py +++ b/psyplot/data.py @@ -646,6 +646,8 @@ def add_attrs(obj): if 'coordinates' in obj.attrs: extra_coords.update(obj.attrs['coordinates'].split()) obj.encoding['coordinates'] = obj.attrs.pop('coordinates') + if 'grid_mapping' in obj.attrs: + extra_coords.add(obj.attrs['grid_mapping']) if 'bounds' in obj.attrs: extra_coords.add(obj.attrs['bounds']) if gridfile is not None and not isinstance(gridfile, xr.Dataset): @@ -920,10 +922,13 @@ def get_variable_by_axis(self, var, axis, coords=None): coord_names, var.dims))): # check for the axis attribute or whether the coordinate is in the # list of possible coordinate names - if (coord.name not in (c.name for c in ret) and - (coord.attrs.get('axis', '').lower() == axis or - coord.name in getattr(self, axis))): - ret.append(coord) + if coord.name not in (c.name for c in ret): + if coord.name in getattr(self, axis): + ret.clear() + ret.append(coord) + break + elif coord.attrs.get('axis', '').lower() == axis: + ret.append(coord) if ret: return None if len(ret) > 1 else ret[0] # If the coordinates attribute is specified but the coordinate From 5c8549d66da35ec8a8911c37811e068ddf9d3680 Mon Sep 17 00:00:00 2001 From: "Philipp S. Sommer" Date: Tue, 7 Apr 2020 13:40:51 +0200 Subject: [PATCH 2/4] add test for decoded grid_mappings --- tests/test_data.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_data.py b/tests/test_data.py index 0e451fa..9caeebe 100755 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -81,6 +81,15 @@ def assertAlmostArrayEqual(self, actual, desired, rtol=1e-07, atol=0, class DecoderTest(unittest.TestCase, AlmostArrayEqualMixin): """Test the :class:`psyplot.data.CFDecoder` class""" + def test_decode_grid_mapping(self): + ds = xr.Dataset() + ds['var'] = (('x', 'y'), np.zeros((5, 4)), {'grid_mapping': 'crs'}) + ds['crs'] = ((), 1) + + self.assertNotIn('crs', ds.coords) + ds = psyd.CFDecoder.decode_coords(ds) + self.assertIn('crs', ds.coords) + def test_1D_cf_bounds(self): """Test whether the CF Conventions for 1D bounaries are correct""" final_bounds = np.arange(-180, 181, 30) From 93a6bc91e7fa1487d15386425212f544e0fad737 Mon Sep 17 00:00:00 2001 From: "Philipp S. Sommer" Date: Tue, 7 Apr 2020 14:10:51 +0200 Subject: [PATCH 3/4] warn when dimension list matches multiples This commit treats matches with dimension lists (such as CFDecoder.x) different than the coordinates or axis attribute. --- psyplot/data.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/psyplot/data.py b/psyplot/data.py index cd56c37..3e4f2c4 100755 --- a/psyplot/data.py +++ b/psyplot/data.py @@ -917,6 +917,7 @@ def get_variable_by_axis(self, var, axis, coords=None): if not coord_names: return ret = [] + matched = [] for coord in map(lambda dim: coords[dim], filter( lambda dim: dim in coords, chain( coord_names, var.dims))): @@ -924,12 +925,18 @@ def get_variable_by_axis(self, var, axis, coords=None): # list of possible coordinate names if coord.name not in (c.name for c in ret): if coord.name in getattr(self, axis): - ret.clear() - ret.append(coord) - break + matched.append(coord) elif coord.attrs.get('axis', '').lower() == axis: ret.append(coord) - if ret: + if matched: + if len(matched) > 1: + warn("Found multiple matches for %s coordinate in the " + "coordinates: %s. I use %s" % ( + axis, ', '.join([c.name for c in matched]), + matched[0].name), + PsyPlotRuntimeWarning) + return matched[0] + elif ret: return None if len(ret) > 1 else ret[0] # If the coordinates attribute is specified but the coordinate # variables themselves have no 'axis' attribute, we interpret the From f72c3b8da229289d235d533d44b81dddab968ad3 Mon Sep 17 00:00:00 2001 From: "Philipp S. Sommer" Date: Tue, 7 Apr 2020 14:10:59 +0200 Subject: [PATCH 4/4] update changelog --- CHANGELOG.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 42ab3cd..2cb8f2d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,18 @@ v1.2.2 ====== +Added +----- +* `psyplot.data.open_dataset` now decodes grid_mappings attributes, +see `#17 `__ + +Changed +------- * psyplot has been moved from https://github.com/Chilipp/psyplot to https://github.com/psyplot/psyplot, see `#16 `__ +* Specifying names in `x`, `y`, `t` and `z` attributes of the `CFDecoder` class + now means that any other attribute (such as the `coordinates` or `axis` attribute) + are ignored + v1.2.1 ======