Skip to content

Commit

Permalink
Merge 0fa80bb into b392c61
Browse files Browse the repository at this point in the history
  • Loading branch information
snowman2 committed Sep 3, 2019
2 parents b392c61 + 0fa80bb commit d947335
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 70 deletions.
180 changes: 153 additions & 27 deletions rioxarray/rioxarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
from datetime import datetime

import numpy as np

import rasterio.warp
import xarray
from affine import Affine
from rasterio.crs import CRS
from rasterio.enums import Resampling
from rasterio.features import geometry_mask
from scipy.interpolate import griddata

from rioxarray.crs import crs_to_wkt
from rioxarray.exceptions import (
DimensionError,
InvalidDimensionOrder,
Expand All @@ -31,7 +31,7 @@
OneDimensionalRaster,
TooManyDimensions,
)
from rioxarray.crs import crs_to_wkt
from scipy.interpolate import griddata

FILL_VALUE_NAMES = ("_FillValue", "missing_value", "fill_value", "nodata")
UNWANTED_RIO_ATTRS = ("nodatavals", "crs", "is_tiled", "res")
Expand Down Expand Up @@ -143,7 +143,7 @@ def _add_attrs_proj(new_data_array, src_data_array):
if "_FillValue" in new_data_array.encoding:
new_attrs.pop("_FillValue", None)

new_data_array.attrs = new_attrs
new_data_array.rio.set_attrs(new_attrs, inplace=True)

# make sure projection added
add_xy_grid_meta(new_data_array.coords)
Expand Down Expand Up @@ -229,6 +229,23 @@ def crs(self):
"""
raise NotImplementedError

def _get_obj(self, inplace):
"""
Get the object to modify.
Parameters
----------
inplace: bool
If True, returns self.
Returns
-------
xarray.Dataset or xarray.DataArray:
"""
if inplace:
return self._obj
return self._obj.copy(deep=True)

def set_crs(self, input_crs, inplace=True):
"""
Set the CRS value for the Dataset/DataArray without modifying
Expand All @@ -238,6 +255,8 @@ def set_crs(self, input_crs, inplace=True):
----------
input_crs: object
Anythong accepted by `rasterio.crs.CRS.from_user_input`.
inplace: bool, optional
If True, it will write to the existing dataset. Default is False.
Returns
-------
Expand All @@ -248,12 +267,9 @@ def set_crs(self, input_crs, inplace=True):
if hasattr(input_crs, "wkt"):
input_crs = input_crs.wkt
crs = CRS.from_user_input(input_crs)
if inplace:
self._crs = crs
return self._obj
xobj = self._obj.copy(deep=True)
xobj.rio._crs = crs
return xobj
obj = self._get_obj(inplace=inplace)
obj.rio._crs = crs
return obj

def write_crs(
self, input_crs=None, grid_mapping_name=DEFAULT_GRID_MAP, inplace=False
Expand All @@ -278,11 +294,9 @@ def write_crs(
"""
if input_crs is not None:
data_obj = self.set_crs(input_crs, inplace=inplace)
elif inplace:
data_obj = self._obj
else:
data_obj = self._obj.copy(deep=True)

data_obj = self._get_obj(inplace=inplace)
# remove old grid maping coordinate if exists
try:
del data_obj.coords[grid_mapping_name]
Expand All @@ -299,7 +313,7 @@ def write_crs(
# http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/cf-conventions.html#appendix-grid-mappings
# http://desktop.arcgis.com/en/arcmap/10.3/manage-data/netcdf/spatial-reference-for-netcdf-data.htm
grid_map_attrs["crs_wkt"] = crs_wkt
data_obj.coords[grid_mapping_name].attrs = grid_map_attrs
data_obj.coords[grid_mapping_name].rio.set_attrs(grid_map_attrs, inplace=True)

# add grid mapping attribute to variables
if hasattr(data_obj, "data_vars"):
Expand All @@ -308,15 +322,110 @@ def write_crs(
self.x_dim in data_obj[var].dims
and self.y_dim in data_obj[var].dims
):
var_attrs = dict(data_obj[var].attrs)
var_attrs.update(grid_mapping=grid_mapping_name)
data_obj[var].attrs = var_attrs
data_obj[var].rio.update_attrs(
dict(grid_mapping=grid_mapping_name), inplace=True
)
else:
var_attrs = dict(data_obj.attrs)
var_attrs.update(grid_mapping=grid_mapping_name)
data_obj.attrs = var_attrs
data_obj.rio.update_attrs(
dict(grid_mapping=grid_mapping_name), inplace=True
)
return data_obj

def write_nodata(self, input_nodata, inplace=False):
"""
Write the nodata to the dataset in a CF compliant manner.
Parameters
----------
input_nodata: object
Nodata value for the dataset.
If input_nodata is None, it will remove the _FillValue attribute.
inplace: bool, optional
If True, it will write to the existing dataset. Default is False.
Returns
-------
xarray.Dataset or xarray.DataArray:
Modified dataset with CF compliant nodata information.
"""
data_obj = self._get_obj(inplace=inplace)
input_nodata = False if input_nodata is None else input_nodata
# add grid mapping attribute to variables
if hasattr(data_obj, "data_vars"):
for var in data_obj.data_vars:
if input_nodata is not False:
data_obj[var].rio.update_attrs(
dict(_FillValue=input_nodata), inplace=True
)
else:
new_vars = dict(data_obj[var].attrs)
new_vars.pop("_FillValue", None)
data_obj[var].rio.set_attrs(
new_vars, inplace=True
)
data_obj[var].rio._nodata = input_nodata
else:
if input_nodata is not False:
data_obj.rio.update_attrs(
dict(_FillValue=input_nodata), inplace=True
)
else:
new_vars = dict(data_obj.attrs)
new_vars.pop("_FillValue", None)
data_obj.rio.set_attrs(
new_vars, inplace=True
)
data_obj.rio._nodata = input_nodata
return data_obj

def set_attrs(self, new_attrs, inplace=False):
"""
Set the attributes of the dataset/dataarray and reset
rioxarray properties to re-search for them.
Parameters
----------
new_attrs: dict
A dictionary of new attributes.
inplace: bool, optional
If True, it will write to the existing dataset. Default is False.
Returns
-------
xarray.Dataset or xarray.DataArray:
Modified dataset with new attributes.
"""
data_obj = self._get_obj(inplace=inplace)
# set the attributes
data_obj.attrs = new_attrs
# reset rioxarray properties
data_obj.rio._nodata = None
data_obj.rio._crs = None
return data_obj

def update_attrs(self, new_attrs, inplace=False):
"""
Update the attributes of the dataset/dataarray and reset
rioxarray properties to re-search for them.
Parameters
----------
new_attrs: dict
A dictionary of new attributes to update with.
inplace: bool, optional
If True, it will write to the existing dataset. Default is False.
Returns
-------
xarray.Dataset or xarray.DataArray:
Modified dataset with updated attributes.
"""
data_attrs = dict(self._obj.attrs)
data_attrs.update(**new_attrs)
return self.set_attrs(data_attrs, inplace=inplace)

def set_spatial_dims(self, x_dim, y_dim, inplace=True):
"""
This sets the spatial dimensions of the dataset.
Expand Down Expand Up @@ -348,12 +457,9 @@ def set_dims(obj, in_x_dim, in_y_dim):
else:
raise DimensionError("y dimension not found: {}".format(y_dim))

if not inplace:
obj_copy = self._obj.copy()
set_dims(obj_copy, x_dim, y_dim)
return obj_copy
set_dims(self._obj, x_dim, y_dim)
return self._obj
data_obj = self._get_obj(inplace=inplace)
set_dims(data_obj, x_dim, y_dim)
return data_obj

@property
def x_dim(self):
Expand Down Expand Up @@ -402,6 +508,26 @@ def __init__(self, xarray_obj):
# properties
self._nodata = None

def set_nodata(self, input_nodata, inplace=True):
"""
Set the nodata value for the DataArray without modifying
the data array.
Parameters
----------
input_nodata: object
Valid nodata for dtype.
inplace: bool, optional
If True, it will write to the existing dataset. Default is False.
Returns
-------
xarray.DataArray: Dataset with nodata attribute set.
"""
obj = self._get_obj(inplace=inplace)
obj.rio._nodata = input_nodata
return obj

@property
def crs(self):
""":obj:`rasterio.crs.CRS`:
Expand Down
56 changes: 16 additions & 40 deletions sphinx/examples/convert_to_raster.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@
{
"data": {
"text/plain": [
"OrderedDict()"
"(OrderedDict(), None, None)"
]
},
"execution_count": 7,
Expand All @@ -223,41 +223,21 @@
],
"source": [
"new_ds = rds.green + rds.blue\n",
"new_ds.attrs"
"new_ds.attrs, new_ds.rio.crs, new_ds.rio.nodata"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(None, None)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"new_ds.rio.crs, new_ds.rio.nodata"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"new_ds.rio.to_raster(\"combination.tif\")"
]
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 9,
"metadata": {},
"outputs": [
{
Expand All @@ -274,38 +254,34 @@
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"new_ds = rds.green + rds.blue\n",
"new_ds.attrs = rds.green.attrs\n",
"new_ds = new_ds.rio.write_crs(rds.green.rio.crs)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(CRS.from_epsg(32722), 0.0)"
"(OrderedDict([('grid_mapping', 'spatial_ref'),\n",
" ('units', 'DN'),\n",
" ('nodata', 0.0)]),\n",
" CRS.from_epsg(32722),\n",
" 0.0)"
]
},
"execution_count": 12,
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"new_ds.rio.crs, new_ds.rio.nodata"
"new_ds = rds.green + rds.blue\n",
"new_ds.rio.write_crs(rds.green.rio.crs, inplace=True)\n",
"new_ds.rio.update_attrs(rds.green.attrs, inplace=True)\n",
"new_ds.attrs, new_ds.rio.crs, new_ds.rio.nodata"
]
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -314,7 +290,7 @@
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": 12,
"metadata": {},
"outputs": [
{
Expand Down
1 change: 1 addition & 0 deletions sphinx/history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ History
------
- Add support for opening netcdf/hdf files with `rioxarray.open_rasterio` (issue #32)
- Added support for custom CRS with wkt attribute for datacube CRS support (issue #35)
- Added `rio.set_nodata()`, `rio.write_nodata()`, `rio.set_attrs()`, `rio.update_attrs()` (issue #37)

0.0.9
-----
Expand Down

0 comments on commit d947335

Please sign in to comment.