Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read grid mapping and bounds as coords #2844

Merged
merged 40 commits into from
Feb 17, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
62152d0
Read and save `grid_mapping` and `bounds` as coordinates.
DWesl Mar 21, 2019
2ae8a7e
Add tests for (de)serialization of `grid_mapping` and `bounds`.
DWesl Mar 21, 2019
fff73c8
BUG: Use only encoding for tracking bounds and grid_mapping.
DWesl Mar 31, 2019
b3696d3
Address feedback on PR.
DWesl May 31, 2019
315d39d
Merge branch 'master' into read_grid_mapping_and_bounds_as_coords
DWesl May 31, 2019
c82cd47
Merge branch 'master' into read_grid_mapping_and_bounds_as_coords
DWesl Feb 14, 2020
02aff73
Style fixes: newline before binary operator.
DWesl Feb 14, 2020
0721506
Style fixes: double quotes for string literals, rewrap lines.
DWesl Feb 14, 2020
239761e
Address comments from review.
DWesl Jul 9, 2020
e0b8e99
Fix style issues and complete name changes.
DWesl Jul 9, 2020
9ba7485
Add more attributes from the CF conventions.
DWesl Aug 2, 2020
bf97fe1
Merge branch 'master' into read_grid_mapping_and_bounds_as_coords
DWesl Aug 2, 2020
4274730
Remove a trailing comma in a one-element dict literal.
DWesl Aug 2, 2020
ca0f805
Merge branch 'master' into read_grid_mapping_and_bounds_as_coords
DWesl Aug 7, 2020
7027767
Stop moving ancillary_variables to coords
DWesl Aug 9, 2020
8d96a66
Expand the list of attributes in the documentation.
DWesl Aug 16, 2020
1a5b35d
Make sure to run the pip associated with the running python.
DWesl Aug 16, 2020
9f53fbb
Warn about new locations for some variables.
DWesl Aug 16, 2020
1b8218d
Merge branch 'master' into read_grid_mapping_and_bounds_as_coords
DWesl Aug 17, 2020
546b43e
Move ancillary variables back to data_vars in test.
DWesl Aug 23, 2020
8ec4af3
Update warnings to provide a more useful stack level.
DWesl Aug 23, 2020
bc0b1d1
Split the CF attribute test into multiple smaller tests.
DWesl Aug 23, 2020
5c085e1
Add a test of a roundtrip after dropping bounds.
DWesl Aug 23, 2020
a5a67d1
Merge work from github back into local branch.
DWesl Aug 23, 2020
a864b83
Run black on changes.
DWesl Aug 23, 2020
c8d1bdc
Check whether round-trip to iris breaks things.
DWesl Aug 23, 2020
478be8a
Remove trailing comma.
DWesl Aug 23, 2020
036695c
Merge branch 'master' into read_grid_mapping_and_bounds_as_coords
DWesl Jan 5, 2021
b0e7a85
Style fixes from black.
DWesl Jan 5, 2021
1a9b201
Include suggestions from review.
DWesl Jan 16, 2021
6f3d55e
Update xarray/tests/test_backends.py
DWesl Jan 17, 2021
5268500
Update xarray/conventions.py
DWesl Jan 17, 2021
2edd367
Mention that there are other attributes not listed
DWesl Jan 17, 2021
948465c
Fix .rst syntax in whats-new
DWesl Jan 17, 2021
c68d372
Shorten name of another test.
DWesl Jan 17, 2021
9ee7c3a
Update docs.
dcherian Jan 17, 2021
b65e579
Merge remote-tracking branch 'upstream/master' into read_grid_mapping…
dcherian Feb 11, 2021
94b8153
fix merge.
dcherian Feb 11, 2021
c8896f3
Activate new behaviour only with `decode_coords="all"`
dcherian Feb 11, 2021
d3ec7ab
[skip-ci] fix docstrings
dcherian Feb 11, 2021
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
25 changes: 25 additions & 0 deletions xarray/conventions.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,18 @@ def stackable(dim):
new_vars[k].encoding['coordinates'] = coord_str
del var_attrs['coordinates']
coord_names.update(var_coord_names)
if 'bounds' in var_attrs:
bounds_str = var_attrs['bounds']
var_bounds_names = [bounds_str]
if all(k in variables for k in var_bounds_names):
new_vars[k].encoding['bounds'] = bounds_str
coord_names.update(var_bounds_names)
if 'grid_mapping' in var_attrs:
proj_str = var_attrs['grid_mapping']
var_proj_names = proj_str.split()
if all(k in variables for k in var_proj_names):
new_vars[k].encoding['grid_mapping'] = proj_str
coord_names.update(var_proj_names)

if decode_coords and 'coordinates' in attributes:
attributes = OrderedDict(attributes)
Expand Down Expand Up @@ -535,6 +547,7 @@ def _encode_coordinates(variables, attributes, non_dim_coord_names):

global_coordinates = non_dim_coord_names.copy()
variable_coordinates = defaultdict(set)
not_technically_coordinates = set()
for coord_name in non_dim_coord_names:
target_dims = variables[coord_name].dims
for k, v in variables.items():
Expand All @@ -543,6 +556,12 @@ def _encode_coordinates(variables, attributes, non_dim_coord_names):
variable_coordinates[k].add(coord_name)
global_coordinates.discard(coord_name)

att_val = v.attrs.get
if ((att_val("bounds", None) == coord_name or
att_val("grid_mapping", None) == coord_name)):
not_technically_coordinates.add(coord_name)
global_coordinates.discard(coord_name)

variables = OrderedDict((k, v.copy(deep=False))
for k, v in variables.items())

Expand All @@ -553,6 +572,12 @@ def _encode_coordinates(variables, attributes, non_dim_coord_names):
raise ValueError('cannot serialize coordinates because variable '
"%s already has an attribute 'coordinates'"
% var_name)

# Only add actual coordinates to coordinates
# Exceptions are created using CF mechanisms
# Non-CF datasets work as previously
for not_coord in not_technically_coordinates:
coord_names.discard(not_coord)
attrs['coordinates'] = ' '.join(map(str, coord_names))

# These coordinates are not associated with any particular variables, so we
Expand Down
34 changes: 34 additions & 0 deletions xarray/tests/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,40 @@ def test_roundtrip_mask_and_scale(self, decoded_fn, encoded_fn):
actual.variables[k].dtype)
assert_allclose(decoded, actual, decode_bytes=False)

def test_grid_mapping_and_bounds_are_coordinates(self):
original = Dataset(
dict(variable=(('latitude', 'longitude'),
[[0, 1], [2, 3]],
{'grid_mapping': 'latlon'})),
dict(
latitude=('latitude',
[0, 1],
{'bounds': 'latitude_bnds',
'grid_mapping': 'latlon'}),
longitude=('longitude',
[0, 1],
{'bounds': 'longitude_bnds',
'grid_mapping': 'latlon'}),
latlon=((), -1, {'grid_mapping_name': 'latitude_longitude'}),
latitude_bnds=(('latitude', 'bnds2'),
[[0, 1], [1, 2]]),
longitude_bnds=(('longitude', 'bnds2'),
[[0, 1], [1, 2]])
)
)
with self.roundtrip(original) as actual:
assert_identical(actual, original)

with create_tmp_file() as tmp_file:
original.to_netcdf(tmp_file)
with open_dataset(tmp_file, decode_coords=False) as ds:
assert (ds.coords['latitude'].attrs['bounds'] ==
'latitude_bnds')
assert (ds.coords['longitude'].attrs['bounds'] ==
'longitude_bnds')
assert 'latlon' not in ds['variable'].attrs['coordinates']
assert 'coordinates' not in ds.attrs

def test_coordinates_encoding(self):
def equals_latlon(obj):
return obj == 'lat lon' or obj == 'lon lat'
Expand Down