def clip_box(self, minx, miny, maxx, maxy, auto_expand=False, auto_expand_limit=3): """Clip the :class:`xarray.DataArray` by a bounding box. Parameters ---------- minx: float Minimum bound for x coordinate. miny: float Minimum bound for y coordinate. maxx: float Maximum bound for x coordinate. maxy: float Maximum bound for y coordinate. auto_expand: bool If True, it will expand clip search if only 1D raster found with clip. auto_expand_limit: int maximum number of times the clip will be retried before raising an exception. Returns ------- DataArray: A clipped :class:`xarray.DataArray` object. """ if self.width == 1 or self.height == 1: raise OneDimensionalRaster( "At least one of the raster x,y coordinates has only one point." ) resolution_x, resolution_y = self.resolution() clip_minx = minx - abs(resolution_x) / 2.0 clip_miny = miny - abs(resolution_y) / 2.0 clip_maxx = maxx + abs(resolution_x) / 2.0 clip_maxy = maxy + abs(resolution_y) / 2.0 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.") if cl_array.rio.width == 1 or cl_array.rio.height == 1: if auto_expand and auto_expand < auto_expand_limit: return self.clip_box( clip_minx, clip_miny, clip_maxx, clip_maxy, auto_expand=int(auto_expand) + 1, auto_expand_limit=auto_expand_limit, ) raise OneDimensionalRaster( "At least one of the clipped raster x,y coordinates" " has only one point." ) # make sure correct attributes preserved & projection added _add_attrs_proj(cl_array, self._obj) return cl_array
def resolution(self, recalc=False): """Determine the resolution of the `xarray.DataArray` Parameters ---------- recalc: bool, optional Will force the resolution to be recalculated instead of using the transform attribute. """ if not recalc or self.width == 1 or self.height == 1: try: # get resolution from xarray rasterio data_transform = Affine(*self._obj.attrs["transform"][:6]) resolution_x = data_transform.a resolution_y = data_transform.e recalc = False except KeyError: recalc = True if recalc: left, bottom, right, top = self._internal_bounds() if self.width == 1 or self.height == 1: raise OneDimensionalRaster( "Only 1 dimenional array found. Cannot calculate the resolution." ) resolution_x = (right - left) / (self.width - 1) resolution_y = (bottom - top) / (self.height - 1) return resolution_x, resolution_y
def resolution(self, recalc=False): """ Parameters ---------- recalc: bool, optional Will force the resolution to be recalculated instead of using the transform attribute. Returns ------- x_resolution, y_resolution: float The resolution of the `xarray.DataArray` | `xarray.Dataset` """ transform = self._cached_transform() if ( not recalc or self.width == 1 or self.height == 1 ) and transform is not None: resolution_x = transform.a resolution_y = transform.e return resolution_x, resolution_y # if the coordinates of the spatial dimensions are missing # use the cached transform resolution try: left, bottom, right, top = self._internal_bounds() except DimensionMissingCoordinateError: if transform is None: raise resolution_x = transform.a resolution_y = transform.e return resolution_x, resolution_y 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) resolution_y = (bottom - top) / (self.height - 1) return resolution_x, resolution_y
def clip_box(self, minx, miny, maxx, maxy, auto_expand=False, auto_expand_limit=3): """Clip the :obj:`xarray.DataArray` by a bounding box. Parameters ---------- minx: float Minimum bound for x coordinate. miny: float Minimum bound for y coordinate. maxx: float Maximum bound for x coordinate. maxy: float Maximum bound for y coordinate. auto_expand: bool If True, it will expand clip search if only 1D raster found with clip. auto_expand_limit: int maximum number of times the clip will be retried before raising an exception. Returns ------- :obj:`xarray.DataArray`: The clipped object. """ 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)}") # make sure that if the coordinates are # in reverse order that it still works resolution_x, resolution_y = self.resolution() if resolution_y < 0: top = maxy bottom = miny else: top = miny bottom = maxy if resolution_x < 0: left = maxx right = minx else: left = minx right = maxx # pull the data out window = rasterio.windows.from_bounds( left=np.array(left).item(), bottom=np.array(bottom).item(), right=np.array(right).item(), top=np.array(top).item(), transform=self.transform(recalc=True), width=self.width, height=self.height, ) cl_array = self.isel_window(window) # check that the window has data in it if cl_array.rio.width <= 1 or cl_array.rio.height <= 1: if auto_expand and auto_expand < auto_expand_limit: resolution_x, resolution_y = self.resolution() return self.clip_box( minx=minx - abs(resolution_x) / 2.0, miny=miny - abs(resolution_y) / 2.0, maxx=maxx + abs(resolution_x) / 2.0, maxy=maxy + abs(resolution_y) / 2.0, auto_expand=int(auto_expand) + 1, auto_expand_limit=auto_expand_limit, ) if cl_array.rio.width < 1 or cl_array.rio.height < 1: 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: 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 _add_attrs_proj(cl_array, self._obj) return cl_array