Search for products by tile#
Built-in search by tile#
Many providers already support search by tile (Sentinel 2 MGRS tiling grid): creodias, cop_dataspace, earth_search, geodes, planetary_computer.
For these providers, you can use grid:code as search parameter using EODAG:
[1]:
from eodag import EODataAccessGateway, setup_logging
dag = EODataAccessGateway()
products = dag.search(
provider="cop_dataspace",
collection="S2_MSI_L1C",
start="2018-06-01",
end="2018-06-15",
**{"grid:code": "MGRS-31TFK"}
)
products
[1]:
| SearchResult (6) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0 EOProduct(id=S2B_MSIL1C_20180602T104019_N0500_R008_T31TFK_20230827T165546, provider=cop_dataspace)
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 EOProduct(id=S2A_MSIL1C_20180604T103021_N0500_R108_T31TFK_20230819T115015, provider=cop_dataspace)
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 EOProduct(id=S2A_MSIL1C_20180607T104021_N0500_R008_T31TFK_20230818T193607, provider=cop_dataspace)
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3 EOProduct(id=S2B_MSIL1C_20180609T103019_N0500_R108_T31TFK_20230823T173246, provider=cop_dataspace)
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4 EOProduct(id=S2B_MSIL1C_20180612T104019_N0500_R008_T31TFK_20230824T092151, provider=cop_dataspace)
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5 EOProduct(id=S2A_MSIL1C_20180614T103021_N0500_R108_T31TFK_20230812T193420, provider=cop_dataspace)
|
[2]:
[p.properties["grid:code"] for p in products]
[2]:
['MGRS-31TFK',
'MGRS-31TFK',
'MGRS-31TFK',
'MGRS-31TFK',
'MGRS-31TFK',
'MGRS-31TFK']
Search by tile using custom locations#
eodag allows to search for products by geometric features that match a location query, see the API user guide for an introduction to this concept.
In this tutorial we will use a shapefile that represents the Sentinel 2 tiling grid to search for Sentinel 2 Level-1C products with cop_dataspace at a specific tile. In this shapefile each tile is defined by its centroid and a tile_id attribute (e.g. 29PMT). This shapefile was created by downloading first the Sentinel 2 tiling grid (MGRS) provided by ESA as a KML
file. It was then converted as a shapefile and processed to compute the centroids. We use the tile’s centroid here as eodag returns products that intersects the user defined search area. Since tiles overlap with each other, using the polygons instead of the centroids would return more tiles than just the one we target.
[3]:
import os
from zipfile import ZipFile
# Interactive mapping
import folium
from folium.plugins import TimestampedGeoJson
# pyshp: to read shapefiles
import shapefile
Setup#
A workspace directory is created to store the files that will be generated.
[4]:
workspace = "eodag_workspace_locations_tiles"
if not os.path.isdir(workspace):
os.mkdir(workspace)
You should have an auxdata folder next to this tutorial’s file. It contains a shapefile that is needed to run this tutorial correctly.
[5]:
sentinel2_grid_zip = os.path.join("auxdata", "sentinel2_tiling_grid_centroids.zip")
if not os.path.isfile(sentinel2_grid_zip):
raise FileNotFoundError("Auxdata not found, please check your configuration.")
[6]:
# We unzip the archived shapefile.
with ZipFile(sentinel2_grid_zip, "r") as fzip:
fzip.extractall("auxdata")
In this tutorial products will just be searched for, not downloaded. We don’t need to set up cop_dataspace credentials to search for products. If you wish to download them, you should set the credentials beforehand, using these two environment variables for instance.
[7]:
# os.environ["EODAG__COP_DATASPACE__AUTH__CREDENTIALS__USERNAME"] = "PLEASE_CHANGE_ME"
# os.environ["EODAG__COP_DATASPACE__AUTH__CREDENTIALS__PASSWORD"] = "PLEASE_CHANGE_ME"
Logging is activated to better inspect what eodag does internally.
[8]:
setup_logging(2) # INFO level
The default search criteria consists of a time period in June 2018 and eodag’s collection identifier for Sentinel 2 Level-1C products.
[9]:
default_search_criteria = dict(
collection="S2_MSI_L1C",
start="2018-06-01",
end="2018-06-15"
)
Add a locations configuration#
We check and store the content of this shapefile.
[10]:
sentinel2_shp = os.path.join('auxdata', 'sentinel2_tiling_grid_centroids.shp')
with shapefile.Reader(sentinel2_shp) as shp:
print(shp, "\n")
print("fields:", shp.fields)
shaperecs = shp.shapeRecords()
shapefile Reader
56686 shapes (type 'POINT')
56686 records (2 fields)
fields: [Field(name="DeletionFlag", field_type=FieldType.C, size=1, decimal=0), Field(name="tile_id", field_type=FieldType.C, size=5, decimal=0)]
It has about 57 000 tiles/polygons and a field tile_id.
We create a YAML file to configure this new location selector, we will refer to it with s2_tile_centroid.
[11]:
# Save the locations configuration file.
locations_yaml_content = """
shapefiles:
- name: s2_tile_centroid
path: {}
attr: tile_id
""".format(os.path.abspath(sentinel2_shp))
locations_filepath = os.path.abspath(os.path.join(workspace, "custom_locations.yml"))
with open(locations_filepath, "w") as f_yml:
f_yml.write(locations_yaml_content.strip())
An instance of an EODataAccessGateway class is created, it makes use of this location configuration file.
[12]:
dag = EODataAccessGateway(locations_conf_path=locations_filepath)
2026-03-27 16:57:54,440 eodag.provider [INFO ] Loading user configuration from: /home/sbrunato/.config/eodag/eodag.yml
2026-03-27 16:57:54,449 eodag.provider [WARNING ] peps: could not create provider from scratch using config
2026-03-27 16:57:54,452 eodag.core [INFO ] aws_eos: provider needing auth for search has been pruned because no credentials could be found
2026-03-27 16:57:54,452 eodag.core [INFO ] cop_cds: provider needing auth for search has been pruned because no credentials could be found
2026-03-27 16:57:54,452 eodag.core [INFO ] meteoblue: provider needing auth for search has been pruned because no credentials could be found
2026-03-27 16:57:54,453 eodag.core [INFO ] hydroweb_next: provider needing auth for search has been pruned because no credentials could be found
2026-03-27 16:57:54,453 eodag.core [INFO ] wekeo_ecmwf: provider needing auth for search has been pruned because no credentials could be found
2026-03-27 16:57:54,453 eodag.core [INFO ] creodias_s3: provider needing auth for search has been pruned because no credentials could be found
2026-03-27 16:57:54,453 eodag.core [INFO ] dedt_lumi: provider needing auth for search has been pruned because no credentials could be found
2026-03-27 16:57:54,453 eodag.core [INFO ] dedt_mn5: provider needing auth for search has been pruned because no credentials could be found
2026-03-27 16:57:54,453 eodag.core [INFO ] geodes_s3: provider needing auth for search has been pruned because no credentials could be found
2026-03-27 16:57:54,453 eodag.core [INFO ] cop_ewds: provider needing auth for search has been pruned because no credentials could be found
2026-03-27 16:57:54,455 eodag.core [INFO ] Locations configuration loaded from /home/sbrunato/workspace/eodag/docs/notebooks/tutos/eodag_workspace_locations_tiles/custom_locations.yml
We want to look for Sentinel 2 Level-1C products. We can check whether this collection is offered by cop_dataspace (as configured in eodag). If so, cop_dataspace is set as the provider used to search for products.
[13]:
"S2_MSI_L1C" in dag.providers["cop_dataspace"].collections_config
[13]:
True
Search#
A single tile#
Our target tile is 31TFK and is located in the South-East of France. Its feature is retrieved from the shapefil to be displayed later on an interactive map.
[14]:
targeted_tile_name = "31TFK"
# Get the targeted tile feature
targeted_tile = [
sr
for sr in shaperecs
if sr.record["tile_id"] == "31TFK"
][0]
We search for all the products that intersect with the centroid of this tile.
[15]:
products = dag.search_all(
provider="cop_dataspace",
locations=dict(s2_tile_centroid="31TFK"),
**default_search_criteria
)
print(f"{len(products)} were found given the above search criteria")
2026-03-27 16:57:54,753 eodag.core [INFO ] Searching on provider cop_dataspace
2026-03-27 16:57:54,770 eodag.search.base [INFO ] cop_dataspace is configured with default sorting by 'start_datetime' in ascending order
2026-03-27 16:57:54,772 eodag.search.qssearch [INFO ] Sending search request: https://catalogue.dataspace.copernicus.eu/odata/v1/Products?$filter=Collection/Name%20eq%20%27SENTINEL-2%27%20and%20OData.CSC.Intersects%28area=geography%27SRID=4326%3BPOINT%20%284.9533%2044.6422%29%27%29%20and%20Attributes/OData.CSC.StringAttribute/any%28att:att/Name%20eq%20%27productType%27%20and%20att/OData.CSC.StringAttribute/Value%20eq%20%27S2MSI1C%27%29%20and%20ContentDate/Start%20lt%202018-06-15T00:00:00.000Z%20and%20ContentDate/End%20gt%202018-06-01T00:00:00.000Z&$orderby=ContentDate/Start%20asc&$top=1000&$skip=0&$expand=Attributes&$expand=Assets
2026-03-27 16:58:00,527 eodag.core [INFO ] Found 6 result(s) on provider 'cop_dataspace'
6 were found given the above search criteria
The products found are displayed on an interactive map along with the centroid of the targeted tile. A time player allows to see when the products were sensed.
[16]:
# The GeoJSON representation has to be slightly adapted for the time slider
adapted_prods = products.as_geojson_object()
for feature in adapted_prods["features"]:
feature["properties"]["time"] = feature["properties"]["start_datetime"]
# Create a map zoomed over the search area
fmap = folium.Map([44.5, 5], zoom_start=8)
# Add a layer that map the tile's centroid
folium.GeoJson(
data=targeted_tile,
tooltip = targeted_tile_name,
).add_to(fmap)
# Add layer that temporally maps the products found
TimestampedGeoJson(
adapted_prods,
transition_time=50, # Transition duration in ms
period="PT3H", # Array of times, here every 3 hours
duration="PT12H", # Feature display duragion, here 6 hours
time_slider_drag_update=True, # Update the map when the slider is dragged
auto_play=False, # Don't auto play the animation
).add_to(fmap)
fmap
[16]:
Note
Instead of using the tile’s centroid we could have directly used its extent and filter the returned products to keep only those fully contained within the tile. Check out the section dedicated to filtering products in the API user guide.
Multiple tiles#
We can search for products that overlap with several tiles using a regular expression. We use the expression "31T[CDE][MLK]" to look for products over 9 different tiles (31TCM, 31TCL, 31TCK, 31TDM, etc.) over France.
[17]:
products = dag.search_all(
provider="cop_dataspace",
locations=dict(s2_tile_centroid="31T[CDE][MLK]"),
**default_search_criteria
)
2026-03-27 16:58:00,848 eodag.core [INFO ] Searching on provider cop_dataspace
2026-03-27 16:58:00,864 eodag.search.base [INFO ] cop_dataspace is configured with default sorting by 'start_datetime' in ascending order
2026-03-27 16:58:00,865 eodag.search.qssearch [INFO ] Sending search request: https://catalogue.dataspace.copernicus.eu/odata/v1/Products?$filter=Collection/Name%20eq%20%27SENTINEL-2%27%20and%20OData.CSC.Intersects%28area=geography%27SRID=4326%3BMULTIPOINT%20%28%283.7147%2046.4567%29%2C%20%283.7032%2045.5565%29%2C%20%283.6922%2044.6568%29%2C%20%282.4122%2046.4574%29%2C%20%282.4216%2045.5572%29%2C%20%281.1109%2046.4433%29%2C%20%281.1413%2045.5436%29%2C%20%281.1703%2044.6442%29%2C%20%282.4306%2044.6575%29%29%27%29%20and%20Attributes/OData.CSC.StringAttribute/any%28att:att/Name%20eq%20%27productType%27%20and%20att/OData.CSC.StringAttribute/Value%20eq%20%27S2MSI1C%27%29%20and%20ContentDate/Start%20lt%202018-06-15T00:00:00.000Z%20and%20ContentDate/End%20gt%202018-06-01T00:00:00.000Z&$orderby=ContentDate/Start%20asc&$top=1000&$skip=0&$expand=Attributes&$expand=Assets
2026-03-27 16:58:06,368 eodag.core [INFO ] Found 32 result(s) on provider 'cop_dataspace'
[18]:
print(f"{len(products)} were found given the above search criteria")
32 were found given the above search criteria
The products are displayed on an interactive map. By hovering over them you can observe that the MGRS number of the tiles match with the regular expressions we used.
[19]:
# Create a map zoomed over the search area
fmap = folium.Map([44.5, 1.5], zoom_start=6)
# Create a layer that maps the products found
folium.GeoJson(
data=products,
tooltip=folium.GeoJsonTooltip(
fields=[
"title", # The product's title
"grid:code", # The tile number on the MGRS grid
]
),
).add_to(fmap)
fmap
[19]:
This example has demonstrated the possibilities offered by eodag to easily select products from a tile grid by using regular expressions over their identifier.