Пример #1
0
def test_make_coords__attr_trans(request, modis_reproject):
    with xarray.open_dataarray(modis_reproject["input"]) as xdi, request.param(
            modis_reproject["input"]) as xri:
        # calculate coordinates from the attribute transform
        width, height = xdi.rio.shape
        attr_transform = xdi.rio.transform()
        calc_coords_attr_trans = _make_coords(xdi, attr_transform, width,
                                              height, xdi.attrs["crs"])
        widthr, heightr = xri.rio.shape
        calculated_transformr = xri.rio.transform()
        calc_coords_calc_transr = _make_coords(xri, calculated_transformr,
                                               widthr, heightr,
                                               xdi.attrs["crs"])

        # check to see if they all match
        assert_array_equal(xri.coords["x"].values,
                           calc_coords_calc_transr["x"].values)
        assert_array_equal(xri.coords["y"].values,
                           calc_coords_calc_transr["y"].values)
        assert_array_equal(xri.coords["x"].values,
                           calc_coords_attr_trans["x"].values)
        assert_array_equal(xri.coords["y"].values,
                           calc_coords_attr_trans["y"].values)
        assert_almost_equal(xdi.coords["x"].values,
                            xri.coords["x"].values,
                            decimal=9)
        assert_almost_equal(xdi.coords["y"].values,
                            xri.coords["y"].values,
                            decimal=9)
Пример #2
0
def _clip_from_disk(xds, geometries, all_touched, drop, invert):
    """
    clip from disk if the file object is available
    """
    try:
        out_image, out_transform = rasterio.mask.mask(
            xds.rio._manager.acquire(),
            geometries,
            all_touched=all_touched,
            invert=invert,
            crop=drop,
        )
        if xds.rio.encoded_nodata is not None and not np.isnan(
                xds.rio.encoded_nodata):
            out_image = out_image.astype(np.float64)
            out_image[out_image == xds.rio.encoded_nodata] = np.nan

        height, width = out_image.shape[-2:]
        cropped_ds = xarray.DataArray(
            name=xds.name,
            data=out_image,
            coords=_make_coords(xds, out_transform, width, height),
            dims=xds.dims,
            attrs=xds.attrs,
        )
        cropped_ds.encoding = xds.encoding
        return cropped_ds
    except AttributeError:
        return None
def test_make_coords__calc_trans(modis_reproject):
    with xarray.open_dataarray(modis_reproject["input"],
                               autoclose=True) as xdi, xarray.open_rasterio(
                                   modis_reproject["input"]) as xri:
        # calculate coordinates from the calculated transform
        width, height = xdi.rio.shape
        calculated_transform = xdi.rio.transform(recalc=True)
        calc_coords_calc_trans = _make_coords(xdi, calculated_transform, width,
                                              height, xdi.attrs["crs"])
        widthr, heightr = xri.rio.shape
        calculated_transformr = xri.rio.transform(recalc=True)
        calc_coords_calc_transr = _make_coords(xri, calculated_transformr,
                                               widthr, heightr,
                                               xdi.attrs["crs"])

        # check to see if they all match
        assert_array_equal(xri.coords["x"].values,
                           calc_coords_calc_trans["x"].values)
        assert_array_equal(xri.coords["y"].values,
                           calc_coords_calc_trans["y"].values)
        assert_array_equal(xri.coords["x"].values,
                           calc_coords_calc_transr["x"].values)
        assert_array_equal(xri.coords["y"].values,
                           calc_coords_calc_transr["y"].values)
Пример #4
0
def merge_arrays(
    dataarrays: Iterable[DataArray],
    bounds: Optional[Tuple] = None,
    res: Optional[Tuple] = None,
    nodata: Optional[float] = None,
    precision: Optional[float] = None,
    method: Union[str, Callable, None] = None,
    crs: Optional[CRS] = None,
    parse_coordinates: bool = True,
) -> DataArray:
    """
    Merge data arrays geospatially.

    Uses rasterio.merge.merge:
        https://rasterio.readthedocs.io/en/stable/api/rasterio.merge.html#rasterio.merge.merge

    .. versionadded:: 0.2 crs

    Parameters
    ----------
    dataarrays: list
        List of xarray.DataArray's with all geo attributes.
        The first one is assumed to have the same
        CRS, dtype, and dimensions as the others in the array.
    bounds: tuple, optional
        Bounds of the output image (left, bottom, right, top).
        If not set, bounds are determined from bounds of input DataArrays.
    res: tuple, optional
        Output resolution in units of coordinate reference system.
        If not set, the resolution of the first DataArray is used.
        If a single value is passed, output pixels will be square.
    nodata: float, optional
        nodata value to use in output file.
        If not set, uses the nodata value in the first input DataArray.
    precision: float, optional
        Number of decimal points of precision when computing inverse transform.
    method: str or callable, optional
        See rasterio docs.
    crs: rasterio.crs.CRS, optional
        Output CRS. If not set, the CRS of the first DataArray is used.
    parse_coordinates: bool, optional
        If False, it will disable loading spatial coordinates.

    Returns
    -------
    :obj:`xarray.DataArray`:
        The geospatially merged data.
    """
    input_kwargs = dict(bounds=bounds,
                        res=res,
                        nodata=nodata,
                        precision=precision,
                        method=method)

    if crs is None:
        crs = dataarrays[0].rio.crs
    if res is None:
        res = tuple(abs(res_val) for res_val in dataarrays[0].rio.resolution())

    # prepare the duck arrays
    rioduckarrays = []
    for dataarray in dataarrays:
        da_res = tuple(abs(res_val) for res_val in dataarray.rio.resolution())
        if da_res != res or dataarray.rio.crs != crs:
            rioduckarrays.append(
                RasterioDatasetDuck(
                    dataarray.rio.reproject(dst_crs=crs, resolution=res)))
        else:
            rioduckarrays.append(RasterioDatasetDuck(dataarray))

    # use rasterio to merge
    merged_data, merged_transform = _rio_merge(
        rioduckarrays,
        **{key: val
           for key, val in input_kwargs.items() if val is not None},
    )

    # generate merged data array
    representative_array = rioduckarrays[0]._xds
    if parse_coordinates:
        coords = _make_coords(
            representative_array,
            merged_transform,
            merged_data.shape[-1],
            merged_data.shape[-2],
        )
    else:
        coords = _get_nonspatial_coords(representative_array)

    xda = DataArray(
        name=representative_array.name,
        data=merged_data,
        coords=coords,
        dims=tuple(representative_array.dims),
        attrs=representative_array.attrs,
    )
    xda.rio.write_nodata(
        nodata if nodata is not None else representative_array.rio.nodata,
        inplace=True)
    xda.rio.write_crs(representative_array.rio.crs, inplace=True)
    xda.rio.write_transform(merged_transform, inplace=True)
    return xda
Пример #5
0
def merge_datasets(
    datasets: Iterable[Dataset],
    bounds: Optional[Tuple] = None,
    res: Optional[Tuple] = None,
    nodata: Optional[float] = None,
    precision: Optional[float] = None,
    method: Union[str, Callable, None] = None,
    crs: Optional[CRS] = None,
) -> DataArray:
    """
    Merge datasets geospatially.

    Uses rasterio.merge.merge:
        https://rasterio.readthedocs.io/en/stable/api/rasterio.merge.html#rasterio.merge.merge

    .. versionadded:: 0.2 crs

    Parameters
    ----------
    datasets: list
        List of xarray.Dataset's with all geo attributes.
        The first one is assumed to have the same
        CRS, dtype, dimensions, and data_vars as the others in the array.
    bounds: tuple, optional
        Bounds of the output image (left, bottom, right, top).
        If not set, bounds are determined from bounds of input Dataset.
    res: tuple, optional
        Output resolution in units of coordinate reference system.
        If not set, the resolution of the first Dataset is used.
        If a single value is passed, output pixels will be square.
    nodata: float, optional
        nodata value to use in output file.
        If not set, uses the nodata value in the first input Dataset.
    precision: float, optional
        Number of decimal points of precision when computing inverse transform.
    method: str or callable, optional
        See rasterio docs.
    crs: rasterio.crs.CRS, optional
        Output CRS. If not set, the CRS of the first DataArray is used.

    Returns
    -------
    :obj:`xarray.Dataset`:
        The geospatially merged data.
    """

    representative_ds = datasets[0]
    merged_data = {}
    for data_var in representative_ds.data_vars:
        merged_data[data_var] = merge_arrays(
            [dataset[data_var] for dataset in datasets],
            bounds=bounds,
            res=res,
            nodata=nodata,
            precision=precision,
            method=method,
            crs=crs,
            parse_coordinates=False,
        )
    data_var = list(representative_ds.data_vars)[0]
    xds = Dataset(
        merged_data,
        coords=_make_coords(
            merged_data[data_var],
            merged_data[data_var].rio.transform(),
            merged_data[data_var].shape[-1],
            merged_data[data_var].shape[-2],
        ),
        attrs=representative_ds.attrs,
    )
    xds.rio.write_crs(merged_data[data_var].rio.crs, inplace=True)
    return xds
Пример #6
0
    def reproject(
        self,
        dst_crs,
        resolution=None,
        shape=None,
        transform=None,
        resampling=Resampling.nearest,
    ):
        """
        Reproject :obj:`xarray.DataArray` objects

        Powered by `rasterio.warp.reproject`

        .. note:: Only 2D/3D arrays with dimensions 'x'/'y' are currently supported.
            Requires either a grid mapping variable with 'spatial_ref' or
            a 'crs' attribute to be set containing a valid CRS.
            If using a WKT (e.g. from spatiareference.org), make sure it is an OGC WKT.

        .. versionadded:: 0.0.27 shape
        .. versionadded:: 0.0.28 transform

        Parameters
        ----------
        dst_crs: str
            OGC WKT string or Proj.4 string.
        resolution: float or tuple(float, float), optional
            Size of a destination pixel in destination projection units
            (e.g. degrees or metres).
        shape: tuple(int, int), optional
            Shape of the destination in pixels (dst_height, dst_width). Cannot be used
            together with resolution.
        transform: optional
            The destination transform.
        resampling: Resampling method, optional
            See rasterio.warp.reproject for more details.


        Returns
        -------
        :obj:`xarray.DataArray`:
            The reprojected DataArray.
        """
        if resolution is not None and (shape is not None
                                       or transform is not None):
            raise RioXarrayError(
                "resolution cannot be used with shape or transform.")
        if self.crs is None:
            raise MissingCRS(
                "CRS not found. Please set the CRS with 'rio.write_crs()'."
                f"{_get_data_var_message(self._obj)}")
        src_affine = self.transform(recalc=True)
        if transform is None:
            dst_affine, dst_width, dst_height = _make_dst_affine(
                self._obj, self.crs, dst_crs, resolution, shape)
        else:
            dst_affine = transform
            if shape is not None:
                dst_height, dst_width = shape
            else:
                dst_height, dst_width = self.shape

        extra_dim = self._check_dimensions()
        if extra_dim:
            dst_data = np.zeros(
                (self._obj[extra_dim].size, dst_height, dst_width),
                dtype=self._obj.dtype.type,
            )
        else:
            dst_data = np.zeros((dst_height, dst_width),
                                dtype=self._obj.dtype.type)

        dst_nodata = self._obj.dtype.type(
            self.nodata if self.nodata is not None else -9999)
        src_nodata = self._obj.dtype.type(
            self.nodata if self.nodata is not None else dst_nodata)
        rasterio.warp.reproject(
            source=self._obj.values,
            destination=dst_data,
            src_transform=src_affine,
            src_crs=self.crs,
            src_nodata=src_nodata,
            dst_transform=dst_affine,
            dst_crs=dst_crs,
            dst_nodata=dst_nodata,
            resampling=resampling,
        )
        # add necessary attributes
        new_attrs = _generate_attrs(self._obj, dst_nodata)
        # make sure dimensions with coordinates renamed to x,y
        dst_dims = []
        for dim in self._obj.dims:
            if dim == self.x_dim:
                dst_dims.append("x")
            elif dim == self.y_dim:
                dst_dims.append("y")
            else:
                dst_dims.append(dim)
        xda = xarray.DataArray(
            name=self._obj.name,
            data=dst_data,
            coords=_make_coords(self._obj, dst_affine, dst_width, dst_height),
            dims=tuple(dst_dims),
            attrs=new_attrs,
        )
        xda.encoding = self._obj.encoding
        xda.rio.write_transform(dst_affine, inplace=True)
        xda.rio.write_crs(dst_crs, inplace=True)
        xda.rio.write_coordinate_system(inplace=True)
        return xda
Пример #7
0
def merge_arrays(
    dataarrays: Iterable[DataArray],
    bounds: Union[Tuple, None] = None,
    res: Union[Tuple, None] = None,
    nodata: Union[float, None] = None,
    precision: Union[float, None] = None,
    method: Union[str, Callable, None] = None,
    parse_coordinates: bool = True,
) -> DataArray:
    """
    Merge data arrays geospatially.

    Uses rasterio.merge.merge:
        https://rasterio.readthedocs.io/en/stable/api/rasterio.merge.html#rasterio.merge.merge

    Parameters
    ----------
    dataarrays: list
        List of xarray.DataArray's with all geo attributes.
        The first one is assumed to have the same
        CRS, dtype, and dimensions as the others in the array.
    bounds: tuple, optional
        Bounds of the output image (left, bottom, right, top).
        If not set, bounds are determined from bounds of input DataArrays.
    res: tuple, optional
        Output resolution in units of coordinate reference system.
        If not set, the resolution of the first DataArray is used.
        If a single value is passed, output pixels will be square.
    nodata: float, optional
        nodata value to use in output file.
        If not set, uses the nodata value in the first input DataArray.
    precision: float, optional
        Number of decimal points of precision when computing inverse transform.
    method: str or callable, optional
        See rasterio docs.
    parse_coordinates: bool, optional
        If False, it will disable loading spatial coordinates.

    Returns
    -------
    DataArray: The geospatially merged data.
    """

    input_kwargs = dict(bounds=bounds,
                        res=res,
                        nodata=nodata,
                        precision=precision,
                        method=method)
    merged_data, merged_transform = _rio_merge(
        [RasterioDatasetDuck(dataarray) for dataarray in dataarrays],
        **{key: val
           for key, val in input_kwargs.items() if val is not None},
    )
    merged_shape = merged_data.shape
    representative_array = dataarrays[0]
    merged_crs = representative_array.rio.crs
    if parse_coordinates:
        coords = _make_coords(
            representative_array,
            merged_transform,
            merged_shape[-1],
            merged_shape[-2],
            merged_crs,
        )
    else:
        coords = _get_nonspatial_coords(representative_array)

    out_attrs = representative_array.attrs
    out_attrs["transform"] = tuple(merged_transform)[:6]
    xda = DataArray(
        name=dataarrays[0].name,
        data=merged_data,
        coords=coords,
        dims=tuple(representative_array.dims),
        attrs=out_attrs,
    )
    out_nodata = nodata if nodata is not None else representative_array.rio.nodata
    xda.rio.write_nodata(out_nodata, inplace=True)
    xda.rio.write_crs(representative_array.rio.crs, inplace=True)
    return xda
Пример #8
0
    def reproject(
        self,
        dst_crs,
        resolution=None,
        shape=None,
        transform=None,
        resampling=Resampling.nearest,
        nodata=None,
        **kwargs,
    ):
        """
        Reproject :obj:`xarray.DataArray` objects

        Powered by :func:`rasterio.warp.reproject`

        .. note:: Only 2D/3D arrays with dimensions 'x'/'y' are currently supported.
            Requires either a grid mapping variable with 'spatial_ref' or
            a 'crs' attribute to be set containing a valid CRS.
            If using a WKT (e.g. from spatiareference.org), make sure it is an OGC WKT.

        .. versionadded:: 0.0.27 shape
        .. versionadded:: 0.0.28 transform
        .. versionadded:: 0.5.0 nodata, kwargs

        Parameters
        ----------
        dst_crs: str
            OGC WKT string or Proj.4 string.
        resolution: float or tuple(float, float), optional
            Size of a destination pixel in destination projection units
            (e.g. degrees or metres).
        shape: tuple(int, int), optional
            Shape of the destination in pixels (dst_height, dst_width). Cannot be used
            together with resolution.
        transform: Affine, optional
            The destination transform.
        resampling: rasterio.enums.Resampling, optional
            See :func:`rasterio.warp.reproject` for more details.
        nodata: float, optional
            The nodata value used to initialize the destination;
            it will remain in all areas not covered by the reprojected source.
            Defaults to the nodata value of the source image if none provided
            and exists or attempts to find an appropriate value by dtype.
        **kwargs: dict
            Additional keyword arguments to pass into :func:`rasterio.warp.reproject`.
            To override:
            - src_transform: `rio.write_transform`
            - src_crs: `rio.write_crs`
            - src_nodata: `rio.write_nodata`


        Returns
        -------
        :obj:`xarray.DataArray`:
            The reprojected DataArray.
        """
        if resolution is not None and (shape is not None
                                       or transform is not None):
            raise RioXarrayError(
                "resolution cannot be used with shape or transform.")
        if self.crs is None:
            raise MissingCRS(
                "CRS not found. Please set the CRS with 'rio.write_crs()'."
                f"{_get_data_var_message(self._obj)}")
        gcps = self.get_gcps()
        if gcps:
            kwargs.setdefault("gcps", gcps)

        src_affine = None if "gcps" in kwargs else self.transform(recalc=True)
        if transform is None:
            dst_affine, dst_width, dst_height = _make_dst_affine(
                self._obj, self.crs, dst_crs, resolution, shape, **kwargs)
        else:
            dst_affine = transform
            if shape is not None:
                dst_height, dst_width = shape
            else:
                dst_height, dst_width = self.shape

        dst_data = self._create_dst_data(dst_height, dst_width)

        dst_nodata = self._get_dst_nodata(nodata)

        rasterio.warp.reproject(
            source=self._obj.values,
            destination=dst_data,
            src_transform=src_affine,
            src_crs=self.crs,
            src_nodata=self.nodata,
            dst_transform=dst_affine,
            dst_crs=dst_crs,
            dst_nodata=dst_nodata,
            resampling=resampling,
            **kwargs,
        )
        # add necessary attributes
        new_attrs = _generate_attrs(self._obj, dst_nodata)
        # make sure dimensions with coordinates renamed to x,y
        dst_dims = []
        for dim in self._obj.dims:
            if dim == self.x_dim:
                dst_dims.append("x")
            elif dim == self.y_dim:
                dst_dims.append("y")
            else:
                dst_dims.append(dim)
        xda = xarray.DataArray(
            name=self._obj.name,
            data=dst_data,
            coords=_make_coords(self._obj, dst_affine, dst_width, dst_height),
            dims=tuple(dst_dims),
            attrs=new_attrs,
        )
        xda.encoding = self._obj.encoding
        xda.rio.write_transform(dst_affine, inplace=True)
        xda.rio.write_crs(dst_crs, inplace=True)
        xda.rio.write_coordinate_system(inplace=True)
        return xda