Sentinel-2 data in Python¶

OpenGeoHub Summer School 2023

  • Lorena Abad
  • 2023-09-01

Accessing data via STAC API¶

Libraries needed for this exercise are imported below:

In [1]:
import geogif # render gifs from raster images
import geopandas as gpd # handle geospatial data frames
from IPython.display import Image # visualize URLs
import pandas as pd # data wrangling
import pystac_client # connecting to the STAC API
from rasterio.enums import Resampling # perform resampling operations
import rioxarray # handle spatio-temporal arrays
import shapely # create vector objects
import stackstac # build an on-demand STAC data cube

Querying data with pystac-client¶

STAC stands for SpatioTemporal Asset Catalog and it is "a common language to describe geospatial information, so it can more easily be worked with, indexed, and discovered".

pystac-client allows the querying of a STAC API using Python.

There are several APIs available to query data, you can browse them all in the STAC catalog index. Some of these APIs will require authentication to access the data. We will use the Earth Search catalog for this notebook, which allows querying data on Amazon Web Services (AWS). The data we will fetch does not require authentication.

In [2]:
# STAC API URL 
api_url = 'https://earth-search.aws.element84.com/v1'

To start fetching data, we will open the client. We can see the collections available for this API:

In [3]:
client = pystac_client.Client.open(api_url)
for collection in client.get_collections():
    print(collection)
<CollectionClient id=cop-dem-glo-30>
<CollectionClient id=naip>
<CollectionClient id=sentinel-2-l2a>
<CollectionClient id=sentinel-2-l1c>
<CollectionClient id=landsat-c2-l2>
<CollectionClient id=cop-dem-glo-90>
<CollectionClient id=sentinel-1-grd>

Let's focus on Sentinel-2 data level 2a. Here are the different levels that Sentinel-2 has. Level 2a provides atmospherically corrected data representing surface reflectance.

In [4]:
# collection ID
collection = 'sentinel-2-l2a'

Let's define now the spatial and temporal extent for our query. We will query all scenes intersecting the point coordinates and the time range given.

In [5]:
# coordinates
lon = 16.9
lat = 52.4
# date range
datetime = '2022-05-01/2022-10-01'
point = shapely.Point(lon, lat)

And we pass these arguments to our search:

In [34]:
search = client.search(
    collections=[collection],
    intersects=point,
    datetime=datetime,
    query=["eo:cloud_cover<10"],
)
In [35]:
items = search.item_collection()
len(items)
Out[35]:
8

We can view our query as a Geopandas data frame for easier readability:

In [36]:
df = gpd.GeoDataFrame.from_features(items.to_dict(), crs="epsg:4326")
df
Out[36]:
geometry created platform constellation instruments eo:cloud_cover proj:epsg mgrs:utm_zone mgrs:latitude_band mgrs:grid_square ... s2:datastrip_id s2:granule_id s2:reflectance_conversion_factor datetime s2:sequence earthsearch:s3_path earthsearch:payload_id earthsearch:boa_offset_applied processing:software updated
0 POLYGON ((16.49848 53.24020, 17.39166 53.22562... 2022-11-06T13:14:57.270Z sentinel-2a sentinel-2 [msi] 0.003331 32633 33 U XU ... S2A_OPER_MSI_L2A_DS_ATOS_20220826T162059_S2022... S2A_OPER_MSI_L2A_TL_ATOS_20220826T162059_A0374... 0.977922 2022-08-26T10:16:12.680000Z 0 s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/X... roda-sentinel2/workflow-sentinel2-to-stac/bff1... True {'sentinel2-to-stac': '0.1.0'} 2022-11-06T13:14:57.270Z
1 POLYGON ((16.49848 53.24020, 17.39346 53.22558... 2022-11-06T12:53:48.090Z sentinel-2a sentinel-2 [msi] 4.800238 32633 33 U XU ... S2A_OPER_MSI_L2A_DS_ATOS_20220816T162557_S2022... S2A_OPER_MSI_L2A_TL_ATOS_20220816T162557_A0373... 0.974147 2022-08-16T10:16:12.609000Z 0 s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/X... roda-sentinel2/workflow-sentinel2-to-stac/b5b7... True {'sentinel2-to-stac': '0.1.0'} 2022-11-06T12:53:48.090Z
2 POLYGON ((16.49848 53.24020, 18.14175 53.20819... 2022-11-06T13:12:58.202Z sentinel-2a sentinel-2 [msi] 8.775087 32633 33 U XU ... S2A_OPER_MSI_L2A_DS_ATOS_20220803T135155_S2022... S2A_OPER_MSI_L2A_TL_ATOS_20220803T135155_A0371... 0.970396 2022-08-03T10:06:14.409000Z 0 s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/X... roda-sentinel2/workflow-sentinel2-to-stac/6245... True {'sentinel2-to-stac': '0.1.0'} 2022-11-06T13:12:58.202Z
3 POLYGON ((16.49848 53.24020, 18.14175 53.20819... 2022-11-06T13:14:37.621Z sentinel-2b sentinel-2 [msi] 0.005511 32633 33 U XU ... S2B_OPER_MSI_L2A_DS_2BPS_20220719T113943_S2022... S2B_OPER_MSI_L2A_TL_2BPS_20220719T113943_A0280... 0.967885 2022-07-19T10:06:08.645000Z 0 s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/X... roda-sentinel2/workflow-sentinel2-to-stac/4f39... True {'sentinel2-to-stac': '0.1.0'} 2022-11-06T13:14:37.621Z
4 POLYGON ((16.49848 53.24020, 18.14175 53.20819... 2022-11-06T12:54:05.312Z sentinel-2a sentinel-2 [msi] 1.825375 32633 33 U XU ... S2A_OPER_MSI_L2A_DS_ATOS_20220714T175057_S2022... S2A_OPER_MSI_L2A_TL_ATOS_20220714T175057_A0368... 0.967507 2022-07-14T10:06:16.331000Z 0 s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/X... roda-sentinel2/workflow-sentinel2-to-stac/1cea... True {'sentinel2-to-stac': '0.1.0'} 2022-11-06T12:54:05.312Z
5 POLYGON ((16.49848 53.24020, 17.39346 53.22558... 2022-11-06T12:55:07.931Z sentinel-2a sentinel-2 [msi] 1.067175 32633 33 U XU ... S2A_OPER_MSI_L2A_DS_ATOS_20220627T162810_S2022... S2A_OPER_MSI_L2A_TL_ATOS_20220627T162810_A0366... 0.967975 2022-06-27T10:16:12.822000Z 0 s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/X... roda-sentinel2/workflow-sentinel2-to-stac/fd88... True {'sentinel2-to-stac': '0.1.0'} 2022-11-06T12:55:07.931Z
6 POLYGON ((16.49848 53.24020, 18.14175 53.20819... 2022-11-06T12:52:50.337Z sentinel-2a sentinel-2 [msi] 0.002495 32633 33 U XU ... S2A_OPER_MSI_L2A_DS_ATOS_20220624T143914_S2022... S2A_OPER_MSI_L2A_TL_ATOS_20220624T143914_A0365... 0.968339 2022-06-24T10:06:16.177000Z 0 s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/X... roda-sentinel2/workflow-sentinel2-to-stac/9b8a... True {'sentinel2-to-stac': '0.1.0'} 2022-11-06T12:52:50.337Z
7 POLYGON ((16.49848 53.24020, 18.14175 53.20819... 2022-11-06T13:16:38.195Z sentinel-2b sentinel-2 [msi] 7.491449 32633 33 U XU ... S2B_OPER_MSI_L2A_DS_2BPS_20220619T114329_S2022... S2B_OPER_MSI_L2A_TL_2BPS_20220619T114329_A0276... 0.969127 2022-06-19T10:06:08.087000Z 0 s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/X... roda-sentinel2/workflow-sentinel2-to-stac/58f8... True {'sentinel2-to-stac': '0.1.0'} 2022-11-06T13:16:38.195Z

8 rows × 42 columns

This proves useful for example when we want to visualize the cloud cover of our whole collection:

In [37]:
df["datetime"] = pd.to_datetime(df["datetime"])

ts = df.set_index("datetime").sort_index()["eo:cloud_cover"]
ts.plot(title="eo:cloud-cover")
Out[37]:
<Axes: title={'center': 'eo:cloud-cover'}, xlabel='datetime'>
No description has been provided for this image

Let's explore the properties of one item. But first let's look for an item index with low cloud cover and low nodata.

In [38]:
df_filt = df.loc[(df['eo:cloud_cover'] <= 2) & (df['s2:nodata_pixel_percentage'] <= 10)]
df_filt
Out[38]:
geometry created platform constellation instruments eo:cloud_cover proj:epsg mgrs:utm_zone mgrs:latitude_band mgrs:grid_square ... s2:datastrip_id s2:granule_id s2:reflectance_conversion_factor datetime s2:sequence earthsearch:s3_path earthsearch:payload_id earthsearch:boa_offset_applied processing:software updated
3 POLYGON ((16.49848 53.24020, 18.14175 53.20819... 2022-11-06T13:14:37.621Z sentinel-2b sentinel-2 [msi] 0.005511 32633 33 U XU ... S2B_OPER_MSI_L2A_DS_2BPS_20220719T113943_S2022... S2B_OPER_MSI_L2A_TL_2BPS_20220719T113943_A0280... 0.967885 2022-07-19 10:06:08.645000+00:00 0 s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/X... roda-sentinel2/workflow-sentinel2-to-stac/4f39... True {'sentinel2-to-stac': '0.1.0'} 2022-11-06T13:14:37.621Z
4 POLYGON ((16.49848 53.24020, 18.14175 53.20819... 2022-11-06T12:54:05.312Z sentinel-2a sentinel-2 [msi] 1.825375 32633 33 U XU ... S2A_OPER_MSI_L2A_DS_ATOS_20220714T175057_S2022... S2A_OPER_MSI_L2A_TL_ATOS_20220714T175057_A0368... 0.967507 2022-07-14 10:06:16.331000+00:00 0 s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/X... roda-sentinel2/workflow-sentinel2-to-stac/1cea... True {'sentinel2-to-stac': '0.1.0'} 2022-11-06T12:54:05.312Z
6 POLYGON ((16.49848 53.24020, 18.14175 53.20819... 2022-11-06T12:52:50.337Z sentinel-2a sentinel-2 [msi] 0.002495 32633 33 U XU ... S2A_OPER_MSI_L2A_DS_ATOS_20220624T143914_S2022... S2A_OPER_MSI_L2A_TL_ATOS_20220624T143914_A0365... 0.968339 2022-06-24 10:06:16.177000+00:00 0 s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/X... roda-sentinel2/workflow-sentinel2-to-stac/9b8a... True {'sentinel2-to-stac': '0.1.0'} 2022-11-06T12:52:50.337Z

3 rows × 42 columns

In [39]:
item = items[df_filt.index[0]]
item.geometry
Out[39]:
{'type': 'Polygon',
 'coordinates': [[[16.498475093400046, 53.240199174677954],
   [18.141754296879448, 53.20819279121764],
   [18.071664488869853, 52.22257539160585],
   [16.464995307918354, 52.25346561204129],
   [16.498475093400046, 53.240199174677954]]]}
In [40]:
item.datetime
Out[40]:
datetime.datetime(2022, 7, 19, 10, 6, 8, 645000, tzinfo=tzutc())
In [41]:
item.properties
Out[41]:
{'created': '2022-11-06T13:14:37.621Z',
 'platform': 'sentinel-2b',
 'constellation': 'sentinel-2',
 'instruments': ['msi'],
 'eo:cloud_cover': 0.005511,
 'proj:epsg': 32633,
 'mgrs:utm_zone': 33,
 'mgrs:latitude_band': 'U',
 'mgrs:grid_square': 'XU',
 'grid:code': 'MGRS-33UXU',
 'view:sun_azimuth': 157.993614061013,
 'view:sun_elevation': 56.588942214785,
 's2:degraded_msi_data_percentage': 0,
 's2:nodata_pixel_percentage': 3e-06,
 's2:saturated_defective_pixel_percentage': 0,
 's2:dark_features_percentage': 0.004429,
 's2:cloud_shadow_percentage': 0,
 's2:vegetation_percentage': 64.467937,
 's2:not_vegetated_percentage': 34.062394,
 's2:water_percentage': 1.263951,
 's2:unclassified_percentage': 0.195772,
 's2:medium_proba_clouds_percentage': 7e-05,
 's2:high_proba_clouds_percentage': 3e-06,
 's2:thin_cirrus_percentage': 0.005438,
 's2:snow_ice_percentage': 0,
 's2:product_type': 'S2MSI2A',
 's2:processing_baseline': '04.00',
 's2:product_uri': 'S2B_MSIL2A_20220719T095559_N0400_R122_T33UXU_20220719T113943.SAFE',
 's2:generation_time': '2022-07-19T11:39:43.000000Z',
 's2:datatake_id': 'GS2B_20220719T095559_028033_N04.00',
 's2:datatake_type': 'INS-NOBS',
 's2:datastrip_id': 'S2B_OPER_MSI_L2A_DS_2BPS_20220719T113943_S20220719T095747_N04.00',
 's2:granule_id': 'S2B_OPER_MSI_L2A_TL_2BPS_20220719T113943_A028033_T33UXU_N04.00',
 's2:reflectance_conversion_factor': 0.967884952505288,
 'datetime': '2022-07-19T10:06:08.645000Z',
 's2:sequence': '0',
 'earthsearch:s3_path': 's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/7/S2B_33UXU_20220719_0_L2A',
 'earthsearch:payload_id': 'roda-sentinel2/workflow-sentinel2-to-stac/4f39107c8fe71ec8f29d674a811d6c21',
 'earthsearch:boa_offset_applied': True,
 'processing:software': {'sentinel2-to-stac': '0.1.0'},
 'updated': '2022-11-06T13:14:37.621Z'}

We can also take a look at the assets for the item. That is which bands are available.

In [42]:
item.assets.keys()
Out[42]:
dict_keys(['aot', 'blue', 'coastal', 'granule_metadata', 'green', 'nir', 'nir08', 'nir09', 'red', 'rededge1', 'rededge2', 'rededge3', 'scl', 'swir16', 'swir22', 'thumbnail', 'tileinfo_metadata', 'visual', 'wvp', 'aot-jp2', 'blue-jp2', 'coastal-jp2', 'green-jp2', 'nir-jp2', 'nir08-jp2', 'nir09-jp2', 'red-jp2', 'rededge1-jp2', 'rededge2-jp2', 'rededge3-jp2', 'scl-jp2', 'swir16-jp2', 'swir22-jp2', 'visual-jp2', 'wvp-jp2'])

And we can also preview how this scene looks like:

In [43]:
thumbnail = item.assets["thumbnail"].href
Image(url = thumbnail)
Out[43]:
No description has been provided for this image

Let's take a look at one single band:

In [44]:
asset = item.assets["red"]
In [45]:
asset.extra_fields
Out[45]:
{'eo:bands': [{'name': 'red',
   'common_name': 'red',
   'description': 'Red (band 4)',
   'center_wavelength': 0.665,
   'full_width_half_max': 0.038}],
 'gsd': 10,
 'proj:shape': [10980, 10980],
 'proj:transform': [10, 0, 600000, 0, -10, 5900040],
 'raster:bands': [{'nodata': 0,
   'data_type': 'uint16',
   'bits_per_sample': 15,
   'spatial_resolution': 10,
   'scale': 0.0001,
   'offset': -0.1}]}

And read it with rioxarray.

In [46]:
red = rioxarray.open_rasterio(item.assets["red"].href, decode_coords="all")

We can now plot the data, in this case a subset to speed up the process. That is achieved with the isel() function.

In [47]:
red.isel(x=slice(2000, 4000), y=slice(8000, 10500)).plot(robust=True)
Out[47]:
<matplotlib.collections.QuadMesh at 0x7f8e44b78fd0>
No description has been provided for this image

What about an RGB representation?

In [48]:
rgb = rioxarray.open_rasterio(item.assets["visual"].href)
In [49]:
rgb.isel(x=slice(2000, 4000), y=slice(8000, 10500)).plot.imshow()
Out[49]:
<matplotlib.image.AxesImage at 0x7f8e44c1a410>
No description has been provided for this image

Creating a STAC data cube¶

To work with the STAC items as a data cube we can use the stackstac package.

To limit our data cube size we will create it only focused on the Poznan bounding box.

In [50]:
footprint = gpd.read_file("../../data/poznan.geojson")
footprint.total_bounds
Out[50]:
array([16.75738404, 52.29364398, 17.16361743, 52.53564773])
In [51]:
cube = stackstac.stack(
    items,
    resolution=200,
    bounds_latlon=footprint.total_bounds,
    resampling=Resampling.bilinear
)
cube
/opt/conda/lib/python3.11/site-packages/stackstac/prepare.py:364: 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(
Out[51]:
<xarray.DataArray 'stackstac-26bf16b18d945f83e54e4d04b774ec18' (time: 8,
                                                                band: 32,
                                                                y: 140, x: 143)>
dask.array<fetch_raster_window, shape=(8, 32, 140, 143), dtype=float64, chunksize=(1, 1, 140, 143), chunktype=numpy.ndarray>
Coordinates: (12/52)
  * time                                     (time) datetime64[ns] 2022-06-19...
    id                                       (time) <U24 'S2B_33UXU_20220619_...
  * band                                     (band) <U12 'aot' ... 'wvp-jp2'
  * x                                        (x) float64 6.19e+05 ... 6.474e+05
  * y                                        (y) float64 5.823e+06 ... 5.795e+06
    s2:nodata_pixel_percentage               (time) object 0 0 ... 60.458738
    ...                                       ...
    title                                    (band) <U31 'Aerosol optical thi...
    gsd                                      (band) object None 10 ... None None
    common_name                              (band) object None 'blue' ... None
    center_wavelength                        (band) object None 0.49 ... None
    full_width_half_max                      (band) object None 0.098 ... None
    epsg                                     int64 32633
Attributes:
    spec:        RasterSpec(epsg=32633, bounds=(619000, 5795000, 647600, 5823...
    crs:         epsg:32633
    transform:   | 200.00, 0.00, 619000.00|\n| 0.00,-200.00, 5823000.00|\n| 0...
    resolution:  200
xarray.DataArray
'stackstac-26bf16b18d945f83e54e4d04b774ec18'
  • time: 8
  • band: 32
  • y: 140
  • x: 143
  • dask.array<chunksize=(1, 1, 140, 143), meta=np.ndarray>
    Array Chunk
    Bytes 39.10 MiB 156.41 kiB
    Shape (8, 32, 140, 143) (1, 1, 140, 143)
    Dask graph 256 chunks in 3 graph layers
    Data type float64 numpy.ndarray
    8 1 143 140 32
    • time
      (time)
      datetime64[ns]
      2022-06-19T10:06:08.087000 ... 2...
      array(['2022-06-19T10:06:08.087000000', '2022-06-24T10:06:16.177000000',
             '2022-06-27T10:16:12.822000000', '2022-07-14T10:06:16.331000000',
             '2022-07-19T10:06:08.645000000', '2022-08-03T10:06:14.409000000',
             '2022-08-16T10:16:12.609000000', '2022-08-26T10:16:12.680000000'],
            dtype='datetime64[ns]')
    • id
      (time)
      <U24
      'S2B_33UXU_20220619_0_L2A' ... '...
      array(['S2B_33UXU_20220619_0_L2A', 'S2A_33UXU_20220624_0_L2A',
             'S2A_33UXU_20220627_0_L2A', 'S2A_33UXU_20220714_0_L2A',
             'S2B_33UXU_20220719_0_L2A', 'S2A_33UXU_20220803_0_L2A',
             'S2A_33UXU_20220816_0_L2A', 'S2A_33UXU_20220826_0_L2A'],
            dtype='<U24')
    • band
      (band)
      <U12
      'aot' 'blue' ... 'wvp-jp2'
      array(['aot', 'blue', 'coastal', 'green', 'nir', 'nir08', 'nir09', 'red',
             'rededge1', 'rededge2', 'rededge3', 'scl', 'swir16', 'swir22', 'visual',
             'wvp', 'aot-jp2', 'blue-jp2', 'coastal-jp2', 'green-jp2', 'nir-jp2',
             'nir08-jp2', 'nir09-jp2', 'red-jp2', 'rededge1-jp2', 'rededge2-jp2',
             'rededge3-jp2', 'scl-jp2', 'swir16-jp2', 'swir22-jp2', 'visual-jp2',
             'wvp-jp2'], dtype='<U12')
    • x
      (x)
      float64
      6.19e+05 6.192e+05 ... 6.474e+05
      array([619000., 619200., 619400., 619600., 619800., 620000., 620200., 620400.,
             620600., 620800., 621000., 621200., 621400., 621600., 621800., 622000.,
             622200., 622400., 622600., 622800., 623000., 623200., 623400., 623600.,
             623800., 624000., 624200., 624400., 624600., 624800., 625000., 625200.,
             625400., 625600., 625800., 626000., 626200., 626400., 626600., 626800.,
             627000., 627200., 627400., 627600., 627800., 628000., 628200., 628400.,
             628600., 628800., 629000., 629200., 629400., 629600., 629800., 630000.,
             630200., 630400., 630600., 630800., 631000., 631200., 631400., 631600.,
             631800., 632000., 632200., 632400., 632600., 632800., 633000., 633200.,
             633400., 633600., 633800., 634000., 634200., 634400., 634600., 634800.,
             635000., 635200., 635400., 635600., 635800., 636000., 636200., 636400.,
             636600., 636800., 637000., 637200., 637400., 637600., 637800., 638000.,
             638200., 638400., 638600., 638800., 639000., 639200., 639400., 639600.,
             639800., 640000., 640200., 640400., 640600., 640800., 641000., 641200.,
             641400., 641600., 641800., 642000., 642200., 642400., 642600., 642800.,
             643000., 643200., 643400., 643600., 643800., 644000., 644200., 644400.,
             644600., 644800., 645000., 645200., 645400., 645600., 645800., 646000.,
             646200., 646400., 646600., 646800., 647000., 647200., 647400.])
    • y
      (y)
      float64
      5.823e+06 5.823e+06 ... 5.795e+06
      array([5823000., 5822800., 5822600., 5822400., 5822200., 5822000., 5821800.,
             5821600., 5821400., 5821200., 5821000., 5820800., 5820600., 5820400.,
             5820200., 5820000., 5819800., 5819600., 5819400., 5819200., 5819000.,
             5818800., 5818600., 5818400., 5818200., 5818000., 5817800., 5817600.,
             5817400., 5817200., 5817000., 5816800., 5816600., 5816400., 5816200.,
             5816000., 5815800., 5815600., 5815400., 5815200., 5815000., 5814800.,
             5814600., 5814400., 5814200., 5814000., 5813800., 5813600., 5813400.,
             5813200., 5813000., 5812800., 5812600., 5812400., 5812200., 5812000.,
             5811800., 5811600., 5811400., 5811200., 5811000., 5810800., 5810600.,
             5810400., 5810200., 5810000., 5809800., 5809600., 5809400., 5809200.,
             5809000., 5808800., 5808600., 5808400., 5808200., 5808000., 5807800.,
             5807600., 5807400., 5807200., 5807000., 5806800., 5806600., 5806400.,
             5806200., 5806000., 5805800., 5805600., 5805400., 5805200., 5805000.,
             5804800., 5804600., 5804400., 5804200., 5804000., 5803800., 5803600.,
             5803400., 5803200., 5803000., 5802800., 5802600., 5802400., 5802200.,
             5802000., 5801800., 5801600., 5801400., 5801200., 5801000., 5800800.,
             5800600., 5800400., 5800200., 5800000., 5799800., 5799600., 5799400.,
             5799200., 5799000., 5798800., 5798600., 5798400., 5798200., 5798000.,
             5797800., 5797600., 5797400., 5797200., 5797000., 5796800., 5796600.,
             5796400., 5796200., 5796000., 5795800., 5795600., 5795400., 5795200.])
    • s2:nodata_pixel_percentage
      (time)
      object
      0 0 ... 60.335821 60.458738
      array([0, 0, 60.372794, 0, 3e-06, 3e-06, 60.335821, 60.458738],
            dtype=object)
    • s2:not_vegetated_percentage
      (time)
      float64
      10.43 11.0 12.07 ... 35.87 34.91
      array([10.429534, 11.000518, 12.070826, 30.188122, 34.062394, 34.022531,
             35.867879, 34.906355])
    • earthsearch:boa_offset_applied
      ()
      bool
      True
      array(True)
    • proj:epsg
      ()
      int64
      32633
      array(32633)
    • s2:saturated_defective_pixel_percentage
      ()
      int64
      0
      array(0)
    • s2:degraded_msi_data_percentage
      (time)
      object
      0 0 0.0045 0 0 0 0.0045 0.0044
      array([0, 0, 0.0045, 0, 0, 0, 0.0045, 0.0044], dtype=object)
    • s2:high_proba_clouds_percentage
      (time)
      float64
      0.007488 0.000484 ... 0.000537
      array([7.488000e-03, 4.840000e-04, 3.348470e-01, 4.827590e-01,
             3.000000e-06, 3.067140e+00, 2.117714e+00, 5.370000e-04])
    • earthsearch:s3_path
      (time)
      <U79
      's3://sentinel-cogs/sentinel-s2-...
      array(['s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/6/S2B_33UXU_20220619_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/6/S2A_33UXU_20220624_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/6/S2A_33UXU_20220627_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/7/S2A_33UXU_20220714_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/7/S2B_33UXU_20220719_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/8/S2A_33UXU_20220803_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/8/S2A_33UXU_20220816_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/8/S2A_33UXU_20220826_0_L2A'],
            dtype='<U79')
    • s2:datastrip_id
      (time)
      <U64
      'S2B_OPER_MSI_L2A_DS_2BPS_202206...
      array(['S2B_OPER_MSI_L2A_DS_2BPS_20220619T114329_S20220619T100031_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220624T143914_S20220624T100039_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220627T162810_S20220627T100933_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220714T175057_S20220714T100046_N04.00',
             'S2B_OPER_MSI_L2A_DS_2BPS_20220719T113943_S20220719T095747_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220803T135155_S20220803T100037_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220816T162557_S20220816T100922_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220826T162059_S20220826T100933_N04.00'],
            dtype='<U64')
    • s2:datatake_type
      ()
      <U8
      'INS-NOBS'
      array('INS-NOBS', dtype='<U8')
    • s2:vegetation_percentage
      (time)
      float64
      80.88 87.55 84.59 ... 55.84 64.06
      array([80.8779  , 87.545991, 84.593809, 64.089584, 64.467937, 49.599385,
             55.840641, 64.060515])
    • s2:water_percentage
      (time)
      float64
      1.067 1.266 ... 0.7679 0.7824
      array([1.066825, 1.266303, 0.75182 , 1.253815, 1.263951, 1.116363,
             0.767899, 0.782386])
    • constellation
      ()
      <U10
      'sentinel-2'
      array('sentinel-2', dtype='<U10')
    • s2:medium_proba_clouds_percentage
      (time)
      float64
      0.05143 0.001297 ... 2.271 0.00172
      array([5.143000e-02, 1.297000e-03, 7.322780e-01, 1.287753e+00,
             7.000000e-05, 5.689905e+00, 2.270966e+00, 1.720000e-03])
    • s2:granule_id
      (time)
      <U62
      'S2B_OPER_MSI_L2A_TL_2BPS_202206...
      array(['S2B_OPER_MSI_L2A_TL_2BPS_20220619T114329_A027604_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220624T143914_A036584_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220627T162810_A036627_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220714T175057_A036870_T33UXU_N04.00',
             'S2B_OPER_MSI_L2A_TL_2BPS_20220719T113943_A028033_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220803T135155_A037156_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220816T162557_A037342_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220826T162059_A037485_T33UXU_N04.00'],
            dtype='<U62')
    • eo:cloud_cover
      (time)
      float64
      7.491 0.002495 ... 4.8 0.003331
      array([7.491449e+00, 2.495000e-03, 1.067175e+00, 1.825375e+00,
             5.511000e-03, 8.775087e+00, 4.800238e+00, 3.331000e-03])
    • platform
      (time)
      <U11
      'sentinel-2b' ... 'sentinel-2a'
      array(['sentinel-2b', 'sentinel-2a', 'sentinel-2a', 'sentinel-2a',
             'sentinel-2b', 'sentinel-2a', 'sentinel-2a', 'sentinel-2a'],
            dtype='<U11')
    • s2:dark_features_percentage
      (time)
      float64
      0.002057 0.004107 ... 0.01486
      array([0.002057, 0.004107, 0.006966, 0.00361 , 0.004429, 0.003646,
             0.010289, 0.01486 ])
    • s2:product_type
      ()
      <U7
      'S2MSI2A'
      array('S2MSI2A', dtype='<U7')
    • s2:unclassified_percentage
      (time)
      float64
      0.1322 0.1796 ... 0.9699 0.2326
      array([0.132232, 0.179595, 0.340984, 0.291771, 0.195772, 2.000013,
             0.96991 , 0.232552])
    • s2:datatake_id
      (time)
      <U34
      'GS2B_20220619T100029_027604_N04...
      array(['GS2B_20220619T100029_027604_N04.00',
             'GS2A_20220624T100041_036584_N04.00',
             'GS2A_20220627T100611_036627_N04.00',
             'GS2A_20220714T100041_036870_N04.00',
             'GS2B_20220719T095559_028033_N04.00',
             'GS2A_20220803T100041_037156_N04.00',
             'GS2A_20220816T100611_037342_N04.00',
             'GS2A_20220826T100611_037485_N04.00'], dtype='<U34')
    • earthsearch:payload_id
      (time)
      <U74
      'roda-sentinel2/workflow-sentine...
      array(['roda-sentinel2/workflow-sentinel2-to-stac/58f82edc8c40c1d0d56d8a26269d02eb',
             'roda-sentinel2/workflow-sentinel2-to-stac/9b8a11349c8bf4f2437e596421530090',
             'roda-sentinel2/workflow-sentinel2-to-stac/fd889d2975690939ea2990c8b784fc31',
             'roda-sentinel2/workflow-sentinel2-to-stac/1cea63f7fa1542d8a1c7bcd0b774584d',
             'roda-sentinel2/workflow-sentinel2-to-stac/4f39107c8fe71ec8f29d674a811d6c21',
             'roda-sentinel2/workflow-sentinel2-to-stac/6245fb70f8c638a7681c672a7bf7a006',
             'roda-sentinel2/workflow-sentinel2-to-stac/b5b785b4fac74933d25c20aec8ce66bd',
             'roda-sentinel2/workflow-sentinel2-to-stac/bff15f451a9bb2107d01668bb557f526'],
            dtype='<U74')
    • mgrs:grid_square
      ()
      <U2
      'XU'
      array('XU', dtype='<U2')
    • s2:snow_ice_percentage
      ()
      int64
      0
      array(0)
    • s2:thin_cirrus_percentage
      (time)
      float64
      7.433 0.000713 ... 0.4116 0.001074
      array([7.43253e+00, 7.13000e-04, 5.00000e-05, 5.48640e-02, 5.43800e-03,
             1.80420e-02, 4.11558e-01, 1.07400e-03])
    • view:sun_azimuth
      (time)
      float64
      158.9 158.5 162.7 ... 165.2 166.8
      array([158.91324506, 158.50630661, 162.6663807 , 157.84964052,
             157.99361406, 159.43576449, 165.15376613, 166.81057205])
    • s2:cloud_shadow_percentage
      (time)
      object
      0 0.000989 1.168417 ... 1.743145 0
      array([0, 0.000989, 1.168417, 2.347726, 0, 4.482971, 1.743145, 0],
            dtype=object)
    • mgrs:latitude_band
      ()
      <U1
      'U'
      array('U', dtype='<U1')
    • updated
      (time)
      <U24
      '2022-11-06T13:16:38.195Z' ... '...
      array(['2022-11-06T13:16:38.195Z', '2022-11-06T12:52:50.337Z',
             '2022-11-06T12:55:07.931Z', '2022-11-06T12:54:05.312Z',
             '2022-11-06T13:14:37.621Z', '2022-11-06T13:12:58.202Z',
             '2022-11-06T12:53:48.090Z', '2022-11-06T13:14:57.270Z'],
            dtype='<U24')
    • processing:software
      ()
      object
      {'sentinel2-to-stac': '0.1.0'}
      array({'sentinel2-to-stac': '0.1.0'}, dtype=object)
    • instruments
      ()
      <U3
      'msi'
      array('msi', dtype='<U3')
    • s2:product_uri
      (time)
      <U65
      'S2B_MSIL2A_20220619T100029_N040...
      array(['S2B_MSIL2A_20220619T100029_N0400_R122_T33UXU_20220619T114329.SAFE',
             'S2A_MSIL2A_20220624T100041_N0400_R122_T33UXU_20220624T143914.SAFE',
             'S2A_MSIL2A_20220627T100611_N0400_R022_T33UXU_20220627T162810.SAFE',
             'S2A_MSIL2A_20220714T100041_N0400_R122_T33UXU_20220714T175057.SAFE',
             'S2B_MSIL2A_20220719T095559_N0400_R122_T33UXU_20220719T113943.SAFE',
             'S2A_MSIL2A_20220803T100041_N0400_R122_T33UXU_20220803T135155.SAFE',
             'S2A_MSIL2A_20220816T100611_N0400_R022_T33UXU_20220816T162557.SAFE',
             'S2A_MSIL2A_20220826T100611_N0400_R022_T33UXU_20220826T162059.SAFE'],
            dtype='<U65')
    • view:sun_elevation
      (time)
      float64
      59.41 59.34 59.71 ... 50.17 46.97
      array([59.4067386 , 59.33648111, 59.7142557 , 57.43426893, 56.58894221,
             53.33325433, 50.17160714, 46.96899755])
    • s2:generation_time
      (time)
      <U27
      '2022-06-19T11:43:29.000000Z' .....
      array(['2022-06-19T11:43:29.000000Z', '2022-06-24T14:39:14.000000Z',
             '2022-06-27T16:28:10.000000Z', '2022-07-14T17:50:57.000000Z',
             '2022-07-19T11:39:43.000000Z', '2022-08-03T13:51:55.000000Z',
             '2022-08-16T16:25:57.000000Z', '2022-08-26T16:20:59.000000Z'],
            dtype='<U27')
    • s2:reflectance_conversion_factor
      (time)
      float64
      0.9691 0.9683 ... 0.9741 0.9779
      array([0.96912679, 0.96833888, 0.96797547, 0.96750684, 0.96788495,
             0.97039583, 0.97414715, 0.9779224 ])
    • s2:sequence
      ()
      <U1
      '0'
      array('0', dtype='<U1')
    • mgrs:utm_zone
      ()
      int64
      33
      array(33)
    • grid:code
      ()
      <U10
      'MGRS-33UXU'
      array('MGRS-33UXU', dtype='<U10')
    • s2:processing_baseline
      ()
      <U5
      '04.00'
      array('04.00', dtype='<U5')
    • created
      (time)
      <U24
      '2022-11-06T13:16:38.195Z' ... '...
      array(['2022-11-06T13:16:38.195Z', '2022-11-06T12:52:50.337Z',
             '2022-11-06T12:55:07.931Z', '2022-11-06T12:54:05.312Z',
             '2022-11-06T13:14:37.621Z', '2022-11-06T13:12:58.202Z',
             '2022-11-06T12:53:48.090Z', '2022-11-06T13:14:57.270Z'],
            dtype='<U24')
    • raster:bands
      (band)
      object
      [{'nodata': 0, 'data_type': 'uin...
      array([list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.001, 'offset': 0}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 60, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 60, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint8', 'spatial_resolution': 20}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             None,
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'unit': 'cm', 'scale': 0.001, 'offset': 0}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.001, 'offset': 0}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 60, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 60, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint8', 'spatial_resolution': 20}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'scale': 0.0001, 'offset': -0.1}]),
             None,
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 20, 'unit': 'cm', 'scale': 0.001, 'offset': 0}])],
            dtype=object)
    • title
      (band)
      <U31
      'Aerosol optical thickness (AOT)...
      array(['Aerosol optical thickness (AOT)', 'Blue (band 2) - 10m',
             'Coastal aerosol (band 1) - 60m', 'Green (band 3) - 10m',
             'NIR 1 (band 8) - 10m', 'NIR 2 (band 8A) - 20m',
             'NIR 3 (band 9) - 60m', 'Red (band 4) - 10m',
             'Red edge 1 (band 5) - 20m', 'Red edge 2 (band 6) - 20m',
             'Red edge 3 (band 7) - 20m', 'Scene classification map (SCL)',
             'SWIR 1 (band 11) - 20m', 'SWIR 2 (band 12) - 20m',
             'True color image', 'Water vapour (WVP)',
             'Aerosol optical thickness (AOT)', 'Blue (band 2) - 10m',
             'Coastal aerosol (band 1) - 60m', 'Green (band 3) - 10m',
             'NIR 1 (band 8) - 10m', 'NIR 2 (band 8A) - 20m',
             'NIR 3 (band 9) - 60m', 'Red (band 4) - 10m',
             'Red edge 1 (band 5) - 20m', 'Red edge 2 (band 6) - 20m',
             'Red edge 3 (band 7) - 20m', 'Scene classification map (SCL)',
             'SWIR 1 (band 11) - 20m', 'SWIR 2 (band 12) - 20m',
             'True color image', 'Water vapour (WVP)'], dtype='<U31')
    • gsd
      (band)
      object
      None 10 60 10 ... 20 20 None None
      array([None, 10, 60, 10, 10, 20, 60, 10, 20, 20, 20, None, 20, 20, None,
             None, None, 10, 60, 10, 10, 20, 60, 10, 20, 20, 20, None, 20, 20,
             None, None], dtype=object)
    • common_name
      (band)
      object
      None 'blue' 'coastal' ... None None
      array([None, 'blue', 'coastal', 'green', 'nir', 'nir08', 'nir09', 'red',
             'rededge', 'rededge', 'rededge', None, 'swir16', 'swir22', None,
             None, None, 'blue', 'coastal', 'green', 'nir', 'nir08', 'nir09',
             'red', 'rededge', 'rededge', 'rededge', None, 'swir16', 'swir22',
             None, None], dtype=object)
    • center_wavelength
      (band)
      object
      None 0.49 0.443 ... 2.19 None None
      array([None, 0.49, 0.443, 0.56, 0.842, 0.865, 0.945, 0.665, 0.704, 0.74,
             0.783, None, 1.61, 2.19, None, None, None, 0.49, 0.443, 0.56,
             0.842, 0.865, 0.945, 0.665, 0.704, 0.74, 0.783, None, 1.61, 2.19,
             None, None], dtype=object)
    • full_width_half_max
      (band)
      object
      None 0.098 0.027 ... None None
      array([None, 0.098, 0.027, 0.045, 0.145, 0.033, 0.026, 0.038, 0.019,
             0.018, 0.028, None, 0.143, 0.242, None, None, None, 0.098, 0.027,
             0.045, 0.145, 0.033, 0.026, 0.038, 0.019, 0.018, 0.028, None,
             0.143, 0.242, None, None], dtype=object)
    • epsg
      ()
      int64
      32633
      array(32633)
    • time
      PandasIndex
      PandasIndex(DatetimeIndex(['2022-06-19 10:06:08.087000', '2022-06-24 10:06:16.177000',
                     '2022-06-27 10:16:12.822000', '2022-07-14 10:06:16.331000',
                     '2022-07-19 10:06:08.645000', '2022-08-03 10:06:14.409000',
                     '2022-08-16 10:16:12.609000', '2022-08-26 10:16:12.680000'],
                    dtype='datetime64[ns]', name='time', freq=None))
    • band
      PandasIndex
      PandasIndex(Index(['aot', 'blue', 'coastal', 'green', 'nir', 'nir08', 'nir09', 'red',
             'rededge1', 'rededge2', 'rededge3', 'scl', 'swir16', 'swir22', 'visual',
             'wvp', 'aot-jp2', 'blue-jp2', 'coastal-jp2', 'green-jp2', 'nir-jp2',
             'nir08-jp2', 'nir09-jp2', 'red-jp2', 'rededge1-jp2', 'rededge2-jp2',
             'rededge3-jp2', 'scl-jp2', 'swir16-jp2', 'swir22-jp2', 'visual-jp2',
             'wvp-jp2'],
            dtype='object', name='band'))
    • x
      PandasIndex
      PandasIndex(Index([619000.0, 619200.0, 619400.0, 619600.0, 619800.0, 620000.0, 620200.0,
             620400.0, 620600.0, 620800.0,
             ...
             645600.0, 645800.0, 646000.0, 646200.0, 646400.0, 646600.0, 646800.0,
             647000.0, 647200.0, 647400.0],
            dtype='float64', name='x', length=143))
    • y
      PandasIndex
      PandasIndex(Index([5823000.0, 5822800.0, 5822600.0, 5822400.0, 5822200.0, 5822000.0,
             5821800.0, 5821600.0, 5821400.0, 5821200.0,
             ...
             5797000.0, 5796800.0, 5796600.0, 5796400.0, 5796200.0, 5796000.0,
             5795800.0, 5795600.0, 5795400.0, 5795200.0],
            dtype='float64', name='y', length=140))
  • spec :
    RasterSpec(epsg=32633, bounds=(619000, 5795000, 647600, 5823000), resolutions_xy=(200, 200))
    crs :
    epsg:32633
    transform :
    | 200.00, 0.00, 619000.00| | 0.00,-200.00, 5823000.00| | 0.00, 0.00, 1.00|
    resolution :
    200

We can further wrangle this cube by selecting only RGB bands and creating monthly composites. We can achieve this with xarray resample. This are all the time range formats supported.

In [52]:
rgb = cube.sel(band=["red", "green", "blue"])
monthly = rgb.resample(time="MS").median("time", keep_attrs=True)
In [53]:
monthly
Out[53]:
<xarray.DataArray 'stackstac-26bf16b18d945f83e54e4d04b774ec18' (time: 3,
                                                                band: 3,
                                                                y: 140, x: 143)>
dask.array<stack, shape=(3, 3, 140, 143), dtype=float64, chunksize=(1, 3, 140, 143), chunktype=numpy.ndarray>
Coordinates: (12/26)
  * band                                     (band) <U12 'red' 'green' 'blue'
  * x                                        (x) float64 6.19e+05 ... 6.474e+05
  * y                                        (y) float64 5.823e+06 ... 5.795e+06
    earthsearch:boa_offset_applied           bool True
    proj:epsg                                int64 32633
    s2:saturated_defective_pixel_percentage  int64 0
    ...                                       ...
    gsd                                      (band) object 10 10 10
    common_name                              (band) object 'red' 'green' 'blue'
    center_wavelength                        (band) object 0.665 0.56 0.49
    full_width_half_max                      (band) object 0.038 0.045 0.098
    epsg                                     int64 32633
  * time                                     (time) datetime64[ns] 2022-06-01...
Attributes:
    spec:        RasterSpec(epsg=32633, bounds=(619000, 5795000, 647600, 5823...
    crs:         epsg:32633
    transform:   | 200.00, 0.00, 619000.00|\n| 0.00,-200.00, 5823000.00|\n| 0...
    resolution:  200
xarray.DataArray
'stackstac-26bf16b18d945f83e54e4d04b774ec18'
  • time: 3
  • band: 3
  • y: 140
  • x: 143
  • dask.array<chunksize=(1, 3, 140, 143), meta=np.ndarray>
    Array Chunk
    Bytes 1.37 MiB 469.22 kiB
    Shape (3, 3, 140, 143) (1, 3, 140, 143)
    Dask graph 3 chunks in 14 graph layers
    Data type float64 numpy.ndarray
    3 1 143 140 3
    • band
      (band)
      <U12
      'red' 'green' 'blue'
      array(['red', 'green', 'blue'], dtype='<U12')
    • x
      (x)
      float64
      6.19e+05 6.192e+05 ... 6.474e+05
      array([619000., 619200., 619400., 619600., 619800., 620000., 620200., 620400.,
             620600., 620800., 621000., 621200., 621400., 621600., 621800., 622000.,
             622200., 622400., 622600., 622800., 623000., 623200., 623400., 623600.,
             623800., 624000., 624200., 624400., 624600., 624800., 625000., 625200.,
             625400., 625600., 625800., 626000., 626200., 626400., 626600., 626800.,
             627000., 627200., 627400., 627600., 627800., 628000., 628200., 628400.,
             628600., 628800., 629000., 629200., 629400., 629600., 629800., 630000.,
             630200., 630400., 630600., 630800., 631000., 631200., 631400., 631600.,
             631800., 632000., 632200., 632400., 632600., 632800., 633000., 633200.,
             633400., 633600., 633800., 634000., 634200., 634400., 634600., 634800.,
             635000., 635200., 635400., 635600., 635800., 636000., 636200., 636400.,
             636600., 636800., 637000., 637200., 637400., 637600., 637800., 638000.,
             638200., 638400., 638600., 638800., 639000., 639200., 639400., 639600.,
             639800., 640000., 640200., 640400., 640600., 640800., 641000., 641200.,
             641400., 641600., 641800., 642000., 642200., 642400., 642600., 642800.,
             643000., 643200., 643400., 643600., 643800., 644000., 644200., 644400.,
             644600., 644800., 645000., 645200., 645400., 645600., 645800., 646000.,
             646200., 646400., 646600., 646800., 647000., 647200., 647400.])
    • y
      (y)
      float64
      5.823e+06 5.823e+06 ... 5.795e+06
      array([5823000., 5822800., 5822600., 5822400., 5822200., 5822000., 5821800.,
             5821600., 5821400., 5821200., 5821000., 5820800., 5820600., 5820400.,
             5820200., 5820000., 5819800., 5819600., 5819400., 5819200., 5819000.,
             5818800., 5818600., 5818400., 5818200., 5818000., 5817800., 5817600.,
             5817400., 5817200., 5817000., 5816800., 5816600., 5816400., 5816200.,
             5816000., 5815800., 5815600., 5815400., 5815200., 5815000., 5814800.,
             5814600., 5814400., 5814200., 5814000., 5813800., 5813600., 5813400.,
             5813200., 5813000., 5812800., 5812600., 5812400., 5812200., 5812000.,
             5811800., 5811600., 5811400., 5811200., 5811000., 5810800., 5810600.,
             5810400., 5810200., 5810000., 5809800., 5809600., 5809400., 5809200.,
             5809000., 5808800., 5808600., 5808400., 5808200., 5808000., 5807800.,
             5807600., 5807400., 5807200., 5807000., 5806800., 5806600., 5806400.,
             5806200., 5806000., 5805800., 5805600., 5805400., 5805200., 5805000.,
             5804800., 5804600., 5804400., 5804200., 5804000., 5803800., 5803600.,
             5803400., 5803200., 5803000., 5802800., 5802600., 5802400., 5802200.,
             5802000., 5801800., 5801600., 5801400., 5801200., 5801000., 5800800.,
             5800600., 5800400., 5800200., 5800000., 5799800., 5799600., 5799400.,
             5799200., 5799000., 5798800., 5798600., 5798400., 5798200., 5798000.,
             5797800., 5797600., 5797400., 5797200., 5797000., 5796800., 5796600.,
             5796400., 5796200., 5796000., 5795800., 5795600., 5795400., 5795200.])
    • earthsearch:boa_offset_applied
      ()
      bool
      True
      array(True)
    • proj:epsg
      ()
      int64
      32633
      array(32633)
    • s2:saturated_defective_pixel_percentage
      ()
      int64
      0
      array(0)
    • s2:datatake_type
      ()
      <U8
      'INS-NOBS'
      array('INS-NOBS', dtype='<U8')
    • constellation
      ()
      <U10
      'sentinel-2'
      array('sentinel-2', dtype='<U10')
    • s2:product_type
      ()
      <U7
      'S2MSI2A'
      array('S2MSI2A', dtype='<U7')
    • mgrs:grid_square
      ()
      <U2
      'XU'
      array('XU', dtype='<U2')
    • s2:snow_ice_percentage
      ()
      int64
      0
      array(0)
    • mgrs:latitude_band
      ()
      <U1
      'U'
      array('U', dtype='<U1')
    • processing:software
      ()
      object
      {'sentinel2-to-stac': '0.1.0'}
      array({'sentinel2-to-stac': '0.1.0'}, dtype=object)
    • instruments
      ()
      <U3
      'msi'
      array('msi', dtype='<U3')
    • s2:sequence
      ()
      <U1
      '0'
      array('0', dtype='<U1')
    • mgrs:utm_zone
      ()
      int64
      33
      array(33)
    • grid:code
      ()
      <U10
      'MGRS-33UXU'
      array('MGRS-33UXU', dtype='<U10')
    • s2:processing_baseline
      ()
      <U5
      '04.00'
      array('04.00', dtype='<U5')
    • raster:bands
      (band)
      object
      [{'nodata': 0, 'data_type': 'uin...
      array([list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}])],
            dtype=object)
    • title
      (band)
      <U31
      'Red (band 4) - 10m' ... 'Blue (...
      array(['Red (band 4) - 10m', 'Green (band 3) - 10m',
             'Blue (band 2) - 10m'], dtype='<U31')
    • gsd
      (band)
      object
      10 10 10
      array([10, 10, 10], dtype=object)
    • common_name
      (band)
      object
      'red' 'green' 'blue'
      array(['red', 'green', 'blue'], dtype=object)
    • center_wavelength
      (band)
      object
      0.665 0.56 0.49
      array([0.665, 0.56, 0.49], dtype=object)
    • full_width_half_max
      (band)
      object
      0.038 0.045 0.098
      array([0.038, 0.045, 0.098], dtype=object)
    • epsg
      ()
      int64
      32633
      array(32633)
    • time
      (time)
      datetime64[ns]
      2022-06-01 2022-07-01 2022-08-01
      array(['2022-06-01T00:00:00.000000000', '2022-07-01T00:00:00.000000000',
             '2022-08-01T00:00:00.000000000'], dtype='datetime64[ns]')
    • band
      PandasIndex
      PandasIndex(Index(['red', 'green', 'blue'], dtype='object', name='band'))
    • x
      PandasIndex
      PandasIndex(Index([619000.0, 619200.0, 619400.0, 619600.0, 619800.0, 620000.0, 620200.0,
             620400.0, 620600.0, 620800.0,
             ...
             645600.0, 645800.0, 646000.0, 646200.0, 646400.0, 646600.0, 646800.0,
             647000.0, 647200.0, 647400.0],
            dtype='float64', name='x', length=143))
    • y
      PandasIndex
      PandasIndex(Index([5823000.0, 5822800.0, 5822600.0, 5822400.0, 5822200.0, 5822000.0,
             5821800.0, 5821600.0, 5821400.0, 5821200.0,
             ...
             5797000.0, 5796800.0, 5796600.0, 5796400.0, 5796200.0, 5796000.0,
             5795800.0, 5795600.0, 5795400.0, 5795200.0],
            dtype='float64', name='y', length=140))
    • time
      PandasIndex
      PandasIndex(DatetimeIndex(['2022-06-01', '2022-07-01', '2022-08-01'], dtype='datetime64[ns]', name='time', freq='MS'))
  • spec :
    RasterSpec(epsg=32633, bounds=(619000, 5795000, 647600, 5823000), resolutions_xy=(200, 200))
    crs :
    epsg:32633
    transform :
    | 200.00, 0.00, 619000.00| | 0.00,-200.00, 5823000.00| | 0.00, 0.00, 1.00|
    resolution :
    200

We will use the compute() function from dask to read our object in-memory.

In [54]:
monthly = monthly.compute()

This will make plotting tasks faster.

In [55]:
monthly.plot.imshow(
    col="time",
    col_wrap=3,
    rgb="band",
    robust=True,
    size=4,
    add_labels=False,
)
Out[55]:
<xarray.plot.facetgrid.FacetGrid at 0x7f8e507dbd50>
No description has been provided for this image

Let's take a look now at a smaller area to visualize crops around Poznan.

In [56]:
crops = gpd.read_file("../../data/crops.geojson")
cube = stackstac.stack(
    items,
    resolution=10,
    bounds_latlon=crops.total_bounds,
    resampling=Resampling.bilinear
)
rgb = cube.sel(band=["red", "green", "blue"])
rgb
/opt/conda/lib/python3.11/site-packages/stackstac/prepare.py:364: 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(
Out[56]:
<xarray.DataArray 'stackstac-34b7fdf5d830fa45909152427d7b3f8a' (time: 8,
                                                                band: 3,
                                                                y: 748, x: 1239)>
dask.array<getitem, shape=(8, 3, 748, 1239), dtype=float64, chunksize=(1, 1, 748, 1024), chunktype=numpy.ndarray>
Coordinates: (12/52)
  * time                                     (time) datetime64[ns] 2022-06-19...
    id                                       (time) <U24 'S2B_33UXU_20220619_...
  * band                                     (band) <U12 'red' 'green' 'blue'
  * x                                        (x) float64 6.328e+05 ... 6.452e+05
  * y                                        (y) float64 5.809e+06 ... 5.801e+06
    s2:nodata_pixel_percentage               (time) object 0 0 ... 60.458738
    ...                                       ...
    title                                    (band) <U31 'Red (band 4) - 10m'...
    gsd                                      (band) object 10 10 10
    common_name                              (band) object 'red' 'green' 'blue'
    center_wavelength                        (band) object 0.665 0.56 0.49
    full_width_half_max                      (band) object 0.038 0.045 0.098
    epsg                                     int64 32633
Attributes:
    spec:        RasterSpec(epsg=32633, bounds=(632780, 5801330, 645170, 5808...
    crs:         epsg:32633
    transform:   | 10.00, 0.00, 632780.00|\n| 0.00,-10.00, 5808810.00|\n| 0.0...
    resolution:  10
xarray.DataArray
'stackstac-34b7fdf5d830fa45909152427d7b3f8a'
  • time: 8
  • band: 3
  • y: 748
  • x: 1239
  • dask.array<chunksize=(1, 1, 748, 1024), meta=np.ndarray>
    Array Chunk
    Bytes 169.70 MiB 5.84 MiB
    Shape (8, 3, 748, 1239) (1, 1, 748, 1024)
    Dask graph 48 chunks in 4 graph layers
    Data type float64 numpy.ndarray
    8 1 1239 748 3
    • time
      (time)
      datetime64[ns]
      2022-06-19T10:06:08.087000 ... 2...
      array(['2022-06-19T10:06:08.087000000', '2022-06-24T10:06:16.177000000',
             '2022-06-27T10:16:12.822000000', '2022-07-14T10:06:16.331000000',
             '2022-07-19T10:06:08.645000000', '2022-08-03T10:06:14.409000000',
             '2022-08-16T10:16:12.609000000', '2022-08-26T10:16:12.680000000'],
            dtype='datetime64[ns]')
    • id
      (time)
      <U24
      'S2B_33UXU_20220619_0_L2A' ... '...
      array(['S2B_33UXU_20220619_0_L2A', 'S2A_33UXU_20220624_0_L2A',
             'S2A_33UXU_20220627_0_L2A', 'S2A_33UXU_20220714_0_L2A',
             'S2B_33UXU_20220719_0_L2A', 'S2A_33UXU_20220803_0_L2A',
             'S2A_33UXU_20220816_0_L2A', 'S2A_33UXU_20220826_0_L2A'],
            dtype='<U24')
    • band
      (band)
      <U12
      'red' 'green' 'blue'
      array(['red', 'green', 'blue'], dtype='<U12')
    • x
      (x)
      float64
      6.328e+05 6.328e+05 ... 6.452e+05
      array([632780., 632790., 632800., ..., 645140., 645150., 645160.])
    • y
      (y)
      float64
      5.809e+06 5.809e+06 ... 5.801e+06
      array([5808810., 5808800., 5808790., ..., 5801360., 5801350., 5801340.])
    • s2:nodata_pixel_percentage
      (time)
      object
      0 0 ... 60.335821 60.458738
      array([0, 0, 60.372794, 0, 3e-06, 3e-06, 60.335821, 60.458738],
            dtype=object)
    • s2:not_vegetated_percentage
      (time)
      float64
      10.43 11.0 12.07 ... 35.87 34.91
      array([10.429534, 11.000518, 12.070826, 30.188122, 34.062394, 34.022531,
             35.867879, 34.906355])
    • earthsearch:boa_offset_applied
      ()
      bool
      True
      array(True)
    • proj:epsg
      ()
      int64
      32633
      array(32633)
    • s2:saturated_defective_pixel_percentage
      ()
      int64
      0
      array(0)
    • s2:degraded_msi_data_percentage
      (time)
      object
      0 0 0.0045 0 0 0 0.0045 0.0044
      array([0, 0, 0.0045, 0, 0, 0, 0.0045, 0.0044], dtype=object)
    • s2:high_proba_clouds_percentage
      (time)
      float64
      0.007488 0.000484 ... 0.000537
      array([7.488000e-03, 4.840000e-04, 3.348470e-01, 4.827590e-01,
             3.000000e-06, 3.067140e+00, 2.117714e+00, 5.370000e-04])
    • earthsearch:s3_path
      (time)
      <U79
      's3://sentinel-cogs/sentinel-s2-...
      array(['s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/6/S2B_33UXU_20220619_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/6/S2A_33UXU_20220624_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/6/S2A_33UXU_20220627_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/7/S2A_33UXU_20220714_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/7/S2B_33UXU_20220719_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/8/S2A_33UXU_20220803_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/8/S2A_33UXU_20220816_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/8/S2A_33UXU_20220826_0_L2A'],
            dtype='<U79')
    • s2:datastrip_id
      (time)
      <U64
      'S2B_OPER_MSI_L2A_DS_2BPS_202206...
      array(['S2B_OPER_MSI_L2A_DS_2BPS_20220619T114329_S20220619T100031_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220624T143914_S20220624T100039_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220627T162810_S20220627T100933_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220714T175057_S20220714T100046_N04.00',
             'S2B_OPER_MSI_L2A_DS_2BPS_20220719T113943_S20220719T095747_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220803T135155_S20220803T100037_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220816T162557_S20220816T100922_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220826T162059_S20220826T100933_N04.00'],
            dtype='<U64')
    • s2:datatake_type
      ()
      <U8
      'INS-NOBS'
      array('INS-NOBS', dtype='<U8')
    • s2:vegetation_percentage
      (time)
      float64
      80.88 87.55 84.59 ... 55.84 64.06
      array([80.8779  , 87.545991, 84.593809, 64.089584, 64.467937, 49.599385,
             55.840641, 64.060515])
    • s2:water_percentage
      (time)
      float64
      1.067 1.266 ... 0.7679 0.7824
      array([1.066825, 1.266303, 0.75182 , 1.253815, 1.263951, 1.116363,
             0.767899, 0.782386])
    • constellation
      ()
      <U10
      'sentinel-2'
      array('sentinel-2', dtype='<U10')
    • s2:medium_proba_clouds_percentage
      (time)
      float64
      0.05143 0.001297 ... 2.271 0.00172
      array([5.143000e-02, 1.297000e-03, 7.322780e-01, 1.287753e+00,
             7.000000e-05, 5.689905e+00, 2.270966e+00, 1.720000e-03])
    • s2:granule_id
      (time)
      <U62
      'S2B_OPER_MSI_L2A_TL_2BPS_202206...
      array(['S2B_OPER_MSI_L2A_TL_2BPS_20220619T114329_A027604_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220624T143914_A036584_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220627T162810_A036627_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220714T175057_A036870_T33UXU_N04.00',
             'S2B_OPER_MSI_L2A_TL_2BPS_20220719T113943_A028033_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220803T135155_A037156_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220816T162557_A037342_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220826T162059_A037485_T33UXU_N04.00'],
            dtype='<U62')
    • eo:cloud_cover
      (time)
      float64
      7.491 0.002495 ... 4.8 0.003331
      array([7.491449e+00, 2.495000e-03, 1.067175e+00, 1.825375e+00,
             5.511000e-03, 8.775087e+00, 4.800238e+00, 3.331000e-03])
    • platform
      (time)
      <U11
      'sentinel-2b' ... 'sentinel-2a'
      array(['sentinel-2b', 'sentinel-2a', 'sentinel-2a', 'sentinel-2a',
             'sentinel-2b', 'sentinel-2a', 'sentinel-2a', 'sentinel-2a'],
            dtype='<U11')
    • s2:dark_features_percentage
      (time)
      float64
      0.002057 0.004107 ... 0.01486
      array([0.002057, 0.004107, 0.006966, 0.00361 , 0.004429, 0.003646,
             0.010289, 0.01486 ])
    • s2:product_type
      ()
      <U7
      'S2MSI2A'
      array('S2MSI2A', dtype='<U7')
    • s2:unclassified_percentage
      (time)
      float64
      0.1322 0.1796 ... 0.9699 0.2326
      array([0.132232, 0.179595, 0.340984, 0.291771, 0.195772, 2.000013,
             0.96991 , 0.232552])
    • s2:datatake_id
      (time)
      <U34
      'GS2B_20220619T100029_027604_N04...
      array(['GS2B_20220619T100029_027604_N04.00',
             'GS2A_20220624T100041_036584_N04.00',
             'GS2A_20220627T100611_036627_N04.00',
             'GS2A_20220714T100041_036870_N04.00',
             'GS2B_20220719T095559_028033_N04.00',
             'GS2A_20220803T100041_037156_N04.00',
             'GS2A_20220816T100611_037342_N04.00',
             'GS2A_20220826T100611_037485_N04.00'], dtype='<U34')
    • earthsearch:payload_id
      (time)
      <U74
      'roda-sentinel2/workflow-sentine...
      array(['roda-sentinel2/workflow-sentinel2-to-stac/58f82edc8c40c1d0d56d8a26269d02eb',
             'roda-sentinel2/workflow-sentinel2-to-stac/9b8a11349c8bf4f2437e596421530090',
             'roda-sentinel2/workflow-sentinel2-to-stac/fd889d2975690939ea2990c8b784fc31',
             'roda-sentinel2/workflow-sentinel2-to-stac/1cea63f7fa1542d8a1c7bcd0b774584d',
             'roda-sentinel2/workflow-sentinel2-to-stac/4f39107c8fe71ec8f29d674a811d6c21',
             'roda-sentinel2/workflow-sentinel2-to-stac/6245fb70f8c638a7681c672a7bf7a006',
             'roda-sentinel2/workflow-sentinel2-to-stac/b5b785b4fac74933d25c20aec8ce66bd',
             'roda-sentinel2/workflow-sentinel2-to-stac/bff15f451a9bb2107d01668bb557f526'],
            dtype='<U74')
    • mgrs:grid_square
      ()
      <U2
      'XU'
      array('XU', dtype='<U2')
    • s2:snow_ice_percentage
      ()
      int64
      0
      array(0)
    • s2:thin_cirrus_percentage
      (time)
      float64
      7.433 0.000713 ... 0.4116 0.001074
      array([7.43253e+00, 7.13000e-04, 5.00000e-05, 5.48640e-02, 5.43800e-03,
             1.80420e-02, 4.11558e-01, 1.07400e-03])
    • view:sun_azimuth
      (time)
      float64
      158.9 158.5 162.7 ... 165.2 166.8
      array([158.91324506, 158.50630661, 162.6663807 , 157.84964052,
             157.99361406, 159.43576449, 165.15376613, 166.81057205])
    • s2:cloud_shadow_percentage
      (time)
      object
      0 0.000989 1.168417 ... 1.743145 0
      array([0, 0.000989, 1.168417, 2.347726, 0, 4.482971, 1.743145, 0],
            dtype=object)
    • mgrs:latitude_band
      ()
      <U1
      'U'
      array('U', dtype='<U1')
    • updated
      (time)
      <U24
      '2022-11-06T13:16:38.195Z' ... '...
      array(['2022-11-06T13:16:38.195Z', '2022-11-06T12:52:50.337Z',
             '2022-11-06T12:55:07.931Z', '2022-11-06T12:54:05.312Z',
             '2022-11-06T13:14:37.621Z', '2022-11-06T13:12:58.202Z',
             '2022-11-06T12:53:48.090Z', '2022-11-06T13:14:57.270Z'],
            dtype='<U24')
    • processing:software
      ()
      object
      {'sentinel2-to-stac': '0.1.0'}
      array({'sentinel2-to-stac': '0.1.0'}, dtype=object)
    • instruments
      ()
      <U3
      'msi'
      array('msi', dtype='<U3')
    • s2:product_uri
      (time)
      <U65
      'S2B_MSIL2A_20220619T100029_N040...
      array(['S2B_MSIL2A_20220619T100029_N0400_R122_T33UXU_20220619T114329.SAFE',
             'S2A_MSIL2A_20220624T100041_N0400_R122_T33UXU_20220624T143914.SAFE',
             'S2A_MSIL2A_20220627T100611_N0400_R022_T33UXU_20220627T162810.SAFE',
             'S2A_MSIL2A_20220714T100041_N0400_R122_T33UXU_20220714T175057.SAFE',
             'S2B_MSIL2A_20220719T095559_N0400_R122_T33UXU_20220719T113943.SAFE',
             'S2A_MSIL2A_20220803T100041_N0400_R122_T33UXU_20220803T135155.SAFE',
             'S2A_MSIL2A_20220816T100611_N0400_R022_T33UXU_20220816T162557.SAFE',
             'S2A_MSIL2A_20220826T100611_N0400_R022_T33UXU_20220826T162059.SAFE'],
            dtype='<U65')
    • view:sun_elevation
      (time)
      float64
      59.41 59.34 59.71 ... 50.17 46.97
      array([59.4067386 , 59.33648111, 59.7142557 , 57.43426893, 56.58894221,
             53.33325433, 50.17160714, 46.96899755])
    • s2:generation_time
      (time)
      <U27
      '2022-06-19T11:43:29.000000Z' .....
      array(['2022-06-19T11:43:29.000000Z', '2022-06-24T14:39:14.000000Z',
             '2022-06-27T16:28:10.000000Z', '2022-07-14T17:50:57.000000Z',
             '2022-07-19T11:39:43.000000Z', '2022-08-03T13:51:55.000000Z',
             '2022-08-16T16:25:57.000000Z', '2022-08-26T16:20:59.000000Z'],
            dtype='<U27')
    • s2:reflectance_conversion_factor
      (time)
      float64
      0.9691 0.9683 ... 0.9741 0.9779
      array([0.96912679, 0.96833888, 0.96797547, 0.96750684, 0.96788495,
             0.97039583, 0.97414715, 0.9779224 ])
    • s2:sequence
      ()
      <U1
      '0'
      array('0', dtype='<U1')
    • mgrs:utm_zone
      ()
      int64
      33
      array(33)
    • grid:code
      ()
      <U10
      'MGRS-33UXU'
      array('MGRS-33UXU', dtype='<U10')
    • s2:processing_baseline
      ()
      <U5
      '04.00'
      array('04.00', dtype='<U5')
    • created
      (time)
      <U24
      '2022-11-06T13:16:38.195Z' ... '...
      array(['2022-11-06T13:16:38.195Z', '2022-11-06T12:52:50.337Z',
             '2022-11-06T12:55:07.931Z', '2022-11-06T12:54:05.312Z',
             '2022-11-06T13:14:37.621Z', '2022-11-06T13:12:58.202Z',
             '2022-11-06T12:53:48.090Z', '2022-11-06T13:14:57.270Z'],
            dtype='<U24')
    • raster:bands
      (band)
      object
      [{'nodata': 0, 'data_type': 'uin...
      array([list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
             list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}])],
            dtype=object)
    • title
      (band)
      <U31
      'Red (band 4) - 10m' ... 'Blue (...
      array(['Red (band 4) - 10m', 'Green (band 3) - 10m',
             'Blue (band 2) - 10m'], dtype='<U31')
    • gsd
      (band)
      object
      10 10 10
      array([10, 10, 10], dtype=object)
    • common_name
      (band)
      object
      'red' 'green' 'blue'
      array(['red', 'green', 'blue'], dtype=object)
    • center_wavelength
      (band)
      object
      0.665 0.56 0.49
      array([0.665, 0.56, 0.49], dtype=object)
    • full_width_half_max
      (band)
      object
      0.038 0.045 0.098
      array([0.038, 0.045, 0.098], dtype=object)
    • epsg
      ()
      int64
      32633
      array(32633)
    • time
      PandasIndex
      PandasIndex(DatetimeIndex(['2022-06-19 10:06:08.087000', '2022-06-24 10:06:16.177000',
                     '2022-06-27 10:16:12.822000', '2022-07-14 10:06:16.331000',
                     '2022-07-19 10:06:08.645000', '2022-08-03 10:06:14.409000',
                     '2022-08-16 10:16:12.609000', '2022-08-26 10:16:12.680000'],
                    dtype='datetime64[ns]', name='time', freq=None))
    • band
      PandasIndex
      PandasIndex(Index(['red', 'green', 'blue'], dtype='object', name='band'))
    • x
      PandasIndex
      PandasIndex(Index([632780.0, 632790.0, 632800.0, 632810.0, 632820.0, 632830.0, 632840.0,
             632850.0, 632860.0, 632870.0,
             ...
             645070.0, 645080.0, 645090.0, 645100.0, 645110.0, 645120.0, 645130.0,
             645140.0, 645150.0, 645160.0],
            dtype='float64', name='x', length=1239))
    • y
      PandasIndex
      PandasIndex(Index([5808810.0, 5808800.0, 5808790.0, 5808780.0, 5808770.0, 5808760.0,
             5808750.0, 5808740.0, 5808730.0, 5808720.0,
             ...
             5801430.0, 5801420.0, 5801410.0, 5801400.0, 5801390.0, 5801380.0,
             5801370.0, 5801360.0, 5801350.0, 5801340.0],
            dtype='float64', name='y', length=748))
  • spec :
    RasterSpec(epsg=32633, bounds=(632780, 5801330, 645170, 5808810), resolutions_xy=(10, 10))
    crs :
    epsg:32633
    transform :
    | 10.00, 0.00, 632780.00| | 0.00,-10.00, 5808810.00| | 0.00, 0.00, 1.00|
    resolution :
    10

For a quick view, we can generate a GIF of the Sentinel-2 scenes we have available.

In [57]:
gif_crops = geogif.dgif(rgb).compute()
/opt/conda/lib/python3.11/site-packages/geogif/gif.py:190: RuntimeWarning: invalid value encountered in cast
  u8 = (data * 255).astype("uint8")
In [58]:
gif_crops
Out[58]:
No description has been provided for this image

We can work on derived calculation, for example, we can compute the NDVI per scene

In [59]:
nir, red = cube.sel(band="nir"), cube.sel(band="red")
ndvi = (nir - red) / (nir + red)
In [60]:
ndvi
Out[60]:
<xarray.DataArray 'stackstac-34b7fdf5d830fa45909152427d7b3f8a' (time: 8,
                                                                y: 748, x: 1239)>
dask.array<truediv, shape=(8, 748, 1239), dtype=float64, chunksize=(1, 748, 1024), chunktype=numpy.ndarray>
Coordinates: (12/47)
  * time                                     (time) datetime64[ns] 2022-06-19...
    id                                       (time) <U24 'S2B_33UXU_20220619_...
  * x                                        (x) float64 6.328e+05 ... 6.452e+05
  * y                                        (y) float64 5.809e+06 ... 5.801e+06
    s2:nodata_pixel_percentage               (time) object 0 0 ... 60.458738
    s2:not_vegetated_percentage              (time) float64 10.43 11.0 ... 34.91
    ...                                       ...
    grid:code                                <U10 'MGRS-33UXU'
    s2:processing_baseline                   <U5 '04.00'
    created                                  (time) <U24 '2022-11-06T13:16:38...
    raster:bands                             object [{'nodata': 0, 'data_type...
    gsd                                      object 10
    epsg                                     int64 32633
xarray.DataArray
'stackstac-34b7fdf5d830fa45909152427d7b3f8a'
  • time: 8
  • y: 748
  • x: 1239
  • dask.array<chunksize=(1, 748, 1024), meta=np.ndarray>
    Array Chunk
    Bytes 56.57 MiB 5.84 MiB
    Shape (8, 748, 1239) (1, 748, 1024)
    Dask graph 16 chunks in 8 graph layers
    Data type float64 numpy.ndarray
    1239 748 8
    • time
      (time)
      datetime64[ns]
      2022-06-19T10:06:08.087000 ... 2...
      array(['2022-06-19T10:06:08.087000000', '2022-06-24T10:06:16.177000000',
             '2022-06-27T10:16:12.822000000', '2022-07-14T10:06:16.331000000',
             '2022-07-19T10:06:08.645000000', '2022-08-03T10:06:14.409000000',
             '2022-08-16T10:16:12.609000000', '2022-08-26T10:16:12.680000000'],
            dtype='datetime64[ns]')
    • id
      (time)
      <U24
      'S2B_33UXU_20220619_0_L2A' ... '...
      array(['S2B_33UXU_20220619_0_L2A', 'S2A_33UXU_20220624_0_L2A',
             'S2A_33UXU_20220627_0_L2A', 'S2A_33UXU_20220714_0_L2A',
             'S2B_33UXU_20220719_0_L2A', 'S2A_33UXU_20220803_0_L2A',
             'S2A_33UXU_20220816_0_L2A', 'S2A_33UXU_20220826_0_L2A'],
            dtype='<U24')
    • x
      (x)
      float64
      6.328e+05 6.328e+05 ... 6.452e+05
      array([632780., 632790., 632800., ..., 645140., 645150., 645160.])
    • y
      (y)
      float64
      5.809e+06 5.809e+06 ... 5.801e+06
      array([5808810., 5808800., 5808790., ..., 5801360., 5801350., 5801340.])
    • s2:nodata_pixel_percentage
      (time)
      object
      0 0 ... 60.335821 60.458738
      array([0, 0, 60.372794, 0, 3e-06, 3e-06, 60.335821, 60.458738],
            dtype=object)
    • s2:not_vegetated_percentage
      (time)
      float64
      10.43 11.0 12.07 ... 35.87 34.91
      array([10.429534, 11.000518, 12.070826, 30.188122, 34.062394, 34.022531,
             35.867879, 34.906355])
    • earthsearch:boa_offset_applied
      ()
      bool
      True
      array(True)
    • proj:epsg
      ()
      int64
      32633
      array(32633)
    • s2:saturated_defective_pixel_percentage
      ()
      int64
      0
      array(0)
    • s2:degraded_msi_data_percentage
      (time)
      object
      0 0 0.0045 0 0 0 0.0045 0.0044
      array([0, 0, 0.0045, 0, 0, 0, 0.0045, 0.0044], dtype=object)
    • s2:high_proba_clouds_percentage
      (time)
      float64
      0.007488 0.000484 ... 0.000537
      array([7.488000e-03, 4.840000e-04, 3.348470e-01, 4.827590e-01,
             3.000000e-06, 3.067140e+00, 2.117714e+00, 5.370000e-04])
    • earthsearch:s3_path
      (time)
      <U79
      's3://sentinel-cogs/sentinel-s2-...
      array(['s3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/6/S2B_33UXU_20220619_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/6/S2A_33UXU_20220624_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/6/S2A_33UXU_20220627_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/7/S2A_33UXU_20220714_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/7/S2B_33UXU_20220719_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/8/S2A_33UXU_20220803_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/8/S2A_33UXU_20220816_0_L2A',
             's3://sentinel-cogs/sentinel-s2-l2a-cogs/33/U/XU/2022/8/S2A_33UXU_20220826_0_L2A'],
            dtype='<U79')
    • s2:datastrip_id
      (time)
      <U64
      'S2B_OPER_MSI_L2A_DS_2BPS_202206...
      array(['S2B_OPER_MSI_L2A_DS_2BPS_20220619T114329_S20220619T100031_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220624T143914_S20220624T100039_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220627T162810_S20220627T100933_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220714T175057_S20220714T100046_N04.00',
             'S2B_OPER_MSI_L2A_DS_2BPS_20220719T113943_S20220719T095747_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220803T135155_S20220803T100037_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220816T162557_S20220816T100922_N04.00',
             'S2A_OPER_MSI_L2A_DS_ATOS_20220826T162059_S20220826T100933_N04.00'],
            dtype='<U64')
    • s2:datatake_type
      ()
      <U8
      'INS-NOBS'
      array('INS-NOBS', dtype='<U8')
    • s2:vegetation_percentage
      (time)
      float64
      80.88 87.55 84.59 ... 55.84 64.06
      array([80.8779  , 87.545991, 84.593809, 64.089584, 64.467937, 49.599385,
             55.840641, 64.060515])
    • s2:water_percentage
      (time)
      float64
      1.067 1.266 ... 0.7679 0.7824
      array([1.066825, 1.266303, 0.75182 , 1.253815, 1.263951, 1.116363,
             0.767899, 0.782386])
    • constellation
      ()
      <U10
      'sentinel-2'
      array('sentinel-2', dtype='<U10')
    • s2:medium_proba_clouds_percentage
      (time)
      float64
      0.05143 0.001297 ... 2.271 0.00172
      array([5.143000e-02, 1.297000e-03, 7.322780e-01, 1.287753e+00,
             7.000000e-05, 5.689905e+00, 2.270966e+00, 1.720000e-03])
    • s2:granule_id
      (time)
      <U62
      'S2B_OPER_MSI_L2A_TL_2BPS_202206...
      array(['S2B_OPER_MSI_L2A_TL_2BPS_20220619T114329_A027604_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220624T143914_A036584_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220627T162810_A036627_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220714T175057_A036870_T33UXU_N04.00',
             'S2B_OPER_MSI_L2A_TL_2BPS_20220719T113943_A028033_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220803T135155_A037156_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220816T162557_A037342_T33UXU_N04.00',
             'S2A_OPER_MSI_L2A_TL_ATOS_20220826T162059_A037485_T33UXU_N04.00'],
            dtype='<U62')
    • eo:cloud_cover
      (time)
      float64
      7.491 0.002495 ... 4.8 0.003331
      array([7.491449e+00, 2.495000e-03, 1.067175e+00, 1.825375e+00,
             5.511000e-03, 8.775087e+00, 4.800238e+00, 3.331000e-03])
    • platform
      (time)
      <U11
      'sentinel-2b' ... 'sentinel-2a'
      array(['sentinel-2b', 'sentinel-2a', 'sentinel-2a', 'sentinel-2a',
             'sentinel-2b', 'sentinel-2a', 'sentinel-2a', 'sentinel-2a'],
            dtype='<U11')
    • s2:dark_features_percentage
      (time)
      float64
      0.002057 0.004107 ... 0.01486
      array([0.002057, 0.004107, 0.006966, 0.00361 , 0.004429, 0.003646,
             0.010289, 0.01486 ])
    • s2:product_type
      ()
      <U7
      'S2MSI2A'
      array('S2MSI2A', dtype='<U7')
    • s2:unclassified_percentage
      (time)
      float64
      0.1322 0.1796 ... 0.9699 0.2326
      array([0.132232, 0.179595, 0.340984, 0.291771, 0.195772, 2.000013,
             0.96991 , 0.232552])
    • s2:datatake_id
      (time)
      <U34
      'GS2B_20220619T100029_027604_N04...
      array(['GS2B_20220619T100029_027604_N04.00',
             'GS2A_20220624T100041_036584_N04.00',
             'GS2A_20220627T100611_036627_N04.00',
             'GS2A_20220714T100041_036870_N04.00',
             'GS2B_20220719T095559_028033_N04.00',
             'GS2A_20220803T100041_037156_N04.00',
             'GS2A_20220816T100611_037342_N04.00',
             'GS2A_20220826T100611_037485_N04.00'], dtype='<U34')
    • earthsearch:payload_id
      (time)
      <U74
      'roda-sentinel2/workflow-sentine...
      array(['roda-sentinel2/workflow-sentinel2-to-stac/58f82edc8c40c1d0d56d8a26269d02eb',
             'roda-sentinel2/workflow-sentinel2-to-stac/9b8a11349c8bf4f2437e596421530090',
             'roda-sentinel2/workflow-sentinel2-to-stac/fd889d2975690939ea2990c8b784fc31',
             'roda-sentinel2/workflow-sentinel2-to-stac/1cea63f7fa1542d8a1c7bcd0b774584d',
             'roda-sentinel2/workflow-sentinel2-to-stac/4f39107c8fe71ec8f29d674a811d6c21',
             'roda-sentinel2/workflow-sentinel2-to-stac/6245fb70f8c638a7681c672a7bf7a006',
             'roda-sentinel2/workflow-sentinel2-to-stac/b5b785b4fac74933d25c20aec8ce66bd',
             'roda-sentinel2/workflow-sentinel2-to-stac/bff15f451a9bb2107d01668bb557f526'],
            dtype='<U74')
    • mgrs:grid_square
      ()
      <U2
      'XU'
      array('XU', dtype='<U2')
    • s2:snow_ice_percentage
      ()
      int64
      0
      array(0)
    • s2:thin_cirrus_percentage
      (time)
      float64
      7.433 0.000713 ... 0.4116 0.001074
      array([7.43253e+00, 7.13000e-04, 5.00000e-05, 5.48640e-02, 5.43800e-03,
             1.80420e-02, 4.11558e-01, 1.07400e-03])
    • view:sun_azimuth
      (time)
      float64
      158.9 158.5 162.7 ... 165.2 166.8
      array([158.91324506, 158.50630661, 162.6663807 , 157.84964052,
             157.99361406, 159.43576449, 165.15376613, 166.81057205])
    • s2:cloud_shadow_percentage
      (time)
      object
      0 0.000989 1.168417 ... 1.743145 0
      array([0, 0.000989, 1.168417, 2.347726, 0, 4.482971, 1.743145, 0],
            dtype=object)
    • mgrs:latitude_band
      ()
      <U1
      'U'
      array('U', dtype='<U1')
    • updated
      (time)
      <U24
      '2022-11-06T13:16:38.195Z' ... '...
      array(['2022-11-06T13:16:38.195Z', '2022-11-06T12:52:50.337Z',
             '2022-11-06T12:55:07.931Z', '2022-11-06T12:54:05.312Z',
             '2022-11-06T13:14:37.621Z', '2022-11-06T13:12:58.202Z',
             '2022-11-06T12:53:48.090Z', '2022-11-06T13:14:57.270Z'],
            dtype='<U24')
    • processing:software
      ()
      object
      {'sentinel2-to-stac': '0.1.0'}
      array({'sentinel2-to-stac': '0.1.0'}, dtype=object)
    • instruments
      ()
      <U3
      'msi'
      array('msi', dtype='<U3')
    • s2:product_uri
      (time)
      <U65
      'S2B_MSIL2A_20220619T100029_N040...
      array(['S2B_MSIL2A_20220619T100029_N0400_R122_T33UXU_20220619T114329.SAFE',
             'S2A_MSIL2A_20220624T100041_N0400_R122_T33UXU_20220624T143914.SAFE',
             'S2A_MSIL2A_20220627T100611_N0400_R022_T33UXU_20220627T162810.SAFE',
             'S2A_MSIL2A_20220714T100041_N0400_R122_T33UXU_20220714T175057.SAFE',
             'S2B_MSIL2A_20220719T095559_N0400_R122_T33UXU_20220719T113943.SAFE',
             'S2A_MSIL2A_20220803T100041_N0400_R122_T33UXU_20220803T135155.SAFE',
             'S2A_MSIL2A_20220816T100611_N0400_R022_T33UXU_20220816T162557.SAFE',
             'S2A_MSIL2A_20220826T100611_N0400_R022_T33UXU_20220826T162059.SAFE'],
            dtype='<U65')
    • view:sun_elevation
      (time)
      float64
      59.41 59.34 59.71 ... 50.17 46.97
      array([59.4067386 , 59.33648111, 59.7142557 , 57.43426893, 56.58894221,
             53.33325433, 50.17160714, 46.96899755])
    • s2:generation_time
      (time)
      <U27
      '2022-06-19T11:43:29.000000Z' .....
      array(['2022-06-19T11:43:29.000000Z', '2022-06-24T14:39:14.000000Z',
             '2022-06-27T16:28:10.000000Z', '2022-07-14T17:50:57.000000Z',
             '2022-07-19T11:39:43.000000Z', '2022-08-03T13:51:55.000000Z',
             '2022-08-16T16:25:57.000000Z', '2022-08-26T16:20:59.000000Z'],
            dtype='<U27')
    • s2:reflectance_conversion_factor
      (time)
      float64
      0.9691 0.9683 ... 0.9741 0.9779
      array([0.96912679, 0.96833888, 0.96797547, 0.96750684, 0.96788495,
             0.97039583, 0.97414715, 0.9779224 ])
    • s2:sequence
      ()
      <U1
      '0'
      array('0', dtype='<U1')
    • mgrs:utm_zone
      ()
      int64
      33
      array(33)
    • grid:code
      ()
      <U10
      'MGRS-33UXU'
      array('MGRS-33UXU', dtype='<U10')
    • s2:processing_baseline
      ()
      <U5
      '04.00'
      array('04.00', dtype='<U5')
    • created
      (time)
      <U24
      '2022-11-06T13:16:38.195Z' ... '...
      array(['2022-11-06T13:16:38.195Z', '2022-11-06T12:52:50.337Z',
             '2022-11-06T12:55:07.931Z', '2022-11-06T12:54:05.312Z',
             '2022-11-06T13:14:37.621Z', '2022-11-06T13:12:58.202Z',
             '2022-11-06T12:53:48.090Z', '2022-11-06T13:14:57.270Z'],
            dtype='<U24')
    • raster:bands
      ()
      object
      [{'nodata': 0, 'data_type': 'uin...
      array(list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
            dtype=object)
    • gsd
      ()
      object
      10
      array(10, dtype=object)
    • epsg
      ()
      int64
      32633
      array(32633)
    • time
      PandasIndex
      PandasIndex(DatetimeIndex(['2022-06-19 10:06:08.087000', '2022-06-24 10:06:16.177000',
                     '2022-06-27 10:16:12.822000', '2022-07-14 10:06:16.331000',
                     '2022-07-19 10:06:08.645000', '2022-08-03 10:06:14.409000',
                     '2022-08-16 10:16:12.609000', '2022-08-26 10:16:12.680000'],
                    dtype='datetime64[ns]', name='time', freq=None))
    • x
      PandasIndex
      PandasIndex(Index([632780.0, 632790.0, 632800.0, 632810.0, 632820.0, 632830.0, 632840.0,
             632850.0, 632860.0, 632870.0,
             ...
             645070.0, 645080.0, 645090.0, 645100.0, 645110.0, 645120.0, 645130.0,
             645140.0, 645150.0, 645160.0],
            dtype='float64', name='x', length=1239))
    • y
      PandasIndex
      PandasIndex(Index([5808810.0, 5808800.0, 5808790.0, 5808780.0, 5808770.0, 5808760.0,
             5808750.0, 5808740.0, 5808730.0, 5808720.0,
             ...
             5801430.0, 5801420.0, 5801410.0, 5801400.0, 5801390.0, 5801380.0,
             5801370.0, 5801360.0, 5801350.0, 5801340.0],
            dtype='float64', name='y', length=748))

Let's create a composite with the maximum NDVI value for the whole collection over time.

In [61]:
ndvi_comp = ndvi.max("time")
In [62]:
ndvi_comp
Out[62]:
<xarray.DataArray 'stackstac-34b7fdf5d830fa45909152427d7b3f8a' (y: 748, x: 1239)>
dask.array<_nanmax_skip-aggregate, shape=(748, 1239), dtype=float64, chunksize=(748, 1024), chunktype=numpy.ndarray>
Coordinates: (12/20)
  * x                                        (x) float64 6.328e+05 ... 6.452e+05
  * y                                        (y) float64 5.809e+06 ... 5.801e+06
    earthsearch:boa_offset_applied           bool True
    proj:epsg                                int64 32633
    s2:saturated_defective_pixel_percentage  int64 0
    s2:datatake_type                         <U8 'INS-NOBS'
    ...                                       ...
    mgrs:utm_zone                            int64 33
    grid:code                                <U10 'MGRS-33UXU'
    s2:processing_baseline                   <U5 '04.00'
    raster:bands                             object [{'nodata': 0, 'data_type...
    gsd                                      object 10
    epsg                                     int64 32633
xarray.DataArray
'stackstac-34b7fdf5d830fa45909152427d7b3f8a'
  • y: 748
  • x: 1239
  • dask.array<chunksize=(748, 1024), meta=np.ndarray>
    Array Chunk
    Bytes 7.07 MiB 5.84 MiB
    Shape (748, 1239) (748, 1024)
    Dask graph 2 chunks in 11 graph layers
    Data type float64 numpy.ndarray
    1239 748
    • x
      (x)
      float64
      6.328e+05 6.328e+05 ... 6.452e+05
      array([632780., 632790., 632800., ..., 645140., 645150., 645160.])
    • y
      (y)
      float64
      5.809e+06 5.809e+06 ... 5.801e+06
      array([5808810., 5808800., 5808790., ..., 5801360., 5801350., 5801340.])
    • earthsearch:boa_offset_applied
      ()
      bool
      True
      array(True)
    • proj:epsg
      ()
      int64
      32633
      array(32633)
    • s2:saturated_defective_pixel_percentage
      ()
      int64
      0
      array(0)
    • s2:datatake_type
      ()
      <U8
      'INS-NOBS'
      array('INS-NOBS', dtype='<U8')
    • constellation
      ()
      <U10
      'sentinel-2'
      array('sentinel-2', dtype='<U10')
    • s2:product_type
      ()
      <U7
      'S2MSI2A'
      array('S2MSI2A', dtype='<U7')
    • mgrs:grid_square
      ()
      <U2
      'XU'
      array('XU', dtype='<U2')
    • s2:snow_ice_percentage
      ()
      int64
      0
      array(0)
    • mgrs:latitude_band
      ()
      <U1
      'U'
      array('U', dtype='<U1')
    • processing:software
      ()
      object
      {'sentinel2-to-stac': '0.1.0'}
      array({'sentinel2-to-stac': '0.1.0'}, dtype=object)
    • instruments
      ()
      <U3
      'msi'
      array('msi', dtype='<U3')
    • s2:sequence
      ()
      <U1
      '0'
      array('0', dtype='<U1')
    • mgrs:utm_zone
      ()
      int64
      33
      array(33)
    • grid:code
      ()
      <U10
      'MGRS-33UXU'
      array('MGRS-33UXU', dtype='<U10')
    • s2:processing_baseline
      ()
      <U5
      '04.00'
      array('04.00', dtype='<U5')
    • raster:bands
      ()
      object
      [{'nodata': 0, 'data_type': 'uin...
      array(list([{'nodata': 0, 'data_type': 'uint16', 'bits_per_sample': 15, 'spatial_resolution': 10, 'scale': 0.0001, 'offset': -0.1}]),
            dtype=object)
    • gsd
      ()
      object
      10
      array(10, dtype=object)
    • epsg
      ()
      int64
      32633
      array(32633)
    • x
      PandasIndex
      PandasIndex(Index([632780.0, 632790.0, 632800.0, 632810.0, 632820.0, 632830.0, 632840.0,
             632850.0, 632860.0, 632870.0,
             ...
             645070.0, 645080.0, 645090.0, 645100.0, 645110.0, 645120.0, 645130.0,
             645140.0, 645150.0, 645160.0],
            dtype='float64', name='x', length=1239))
    • y
      PandasIndex
      PandasIndex(Index([5808810.0, 5808800.0, 5808790.0, 5808780.0, 5808770.0, 5808760.0,
             5808750.0, 5808740.0, 5808730.0, 5808720.0,
             ...
             5801430.0, 5801420.0, 5801410.0, 5801400.0, 5801390.0, 5801380.0,
             5801370.0, 5801360.0, 5801350.0, 5801340.0],
            dtype='float64', name='y', length=748))
In [63]:
ndvi_comp = ndvi_comp.compute()
In [64]:
ndvi_comp.plot(vmin=0, vmax=0.8, cmap="YlGn")
Out[64]:
<matplotlib.collections.QuadMesh at 0x7f8e50bb8f10>
No description has been provided for this image

And finally, let's compute the NDVI anomaly, i.e., how much does each pixel from the composite deviates from the mean of the whole collection.

In [65]:
anomaly = ndvi_comp - ndvi.mean()
In [66]:
anomaly = anomaly.compute()
In [67]:
anomaly.plot(cmap="PiYG")
Out[67]:
<matplotlib.collections.QuadMesh at 0x7f8e50b10fd0>
No description has been provided for this image

Downloading the data¶

There might be at some point the need to download the scenes that you just queried. To do so you can use the os and urllib modules that are part of the python standard library as the code snippet below shows. This will download all of the items from your search, so make sure you apply enough filtering so that you don't download data that you don't need.

download_path = "path/to/dir"

for item in items:
    download_path = os.path.join(item.collection_id, item.id)
    if not os.path.exists(download_path):
        os.makedirs(download_path, exist_ok=True)
    for name, asset in item.assets.items():
        urllib.request.urlretrieve(asset.href, 
                                   os.path.join(download_path, 
                                   os.path.basename(asset.href)))

Exercises¶

  1. Adjust your STAC query accordingly and create a new data cube grouped by season. Think about data sizes and play with an AOI of your choice.
  2. Compute a time series of NDVI values for one crop parcel of your choice. Hint: you can easily create a geojson polygon with https://geojson.io/. Take the temporal grouping of your choice, but what would make sense to compare such vegetation values?

More resources¶

This material was based on the Carpentries introduction to Geospatial RAster and Vector data in Python and the EGU23 short course on the same topic by Francesco Nattino and Ou Ku.