Resample Operators with Pangeo#
Resample Operators#
Sometimes we need to align the spatial or temporal dimension of two datacubes, so that they can be merged together.
Spatial resampling Sentinel-2 to match Landsat#
Start importing the necessary libraries and initialize a local connection for Client-Side Processing.
# STAC Catalogue Libraries
import pystac_client
import stackstac
from rasterio.enums import Resampling
Create two datacubes, one for Sentinel-2 and one for Landsat
spatial_extent = [11.4, 45.5, 11.42, 45.52]
temporal_extent = ["2023-06-01", "2023-06-30"]
Datacube for Sentinel-2#
URL = "https://earth-search.aws.element84.com/v1"
catalog = pystac_client.Client.open(URL)
s2_items = catalog.search(
bbox=spatial_extent,
datetime=temporal_extent,
collections=["sentinel-2-l2a"]
).item_collection()
s2_cube = stackstac.stack(s2_items,
bounds_latlon=spatial_extent,
assets=["red","nir"]
)
s2_cube
/srv/conda/envs/notebook/lib/python3.11/site-packages/stackstac/prepare.py:408: UserWarning: The argument 'infer_datetime_format' is deprecated and will be removed in a future version. A strict version of it is now the default, see https://pandas.pydata.org/pdeps/0004-consistent-to-datetime-parsing.html. You can safely remove this argument.
times = pd.to_datetime(
<xarray.DataArray 'stackstac-e2f40d96c48e834b1e77d88ce8ce66ff' (time: 6, band: 2, y: 228, x: 164)> dask.array<fetch_raster_window, shape=(6, 2, 228, 164), dtype=float64, chunksize=(1, 1, 228, 164), chunktype=numpy.ndarray> Coordinates: (12/54) * time (time) datetime64[ns] 2023-06-02... id (time) <U24 'S2A_32TPR_20230602_... * band (band) <U3 'red' 'nir' * x (x) float64 6.874e+05 ... 6.891e+05 * y (y) float64 5.044e+06 ... 5.041e+06 mgrs:latitude_band <U1 'T' ... ... raster:bands object {'nodata': 0, 'data_type'... proj:shape object {10980} common_name (band) <U3 'red' 'nir' center_wavelength (band) float64 0.665 0.842 full_width_half_max (band) float64 0.038 0.145 epsg int64 32632 Attributes: spec: RasterSpec(epsg=32632, bounds=(687430.0, 5041290.0, 689070.0... crs: epsg:32632 transform: | 10.00, 0.00, 687430.00|\n| 0.00,-10.00, 5043570.00|\n| 0.0... resolution: 10.0
Datacube for Landsat#
url = "https://planetarycomputer.microsoft.com/api/stac/v1"
catalog = pystac_client.Client.open(URL)
l8_items = catalog.search(
bbox=spatial_extent,
datetime=temporal_extent,
collections=["landsat-c2-l2"]
).item_collection()
l8_cube = stackstac.stack(l8_items,
bounds_latlon=spatial_extent,
assets=["red","nir08"]
)
l8_cube
/srv/conda/envs/notebook/lib/python3.11/site-packages/stackstac/prepare.py:408: UserWarning: The argument 'infer_datetime_format' is deprecated and will be removed in a future version. A strict version of it is now the default, see https://pandas.pydata.org/pdeps/0004-consistent-to-datetime-parsing.html. You can safely remove this argument.
times = pd.to_datetime(
<xarray.DataArray 'stackstac-31be86bd1beff02963ed0d75e074c4f9' (time: 15, band: 2, y: 76, x: 55)> dask.array<fetch_raster_window, shape=(15, 2, 76, 55), dtype=float64, chunksize=(1, 1, 76, 55), chunktype=numpy.ndarray> Coordinates: (12/36) * time (time) datetime64[ns] 2023-06-03T10:03:52.60... id (time) <U31 'LC08_L2SP_193028_20230603_02_T1... * band (band) <U5 'red' 'nir08' * x (x) float64 6.874e+05 6.874e+05 ... 6.89e+05 * y (y) float64 5.044e+06 5.044e+06 ... 5.041e+06 view:off_nadir int64 0 ... ... title (band) <U22 'Red Band' 'Near Infrared Band 0.8' storage:platform <U3 'AWS' storage:requester_pays bool True raster:bands object {'nodata': 0, 'data_type': 'uint16', ... storage:region <U9 'us-west-2' epsg int64 32632 Attributes: spec: RasterSpec(epsg=32632, bounds=(687420.0, 5041290.0, 689070.0... crs: epsg:32632 transform: | 30.00, 0.00, 687420.00|\n| 0.00,-30.00, 5043570.00|\n| 0.0... resolution: 30.0
From the previous outputs, notice the shape difference in the spatial dimensions x
and y
.
This is due to the different resolution of the two collections: 10m for Sentinel-2, 30m for Landsat.
Now we use the stackstac.stack
to resample the Sentinel-2 data to match Landsat.
s2_cube_coarse = stackstac.stack(s2_items,
bounds_latlon=spatial_extent,
assets=["red","nir"],
resolution=30.0, resampling=Resampling.average, epsg=32632)
s2_cube_coarse
/srv/conda/envs/notebook/lib/python3.11/site-packages/stackstac/prepare.py:408: UserWarning: The argument 'infer_datetime_format' is deprecated and will be removed in a future version. A strict version of it is now the default, see https://pandas.pydata.org/pdeps/0004-consistent-to-datetime-parsing.html. You can safely remove this argument.
times = pd.to_datetime(
<xarray.DataArray 'stackstac-1bf939077e08430e59af76748c4bcf5e' (time: 6, band: 2, y: 76, x: 55)> dask.array<fetch_raster_window, shape=(6, 2, 76, 55), dtype=float64, chunksize=(1, 1, 76, 55), chunktype=numpy.ndarray> Coordinates: (12/54) * time (time) datetime64[ns] 2023-06-02... id (time) <U24 'S2A_32TPR_20230602_... * band (band) <U3 'red' 'nir' * x (x) float64 6.874e+05 ... 6.89e+05 * y (y) float64 5.044e+06 ... 5.041e+06 mgrs:latitude_band <U1 'T' ... ... raster:bands object {'nodata': 0, 'data_type'... proj:shape object {10980} common_name (band) <U3 'red' 'nir' center_wavelength (band) float64 0.665 0.842 full_width_half_max (band) float64 0.038 0.145 epsg int64 32632 Attributes: spec: RasterSpec(epsg=32632, bounds=(687420.0, 5041290.0, 689070.0... crs: epsg:32632 transform: | 30.00, 0.00, 687420.00|\n| 0.00,-30.00, 5043570.00|\n| 0.0... resolution: 30.0