Exemplo n.º 1
0
    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
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
    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