Skip to content

Commit

Permalink
REF: Reduce pyproj.CRS internal usage for speed (#242)
Browse files Browse the repository at this point in the history
  • Loading branch information
snowman2 authored Feb 15, 2021
1 parent 4b9ddcb commit 29fb395
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 14 deletions.
1 change: 1 addition & 0 deletions docs/history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ History

Latest
------
- REF: Reduce pyproj.CRS internal usage for speed (issue #241)

0.2.0
------
Expand Down
2 changes: 1 addition & 1 deletion rioxarray/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ def _parse_tags(tags):
2: np.char, # NC_CHAR
3: np.short, # NC_SHORT
4: np.int_, # NC_INT, NC_LONG
5: np.float, # NC_FLOAT
5: float, # NC_FLOAT
6: np.double, # NC_DOUBLE
7: np.ubyte, # NC_UBYTE
8: np.ushort, # NC_USHORT
Expand Down
20 changes: 15 additions & 5 deletions rioxarray/crs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
from distutils.version import LooseVersion

import rasterio
import rasterio.crs
from pyproj import CRS
from rasterio.errors import CRSError


def crs_to_wkt(crs_input):
def crs_from_user_input(crs_input):
"""
Return a rasterio.crs.CRS from user input.
This is to deal with change in rasterio.crs.CRS
as well as to assist in the transition between GDAL 2/3.
Expand All @@ -20,16 +24,22 @@ def crs_to_wkt(crs_input):
Returns
-------
str: WKT string.
rasterio.crs.CRS
"""
if isinstance(crs_input, rasterio.crs.CRS):
return crs_input
try:
# rasterio.crs.CRS <1.0.14 and
# old versions of opendatacube CRS
crs_input = crs_input.wkt
except AttributeError:
pass
try:
return rasterio.crs.CRS.from_user_input(crs_input)
except CRSError:
pass
# use pyproj for edge cases
crs = CRS.from_user_input(crs_input)
if LooseVersion(rasterio.__gdal_version__) > LooseVersion("3.0.0"):
return crs.to_wkt()
return crs.to_wkt("WKT1_GDAL")
return rasterio.crs.CRS.from_wkt(crs.to_wkt())
return rasterio.crs.CRS.from_wkt(crs.to_wkt("WKT1_GDAL"))
8 changes: 3 additions & 5 deletions rioxarray/raster_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@
import rasterio.mask
import rasterio.warp
import xarray
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.crs import crs_from_user_input
from rioxarray.exceptions import (
MissingCRS,
NoDataInBounds,
Expand Down Expand Up @@ -430,9 +429,8 @@ def reproject_match(self, match_data_array, resampling=Resampling.nearest):
Contains the data from the src_data_array, reprojected to match
match_data_array.
"""
dst_crs = crs_to_wkt(match_data_array.rio.crs)
return self.reproject(
dst_crs,
match_data_array.rio.crs,
transform=match_data_array.rio.transform(recalc=True),
shape=match_data_array.rio.shape,
resampling=resampling,
Expand Down Expand Up @@ -697,7 +695,7 @@ def clip(
"CRS not found. Please set the CRS with 'rio.write_crs()'."
f"{_get_data_var_message(self._obj)}"
)
crs = CRS.from_wkt(crs_to_wkt(crs)) if crs is not None else self.crs
crs = crs_from_user_input(crs) if crs is not None else self.crs
if self.crs != crs:
if LooseVersion(rasterio.__version__) >= LooseVersion("1.2"):
geometries = rasterio.warp.transform_geom(crs, self.crs, geometries)
Expand Down
18 changes: 15 additions & 3 deletions rioxarray/rioxarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from affine import Affine
from rasterio.crs import CRS

from rioxarray.crs import crs_to_wkt
from rioxarray.crs import crs_from_user_input
from rioxarray.exceptions import (
DimensionError,
DimensionMissingCoordinateError,
Expand Down Expand Up @@ -151,6 +151,18 @@ def crs(self):
if self._crs is not None:
return None if self._crs is False else self._crs

# look in wkt attributes to avoid using
# pyproj CRS if possible for performance
for crs_attr in ("spatial_ref", "crs_wkt"):
try:
self.set_crs(
self._obj.coords[self.grid_mapping].attrs[crs_attr],
inplace=True,
)
return self._crs
except KeyError:
pass

# look in grid_mapping
try:
self.set_crs(
Expand Down Expand Up @@ -207,7 +219,7 @@ def set_crs(self, input_crs, inplace=True):
:obj:`xarray.Dataset` | :obj:`xarray.DataArray`:
Dataset with crs attribute.
"""
crs = CRS.from_wkt(crs_to_wkt(input_crs))
crs = crs_from_user_input(input_crs)
obj = self._get_obj(inplace=inplace)
obj.rio._crs = crs
return obj
Expand Down Expand Up @@ -316,7 +328,7 @@ def write_crs(self, input_crs=None, grid_mapping_name=None, inplace=False):
data_obj.coords[grid_mapping_name] = xarray.Variable((), 0)
grid_map_attrs = pyproj.CRS.from_user_input(data_obj.rio.crs).to_cf()
# spatial_ref is for compatibility with GDAL
crs_wkt = crs_to_wkt(data_obj.rio.crs)
crs_wkt = data_obj.rio.crs.to_wkt()
grid_map_attrs["spatial_ref"] = crs_wkt
grid_map_attrs["crs_wkt"] = crs_wkt
if transform is not None:
Expand Down

0 comments on commit 29fb395

Please sign in to comment.