Repository: corteva/rioxarray

Issue:
Cannot clip: x dimension not found
#### Code Sample, a copy-pastable example if possible

```python
data = xr.open_dataset('https://oceandata.sci.gsfc.nasa.gov:443/opendap/MODIST/L3SMI/2020/001/T2020001.L3m_DAY_CHL_chl_ocx_4km.nc')
data = data.rename({"lon": "longitude", "lat": "latitude"})

data.rio.set_spatial_dims(x_dim='longitude', y_dim='latitude')
data.rio.write_crs('EPSG:4826', inplace=True)
data.rio.clip(geometries=regional, crs='EPSG:4826')

---------------------------------------------------------------------------
DimensionError                            Traceback (most recent call last)
<ipython-input-44-7be6870bde44> in <module>
      1 data.rio.set_spatial_dims(x_dim='longitude', y_dim='latitude')
      2 data.rio.write_crs('EPSG:4826', inplace=True)
----> 3 data.rio.clip(geometries=regional, crs='EPSG:4826')

/opt/tljh/user/lib/python3.7/site-packages/rioxarray/rioxarray.py in clip(self, geometries, crs, all_touched, drop, invert)
   1505             clipped_dataset[var] = (
   1506                 self._obj[var]
-> 1507                 .rio.set_spatial_dims(x_dim=self.x_dim, y_dim=self.y_dim, inplace=True)
   1508                 .rio.clip(
   1509                     geometries,

/opt/tljh/user/lib/python3.7/site-packages/rioxarray/rioxarray.py in set_spatial_dims(self, x_dim, y_dim, inplace)
    500 
    501         data_obj = self._get_obj(inplace=inplace)
--> 502         set_dims(data_obj, x_dim, y_dim)
    503         return data_obj
    504 

/opt/tljh/user/lib/python3.7/site-packages/rioxarray/rioxarray.py in set_dims(obj, in_x_dim, in_y_dim)
    493                 obj.rio._x_dim = x_dim
    494             else:
--> 495                 raise DimensionError(f"x dimension not found: {x_dim}")
    496             if y_dim in obj.dims:
    497                 obj.rio._y_dim = y_dim

DimensionError: x dimension not found: longitude

```
#### Problem description
Hi,

I'm trying to clip using a geometry but cannot find the x dimension even after using `set_spatial_dims` .

The regional geometry is in the details section.

Thank you in advance!

#### Expected Output

A clipped version of the file

#### Output of ``pip show rioxarray``

```
Name: rioxarray
Version: 0.0.23
Summary: rasterio xarray extension.
Home-page: https://github.com/corteva/rioxarray
Author: rioxarray Contributors
Author-email: alansnow21@gmail.com
License: BSD license
Location: /opt/tljh/user/lib/python3.7/site-packages
Requires: scipy, xarray, rasterio, pyproj, pillow
Required-by: 
```
<details>
# Paste the output from pip show rioxarray here




# The Geometry:

{'type': 'FeatureCollection',
 'name': 'regional_test',
 'features': [{'type': 'Feature',
   'properties': {'id': 0},
   'geometry': {'type': 'MultiPolygon',
    'coordinates': [[[[-70.97970167, -26.0388336409],
       [-70.983784738, -21.0026871197],
       [-70.0718506076, -21.0020545141],
       [-70.0677675396, -26.0382247972],
       [-70.97970167, -26.0388336409]]]]}}]}

</details>






















Discussion:
snowman2: Ignoring OSX build for now: https://github.com/corteva/rioxarray/issues/100

Patch:
diff --git a/docs/history.rst b/docs/history.rst
index c35367d3..27a12cb2 100644
--- a/docs/history.rst
+++ b/docs/history.rst
@@ -1,6 +1,10 @@
 History
 =======
 
+0.0.24
+------
+- ENH: Add variable names to error messages for clarity (pull #99)
+
 0.0.23
 ------
 - BUG: Fix 'rio.set_spatial_dims' so information saved with 'rio' accesors (issue #94)
diff --git a/rioxarray/rioxarray.py b/rioxarray/rioxarray.py
index 6a4eeb2f..d3b9b0cd 100644
--- a/rioxarray/rioxarray.py
+++ b/rioxarray/rioxarray.py
@@ -264,6 +264,16 @@ def _write_metatata_to_raster(raster_handle, xarray_dataset, tags):
                 raster_handle.set_band_description(iii + 1, band_description)
 
 
+def _get_data_var_message(obj):
+    """
+    Get message for named data variables.
+    """
+    try:
+        return f" Data variable: {obj.name}" if obj.name else ""
+    except AttributeError:
+        return ""
+
+
 class XRasterBase(object):
     """This is the base class for the GIS extensions for xarray"""
 
@@ -492,11 +502,15 @@ class XRasterBase(object):
             if in_x_dim in obj.dims:
                 obj.rio._x_dim = x_dim
             else:
-                raise DimensionError(f"x dimension not found: {x_dim}")
+                raise DimensionError(
+                    f"x dimension ({x_dim}) not found.{_get_data_var_message(obj)}"
+                )
             if y_dim in obj.dims:
                 obj.rio._y_dim = y_dim
             else:
-                raise DimensionError(f"y dimension not found: {y_dim}")
+                raise DimensionError(
+                    f"y dimension ({x_dim}) not found.{_get_data_var_message(obj)}"
+                )
 
         data_obj = self._get_obj(inplace=inplace)
         set_dims(data_obj, x_dim, y_dim)
@@ -508,6 +522,7 @@ class XRasterBase(object):
             return self._x_dim
         raise DimensionError(
             "x dimension not found. 'set_spatial_dims()' can address this."
+            f"{_get_data_var_message(self._obj)}"
         )
 
     @property
@@ -516,6 +531,7 @@ class XRasterBase(object):
             return self._y_dim
         raise DimensionError(
             "x dimension not found. 'set_spatial_dims()' can address this."
+            f"{_get_data_var_message(self._obj)}"
         )
 
     @property
@@ -682,6 +698,7 @@ class RasterArray(XRasterBase):
             if self.width == 1 or self.height == 1:
                 raise OneDimensionalRaster(
                     "Only 1 dimenional array found. Cannot calculate the resolution."
+                    f"{_get_data_var_message(self._obj)}"
                 )
 
             resolution_x = (right - left) / (self.width - 1)
@@ -708,7 +725,10 @@ class RasterArray(XRasterBase):
         """
         extra_dims = list(set(list(self._obj.dims)) - set([self.x_dim, self.y_dim]))
         if len(extra_dims) > 1:
-            raise TooManyDimensions("Only 2D and 3D data arrays supported.")
+            raise TooManyDimensions(
+                "Only 2D and 3D data arrays supported."
+                f"{_get_data_var_message(self._obj)}"
+            )
         elif extra_dims and self._obj.dims != (extra_dims[0], self.y_dim, self.x_dim):
             raise InvalidDimensionOrder(
                 "Invalid dimension order. Expected order: {0}. "
@@ -716,12 +736,14 @@ class RasterArray(XRasterBase):
                 " to reorder your dimensions.".format(
                     (extra_dims[0], self.y_dim, self.x_dim)
                 )
+                + f"{_get_data_var_message(self._obj)}"
             )
         elif not extra_dims and self._obj.dims != (self.y_dim, self.x_dim):
             raise InvalidDimensionOrder(
                 "Invalid dimension order. Expected order: {0}"
                 "You can use `DataArray.transpose{0}` "
                 "to reorder your dimensions.".format((self.y_dim, self.x_dim))
+                + f"{_get_data_var_message(self._obj)}"
             )
         return extra_dims[0] if extra_dims else None
 
@@ -839,6 +861,7 @@ class RasterArray(XRasterBase):
         if self.crs is None:
             raise MissingCRS(
                 "CRS not found. Please set the CRS with 'set_crs()' or 'write_crs()'."
+                f"{_get_data_var_message(self._obj)}"
             )
         src_affine = self.transform()
         if dst_affine_width_height is not None:
@@ -998,6 +1021,7 @@ class RasterArray(XRasterBase):
         if self.width == 1 or self.height == 1:
             raise OneDimensionalRaster(
                 "At least one of the raster x,y coordinates has only one point."
+                f"{_get_data_var_message(self._obj)}"
             )
 
         resolution_x, resolution_y = self.resolution()
@@ -1010,7 +1034,9 @@ class RasterArray(XRasterBase):
         cl_array = self.slice_xy(clip_minx, clip_miny, clip_maxx, clip_maxy)
 
         if cl_array.rio.width < 1 or cl_array.rio.height < 1:
-            raise NoDataInBounds("No data found in bounds.")
+            raise NoDataInBounds(
+                f"No data found in bounds.{_get_data_var_message(self._obj)}"
+            )
 
         if cl_array.rio.width == 1 or cl_array.rio.height == 1:
             if auto_expand and auto_expand < auto_expand_limit:
@@ -1025,6 +1051,7 @@ class RasterArray(XRasterBase):
             raise OneDimensionalRaster(
                 "At least one of the clipped raster x,y coordinates"
                 " has only one point."
+                f"{_get_data_var_message(self._obj)}"
             )
 
         # make sure correct attributes preserved & projection added
@@ -1078,6 +1105,7 @@ class RasterArray(XRasterBase):
         if self.crs is None:
             raise MissingCRS(
                 "CRS not found. Please set the CRS with 'set_crs()' or 'write_crs()'."
+                f"{_get_data_var_message(self._obj)}"
             )
         dst_crs = CRS.from_user_input(crs_to_wkt(crs))
         if self.crs != dst_crs:
@@ -1111,7 +1139,9 @@ class RasterArray(XRasterBase):
             cropped_ds.coords[self.x_dim].size < 1
             or cropped_ds.coords[self.y_dim].size < 1
         ):
-            raise NoDataInBounds("No data found in bounds.")
+            raise NoDataInBounds(
+                f"No data found in bounds.{_get_data_var_message(self._obj)}"
+            )
 
         # make sure correct attributes preserved & projection added
         _add_attrs_proj(cropped_ds, self._obj)


Test patch:
diff --git a/test/integration/test_integration_rioxarray.py b/test/integration/test_integration_rioxarray.py
index bd82ca2a..1ca31ce2 100644
--- a/test/integration/test_integration_rioxarray.py
+++ b/test/integration/test_integration_rioxarray.py
@@ -173,7 +173,12 @@ def test_clip_box__auto_expand(modis_clip):
 
 def test_clip_box__nodata_error(modis_clip):
     with modis_clip["open"](modis_clip["input"]) as xdi:
-        with pytest.raises(NoDataInBounds):
+        var_match = ""
+        if hasattr(xdi, "name") and xdi.name:
+            var_match = " Data variable: __xarray_dataarray_variable__"
+        with pytest.raises(
+            NoDataInBounds, match=f"No data found in bounds.{var_match}"
+        ):
             xdi.rio.clip_box(
                 minx=xdi.x[5].values,
                 miny=xdi.y[7].values,
@@ -184,8 +189,17 @@ def test_clip_box__nodata_error(modis_clip):
 
 def test_clip_box__one_dimension_error(modis_clip):
     with modis_clip["open"](modis_clip["input"]) as xdi:
+        var_match = ""
+        if hasattr(xdi, "name") and xdi.name:
+            var_match = " Data variable: __xarray_dataarray_variable__"
         # test exception after raster clipped
-        with pytest.raises(OneDimensionalRaster):
+        with pytest.raises(
+            OneDimensionalRaster,
+            match=(
+                "At least one of the clipped raster x,y coordinates has "
+                f"only one point.{var_match}"
+            ),
+        ):
             xdi.rio.clip_box(
                 minx=xdi.x[5].values,
                 miny=xdi.y[5].values,
@@ -1472,3 +1486,37 @@ def test_nonstandard_dims_isel_window():
         ).rio.isel_window(Window.from_slices(slice(5), slice(5)))
         assert reprojected.rio.width == 5
         assert reprojected.rio.height == 5
+
+
+def test_nonstandard_dims_error_msg():
+    with xarray.open_dataset(
+        os.path.join(TEST_INPUT_DATA_DIR, "nonstandard_dim.nc")
+    ) as xds:
+        with pytest.raises(
+            DimensionError, match="x dimension not found",
+        ):
+            xds.rio.width
+        with pytest.raises(
+            DimensionError, match="Data variable: analysed_sst",
+        ):
+            xds.analysed_sst.rio.width
+
+
+def test_missing_crs_error_msg():
+    with xarray.open_dataset(
+        os.path.join(TEST_INPUT_DATA_DIR, "nonstandard_dim.nc")
+    ) as xds:
+        xds = xds.drop_vars("spatial_ref")
+        xds.attrs.pop("grid_mapping")
+        with pytest.raises(
+            MissingCRS, match="Data variable: analysed_sst",
+        ):
+            xds.rio.set_spatial_dims(x_dim="lon", y_dim="lat").rio.reproject(
+                "EPSG:4326"
+            )
+        with pytest.raises(
+            MissingCRS, match="Data variable: analysed_sst",
+        ):
+            xds.rio.set_spatial_dims(
+                x_dim="lon", y_dim="lat"
+            ).analysed_sst.rio.reproject("EPSG:4326")