Skip to content

Commit

Permalink
Merge 434b5b9 into c729121
Browse files Browse the repository at this point in the history
  • Loading branch information
ecarrara committed Jun 27, 2019
2 parents c729121 + 434b5b9 commit 6fb4e7f
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
4 changes: 4 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ Enhancements
By `David Huard <https://github.com/huard>`_.
- Add ``keepdims`` argument for reduce operations (:issue:`2170`)
By `Scott Wales <https://github.com/ScottWales>`_.
- Add ``scales``, ``offsets``, ``units``, ``descriptions`` and ``mask_flag_enums``
attributes to :py:class:`~xarray.DataArray` returned by
:py:func:`~xarray.open_rasterio`. (:issue:`3013`)
By `Erle Carrara <https://github.com/ecarrara>`_.
- netCDF chunksizes are now only dropped when original_shape is different,
not when it isn't found. (:issue:`2207`)
By `Karel van de Plassche <https://github.com/Karel-van-de-Plassche>`_.
Expand Down
12 changes: 12 additions & 0 deletions xarray/backends/rasterio_.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,18 @@ def open_rasterio(filename, parse_coordinates=None, chunks=None, cache=None,
attrs['nodatavals'] = tuple(
np.nan if nodataval is None else nodataval
for nodataval in riods.nodatavals)
if hasattr(riods, 'scales'):
# The scale values for the raster bands
attrs['scales'] = riods.scales
if hasattr(riods, 'offsets'):
# The offset values for the raster bands
attrs['offsets'] = riods.offsets
if hasattr(riods, 'descriptions') and any(riods.descriptions):
# Descriptions for each dataset band
attrs['descriptions'] = riods.descriptions
if hasattr(riods, 'units') and any(riods.units):
# A list of units string for each dataset band
attrs['units'] = riods.units

# Parse extra metadata from tags, if supported
parsers = {'ENVI': _parse_envi}
Expand Down
30 changes: 28 additions & 2 deletions xarray/tests/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -3162,7 +3162,8 @@ def create_tmp_geotiff(nx=4, ny=3, nz=3,
transform_args=[5000, 80000, 1000, 2000.],
crs={'units': 'm', 'no_defs': True, 'ellps': 'WGS84',
'proj': 'utm', 'zone': 18},
open_kwargs=None):
open_kwargs=None,
additional_attrs=None):
# yields a temporary geotiff file and a corresponding expected DataArray
import rasterio
from rasterio.transform import from_origin
Expand All @@ -3185,13 +3186,20 @@ def create_tmp_geotiff(nx=4, ny=3, nz=3,
*data_shape)
if transform is None:
transform = from_origin(*transform_args)
if additional_attrs is None:
additional_attrs = {
'descriptions': tuple('d{}'.format(n + 1) for n in range(nz)),
'units': tuple('u{}'.format(n + 1) for n in range(nz)),
}
with rasterio.open(
tmp_file, 'w',
driver='GTiff', height=ny, width=nx, count=nz,
crs=crs,
transform=transform,
dtype=rasterio.float32,
**open_kwargs) as s:
for attr, val in additional_attrs.items():
setattr(s, attr, val)
s.write(data, **write_kwargs)
dx, dy = s.res[0], -s.res[1]

Expand All @@ -3211,7 +3219,7 @@ class TestRasterio:

@requires_scipy_or_netCDF4
def test_serialization(self):
with create_tmp_geotiff() as (tmp_file, expected):
with create_tmp_geotiff(additional_attrs={}) as (tmp_file, expected):
# Write it to a netcdf and read again (roundtrip)
with xr.open_rasterio(tmp_file) as rioda:
with create_tmp_file(suffix='.nc') as tmp_nc_file:
Expand All @@ -3223,6 +3231,10 @@ def test_utm(self):
with create_tmp_geotiff() as (tmp_file, expected):
with xr.open_rasterio(tmp_file) as rioda:
assert_allclose(rioda, expected)
assert rioda.attrs['scales'] == (1.0, 1.0, 1.0)
assert rioda.attrs['offsets'] == (0.0, 0.0, 0.0)
assert rioda.attrs['descriptions'] == ('d1', 'd2', 'd3')
assert rioda.attrs['units'] == ('u1', 'u2', 'u3')
assert isinstance(rioda.attrs['crs'], str)
assert isinstance(rioda.attrs['res'], tuple)
assert isinstance(rioda.attrs['is_tiled'], np.uint8)
Expand All @@ -3246,6 +3258,10 @@ def test_non_rectilinear(self):
assert 'x' not in rioda.coords
assert 'y' not in rioda.coords
assert 'crs' not in rioda.attrs
assert rioda.attrs['scales'] == (1.0, 1.0, 1.0)
assert rioda.attrs['offsets'] == (0.0, 0.0, 0.0)
assert rioda.attrs['descriptions'] == ('d1', 'd2', 'd3')
assert rioda.attrs['units'] == ('u1', 'u2', 'u3')
assert isinstance(rioda.attrs['res'], tuple)
assert isinstance(rioda.attrs['is_tiled'], np.uint8)
assert isinstance(rioda.attrs['transform'], tuple)
Expand All @@ -3266,6 +3282,10 @@ def test_platecarree(self):
as (tmp_file, expected):
with xr.open_rasterio(tmp_file) as rioda:
assert_allclose(rioda, expected)
assert rioda.attrs['scales'] == (1.0,)
assert rioda.attrs['offsets'] == (0.0,)
assert isinstance(rioda.attrs['descriptions'], tuple)
assert isinstance(rioda.attrs['units'], tuple)
assert isinstance(rioda.attrs['crs'], str)
assert isinstance(rioda.attrs['res'], tuple)
assert isinstance(rioda.attrs['is_tiled'], np.uint8)
Expand Down Expand Up @@ -3294,6 +3314,8 @@ def test_notransform(self):
tmp_file, 'w',
driver='GTiff', height=ny, width=nx, count=nz,
dtype=rasterio.float32) as s:
s.descriptions = ('nx', 'ny', 'nz')
s.units = ('cm', 'm', 'km')
s.write(data)

# Tests
Expand All @@ -3305,6 +3327,10 @@ def test_notransform(self):
})
with xr.open_rasterio(tmp_file) as rioda:
assert_allclose(rioda, expected)
assert rioda.attrs['scales'] == (1.0, 1.0, 1.0)
assert rioda.attrs['offsets'] == (0.0, 0.0, 0.0)
assert rioda.attrs['descriptions'] == ('nx', 'ny', 'nz')
assert rioda.attrs['units'] == ('cm', 'm', 'km')
assert isinstance(rioda.attrs['res'], tuple)
assert isinstance(rioda.attrs['is_tiled'], np.uint8)
assert isinstance(rioda.attrs['transform'], tuple)
Expand Down

0 comments on commit 6fb4e7f

Please sign in to comment.