Exemple #1
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
Exemple #2
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