STAC#
Let’s use EOReader to create SpatioTemporal Asset Catalog (STAC) items.
Note: This is experimental for now, use it at your own risk !
Warning:
You will need to install pystac[validation]
,
folium
and eodag
(version != 2.6.0) to run this notebook
Imports#
# Imports
import os
import pystac
import geopandas as gpd
from tempfile import TemporaryDirectory
from shapely.geometry import mapping
from eodag import setup_logging
from eodag.api.core import EODataAccessGateway
from eoreader.reader import Reader
Create logger#
# Create logger
import logging
from sertit import logs
logger = logging.getLogger("eoreader")
logs.init_logger(logger)
Linking some data#
Let’s take 3 products covering approximately the same area (over DAX city in France):
One Landsat-8 OLI-TIRS collection 2
One Landsat-5 TM collection 2
One Sentinel-2 L1C
prod_folder = os.path.join("/home", "data", "DATA", "PRODS")
paths = [
# Landsat-8 OLI-TIRS collection 2
os.path.join(prod_folder, "LANDSATS_COL2", "LC08_L1TP_200030_20201220_20210310_02_T1.tar"),
# Landsat-5 TM collection 2
os.path.join(prod_folder, "LANDSATS_COL2", "LT05_L1TP_200030_20111110_20200820_02_T1.tar"),
# Sentinel-2 L2A
os.path.join(prod_folder, "S2", "PB 02.07+", "S2A_MSIL1C_20191215T110441_N0208_R094_T30TXP_20191215T114155.SAFE"),
]
Create STAC catalog#
Create a STAC catalog and add 3 STAC items to it.
# Create the reader
reader = Reader()
# Work in a temporary directory
tmp = TemporaryDirectory()
# Create STAC catalog
catalog_path = os.path.join(tmp.name, "catalog.json")
catalog = pystac.Catalog(
id='SERTIT_101',
description="SERTIT's Catalog",
title='SERTIT Catalog',
href=catalog_path
)
# Add all the products into the STAC catalog
for path in paths:
logger.info(f"*** {os.path.basename(path)} ***")
# Open the product
prod = reader.open(path, remove_tmp=True)
# Get item
item = prod.stac.create_item()
# Add item to catalogue
catalog.add_item(item)
2023-05-31 13:19:02,675 - [INFO] - *** LC08_L1TP_200030_20201220_20210310_02_T1.tar ***
2023-05-31 13:19:05,884 - [WARNING] - No quicklook found in 20201220T104856_L8_200030_OLI_TIRS
2023-05-31 13:19:07,229 - [INFO] - *** LT05_L1TP_200030_20111110_20200820_02_T1.tar ***
2023-05-31 13:19:08,898 - [INFO] - *** S2A_MSIL1C_20191215T110441_N0208_R094_T30TXP_20191215T114155.SAFE ***
# Save catalog
catalog.describe()
catalog.normalize_and_save(tmp.name, catalog_type=pystac.CatalogType.SELF_CONTAINED)
* <Catalog id=SERTIT_101>
* <Item id=20201220T104856_L8_200030_OLI_TIRS>
* <Item id=20111110T103612_L5_200030_TM>
* <Item id=20191215T110441_S2_T30TXP_L1C_114155>
list(catalog.get_items())[0]
Item: 20201220T104856_L8_200030_OLI_TIRS
id: 20201220T104856_L8_200030_OLI_TIRS |
bbox: [-2.744857724803896, 42.09665285173287, 0.14785265624107427, 44.2467651307631] |
tilename: 200030 |
eo:cloud_cover: 16.36 |
proj:epsg: 32630 |
proj:wkt2: PROJCS["WGS 84 / UTM zone 30N",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-3],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","32630"]] |
proj:geometry: {'type': 'Polygon', 'coordinates': (((704535.0, 4665915.0), (703755.0, 4666095.0), (690465.0, 4669185.0), (630855.0, 4683045.0), (526215.0, 4707375.0), (523635.0, 4707975.0), (523125.0, 4708095.0), (523005.0, 4708125.0), (522945.0, 4708155.0), (522945.0, 4708275.0), (522975.0, 4708425.0), (523185.0, 4709355.0), (566355.0, 4898205.0), (566445.0, 4898595.0), (566475.0, 4898715.0), (566505.0, 4898715.0), (567045.0, 4898595.0), (567975.0, 4898385.0), (573405.0, 4897155.0), (586515.0, 4894185.0), (697485.0, 4869045.0), (748335.0, 4857525.0), (748575.0, 4857465.0), (748575.0, 4857375.0), (748455.0, 4856835.0), (747285.0, 4851675.0), (747135.0, 4851015.0), (745305.0, 4842975.0), (744675.0, 4840215.0), (742125.0, 4829055.0), (741315.0, 4825515.0), (739995.0, 4819755.0), (738825.0, 4814655.0), (729945.0, 4775955.0), (705225.0, 4668735.0), (704685.0, 4666395.0), (704565.0, 4665915.0), (704535.0, 4665915.0)),)} |
proj:bbox: [521085.0, 4664985.0, 751515.0, 4899315.0] |
proj:centroid: {'lat': 43.183607660455536, 'lon': -1.3295876133318103} |
proj:shape: [7811, 7681] |
proj:transform: [30.0, 0.0, 521085.0, 0.0, -30.0, 4899315.0, 0.0, 0.0, 1.0] |
view:sun_azimuth: 161.76832577 |
view:sun_elevation: 68.76909132 |
title: 20201220T104856_L8_200030_OLI_TIRS |
created: 2023-05-31T13:19:05.952616Z |
updated: 2023-05-31T13:19:05.952625Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 30.0 |
datetime: 2020-12-20T10:48:56Z |
STAC Extensions
https://stac-extensions.github.io/eo/v1.0.0/schema.json |
https://stac-extensions.github.io/projection/v1.1.0/schema.json |
https://stac-extensions.github.io/view/v1.0.0/schema.json |
Assets
Asset: Coastal aerosol
href: tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B1.TIF |
type: image/tiff; application=geotiff |
title: Coastal aerosol |
description: Coastal and aerosol studies |
roles: ['reflectance'] |
owner: 20201220T104856_L8_200030_OLI_TIRS |
eoreader_name: COASTAL_AEROSOL |
eo:bands: [{'name': 'Coastal aerosol', 'common_name': 'coastal', 'description': 'Coastal and aerosol studies', 'center_wavelength': 0.44, 'full_width_half_max': 0.02}] |
created: 2023-05-31T13:19:05.951844Z |
updated: 2023-05-31T13:19:05.951871Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 30 |
Asset: Blue
href: tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B2.TIF |
type: image/tiff; application=geotiff |
title: Blue |
description: Bathymetric mapping, distinguishing soil from vegetation and deciduous from coniferous vegetation |
roles: ['reflectance'] |
owner: 20201220T104856_L8_200030_OLI_TIRS |
eoreader_name: BLUE |
eo:bands: [{'name': 'Blue', 'common_name': 'blue', 'description': 'Bathymetric mapping, distinguishing soil from vegetation and deciduous from coniferous vegetation', 'center_wavelength': 0.48, 'full_width_half_max': 0.06}] |
created: 2023-05-31T13:19:05.951933Z |
updated: 2023-05-31T13:19:05.951941Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 30 |
Asset: Green
href: tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B3.TIF |
type: image/tiff; application=geotiff |
title: Green |
description: Emphasizes peak vegetation, which is useful for assessing plant vigor |
roles: ['reflectance'] |
owner: 20201220T104856_L8_200030_OLI_TIRS |
eoreader_name: GREEN |
eo:bands: [{'name': 'Green', 'common_name': 'green', 'description': 'Emphasizes peak vegetation, which is useful for assessing plant vigor', 'center_wavelength': 0.56, 'full_width_half_max': 0.06}] |
created: 2023-05-31T13:19:05.951987Z |
updated: 2023-05-31T13:19:05.951994Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 30 |
Asset: Red
href: tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B4.TIF |
type: image/tiff; application=geotiff |
title: Red |
description: Discriminates vegetation slopes |
roles: ['reflectance'] |
owner: 20201220T104856_L8_200030_OLI_TIRS |
eoreader_name: RED |
eo:bands: [{'name': 'Red', 'common_name': 'red', 'description': 'Discriminates vegetation slopes', 'center_wavelength': 0.655, 'full_width_half_max': 0.03}] |
created: 2023-05-31T13:19:05.952035Z |
updated: 2023-05-31T13:19:05.952042Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 30 |
Asset: Near Infrared (NIR)
href: tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B5.TIF |
type: image/tiff; application=geotiff |
title: Near Infrared (NIR) |
description: Emphasizes biomass content and shorelines |
roles: ['reflectance'] |
owner: 20201220T104856_L8_200030_OLI_TIRS |
eoreader_name: NARROW_NIR |
eo:bands: [{'name': 'Near Infrared (NIR)', 'common_name': 'nir08', 'description': 'Emphasizes biomass content and shorelines', 'center_wavelength': 0.865, 'full_width_half_max': 0.03}] |
created: 2023-05-31T13:19:05.952145Z |
updated: 2023-05-31T13:19:05.952153Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 30 |
Asset: Cirrus
href: tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B9.TIF |
type: image/tiff; application=geotiff |
title: Cirrus |
description: Improved detection of cirrus cloud contamination |
roles: ['reflectance'] |
owner: 20201220T104856_L8_200030_OLI_TIRS |
eoreader_name: CIRRUS |
eo:bands: [{'name': 'Cirrus', 'common_name': 'cirrus', 'description': 'Improved detection of cirrus cloud contamination', 'center_wavelength': 1.37, 'full_width_half_max': 0.02}] |
created: 2023-05-31T13:19:05.952207Z |
updated: 2023-05-31T13:19:05.952215Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 30 |
Asset: SWIR 1
href: tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B6.TIF |
type: image/tiff; application=geotiff |
title: SWIR 1 |
description: Discriminates moisture content of soil and vegetation; penetrates thin clouds |
roles: ['reflectance'] |
owner: 20201220T104856_L8_200030_OLI_TIRS |
eoreader_name: SWIR_1 |
eo:bands: [{'name': 'SWIR 1', 'common_name': 'swir16', 'description': 'Discriminates moisture content of soil and vegetation; penetrates thin clouds', 'center_wavelength': 1.61, 'full_width_half_max': 0.08}] |
created: 2023-05-31T13:19:05.952270Z |
updated: 2023-05-31T13:19:05.952277Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 30 |
Asset: SWIR 2
href: tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B7.TIF |
type: image/tiff; application=geotiff |
title: SWIR 2 |
description: Improved moisture content of soil and vegetation; penetrates thin clouds |
roles: ['reflectance'] |
owner: 20201220T104856_L8_200030_OLI_TIRS |
eoreader_name: SWIR_2 |
eo:bands: [{'name': 'SWIR 2', 'common_name': 'swir22', 'description': 'Improved moisture content of soil and vegetation; penetrates thin clouds', 'center_wavelength': 2.2, 'full_width_half_max': 0.18}] |
created: 2023-05-31T13:19:05.952317Z |
updated: 2023-05-31T13:19:05.952323Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 30 |
Asset: Thermal Infrared (TIRS) 1
href: tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B10.TIF |
type: image/tiff; application=geotiff |
title: Thermal Infrared (TIRS) 1 |
description: 100 meter resolution, thermal mapping and estimated soil moisture |
roles: ['brightness_temperature'] |
owner: 20201220T104856_L8_200030_OLI_TIRS |
eoreader_name: THERMAL_IR_1 |
eo:bands: [{'name': 'Thermal Infrared (TIRS) 1', 'common_name': 'lwir11', 'description': '100 meter resolution, thermal mapping and estimated soil moisture', 'center_wavelength': 10.895, 'full_width_half_max': 0.59}] |
created: 2023-05-31T13:19:05.952362Z |
updated: 2023-05-31T13:19:05.952369Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 100 |
Asset: Thermal Infrared (TIRS) 2
href: tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B11.TIF |
type: image/tiff; application=geotiff |
title: Thermal Infrared (TIRS) 2 |
description: 100 meter resolution, improved thermal mapping and estimated soil moisture |
roles: ['brightness_temperature'] |
owner: 20201220T104856_L8_200030_OLI_TIRS |
eoreader_name: THERMAL_IR_2 |
eo:bands: [{'name': 'Thermal Infrared (TIRS) 2', 'common_name': 'lwir12', 'description': '100 meter resolution, improved thermal mapping and estimated soil moisture', 'center_wavelength': 12.005, 'full_width_half_max': 1.01}] |
created: 2023-05-31T13:19:05.952408Z |
updated: 2023-05-31T13:19:05.952414Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 100 |
Asset: Panchromatic
href: tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B8.TIF |
type: image/tiff; application=geotiff |
title: Panchromatic |
description: 15 meter resolution, sharper image definition |
roles: ['reflectance'] |
owner: 20201220T104856_L8_200030_OLI_TIRS |
eoreader_name: PANCHROMATIC |
eo:bands: [{'name': 'Panchromatic', 'common_name': 'pan', 'description': '15 meter resolution, sharper image definition', 'center_wavelength': 0.59, 'full_width_half_max': 0.18}] |
created: 2023-05-31T13:19:05.952452Z |
updated: 2023-05-31T13:19:05.952459Z |
start_datetime: 2020-12-20T10:48:56Z |
end_datetime: 2020-12-20T10:48:56Z |
instruments: ['OLI-TIRS'] |
constellation: landsat-8 |
gsd: 30 |
Links
Link: SERTIT Catalog
rel: root |
href: /tmp/tmppwz8fcaa/catalog.json |
type: application/json |
title: SERTIT Catalog |
Link:
rel: self |
href: /tmp/tmppwz8fcaa/20201220T104856_L8_200030_OLI_TIRS/20201220T104856_L8_200030_OLI_TIRS.json |
type: application/json |
Link: SERTIT Catalog
rel: parent |
href: /tmp/tmppwz8fcaa/catalog.json |
type: application/json |
title: SERTIT Catalog |
Query the catalog#
EODAG
is an opensource python library that implements STAC and allows you to query your local STAC catalog.
Look at here for a detailed tutorial.
# Create an EODAG custom STAC provider
dag = EODataAccessGateway()
# Set EODAG logging level to WARNING
setup_logging(verbose=1)
# Add the custom STAC provider, exactly like in the tutorial mentioned above
dag.update_providers_config("""
stac_http_provider:
search:
type: StaticStacSearch
api_endpoint: %s
products:
GENERIC_PRODUCT_TYPE:
productType: '{productType}'
download:
type: HTTPDownload
base_uri: %s
flatten_top_dirs: True
outputs_prefix: %s
""" % (catalog_path, tmp.name, tmp.name))
# Set the custom STAC provider as preferred
dag.set_preferred_provider("stac_http_provider")
# Query every product from inside the catalog
all_products, _ = dag.search()
# Load an AOI
aoi_path = os.path.join("/home", "data", "DATA", "AOIs", "DAX.geojson")
aoi = gpd.read_file(aoi_path)
aoi_geojson = mapping(aoi.geometry.values[0])
# Query spatially with the AOI and temporally with a time period
query_args = {"start": "2020-05-01", "end": "2022-05-06", "geom": aoi.geometry.values[0]}
query_products, _ = dag.search(**query_args)
query_products[0]
EOProduct(id=20201220T104856_L8_200030_OLI_TIRS, provider=stac_http_provider)
query_products[0].assets['Blue']
{'href': 'tar+file:///home/data/DATA/PRODS/LANDSATS_COL2/LC08_L1TP_200030_20201220_20210310_02_T1.tar!LC08_L1TP_200030_20201220_20210310_02_T1_B2.TIF',
'type': 'image/tiff; application=geotiff',
'title': 'Blue',
'description': 'Bathymetric mapping, distinguishing soil from vegetation and deciduous from coniferous vegetation',
'eoreader_name': 'BLUE',
'eo:bands': [{'name': 'Blue',
'common_name': 'blue',
'description': 'Bathymetric mapping, distinguishing soil from vegetation and deciduous from coniferous vegetation',
'center_wavelength': 0.48,
'full_width_half_max': 0.06}],
'created': '2023-05-31T13:19:05.951933Z',
'updated': '2023-05-31T13:19:05.951941Z',
'start_datetime': '2020-12-20T10:48:56Z',
'end_datetime': '2020-12-20T10:48:56Z',
'instruments': ['OLI-TIRS'],
'constellation': 'landsat-8',
'gsd': 30,
'roles': ['reflectance']}
Display the results#
We can use folium
to display the results geometry over a map.
import folium
# Create a map zoomed over the search area
fmap = folium.Map((43.2, -1.05), zoom_start=7)
# Add a layer green layer for the query over the AOI
folium.GeoJson(
data=all_products.as_geojson_object(),
tooltip = "All products stored in the catalog",
style_function=lambda x: {'color': 'green'}
).add_to(fmap)
# Add a layer green layer for the query over the AOI
folium.GeoJson(
data=query_products.as_geojson_object(),
tooltip = "Retrieved products with the query",
style_function=lambda x: {'color': 'red'}
).add_to(fmap)
# Add a layer blue layer for the AOI
folium.GeoJson(
data=aoi_geojson,
tooltip = "DAX AOI",
style_function=lambda x: {'color': 'blue'}
).add_to(fmap)
fmap
Make this Notebook Trusted to load map: File -> Trust Notebook
# Clean the tmp directory
tmp.cleanup()