STAC is the central way of accessing any spatio-temporal data on terrabyte. See here for an introduction and the detailed sepcification:
Principally, data is offered over a catalog containing data from various sources. This catalog is further sub-divided into collections. A collection could for example contain a certain satellite data product like Sentinel-1 GRD, SLC or Sentinel-2 L2A. Each collection consists of multiple items, which might represent individual satellite scenes or product tiles (e.g. the MGRS tiles of Sentinel-2). Each item consists of one or many assets, which contain links to the actual data. For example individual GeoTIFF files for each band.
Besides the STAC API (https://stac.terrabyte.lrz.de/public/api) we have made available an export of the STAC Items for each collection as Geoparquet files. You can query those Geoparquet files with the in-memory database DuckDB. Without interacting with the terrabyte STAC API you can query and filter STAC items with your own computing resources.
For this example, you need to have the Python libraries duckdb
(we still need version 1.0.0!), pygeofilter-duckdb
(https://github.com/DLR-terrabyte/pygeofilter-duckdb), and stac-geoparquet
installed.
#!pip install duckdb==1.0.0 stac-geoparquet git+https://github.com/DLR-terrabyte/pygeofilter-duckdb.git
import json
import pystac
import duckdb
from stac_geoparquet.arrow._api import stac_table_to_items
# Install and load DuckDB spatial extension
duckdb.install_extension('spatial')
duckdb.load_extension('spatial')
# Use pygeofilter library to convert between CQL2-JSON/Text and SQL query
from pygeofilter.parsers.cql2_json import parse as json_parse
from pygeofilter.backends.duckdb import to_sql_where
from pygeofilter.util import IdempotentDict
geoparquet_files = {
'sentinel-1-grd': '/dss/dsstbyfs03/pn56su/pn56su-dss-0022/Sentinel-1/GRD/geoparquet/*.parquet',
'sentinel-1-slc': '/dss/dsstbyfs03/pn56su/pn56su-dss-0022/Sentinel-1/SLC/geoparquet/*.parquet',
'sentinel-2-c1-l1c': '/dss/dsstbyfs01/pn56su/pn56su-dss-0008/Sentinel-2-Col-1/L1C/geoparquet/*.parquet',
'sentinel-2-c1-l2a': '/dss/dsstbyfs01/pn56su/pn56su-dss-0008/Sentinel-2-Col-1/L2A/geoparquet/*.parquet',
'sentinel-3-olci-l1-efr': '/dss/dsstbyfs01/pn56su/pn56su-dss-0008/Sentinel-3/OLCI/OL_1_EFR___/geoparquet/*.parquet',
'landsat-tm-c2-l2': '/dss/dsstbyfs01/pn56su/pn56su-dss-0008/Landsat/collection-2/level-2/standard/tm/geoparquet/*.parquet',
'landsat-etm-c2-l2': '/dss/dsstbyfs01/pn56su/pn56su-dss-0008/Landsat/collection-2/level-2/standard/etm/geoparquet/*.parquet',
'landsat-ot-c2-l2': '/dss/dsstbyfs01/pn56su/pn56su-dss-0008/Landsat/collection-2/level-2/standard/oli-tirs/geoparquet/*.parquet',
}
start = '2023-02-01T00:00:00Z'
end = '2023-02-28T23:59:59Z'
collection = 'sentinel-2-c1-l2a'
cql2_filter = {
"op": "and",
"args": [
{
"op": "between",
"args": [
{
"property": "eo:cloud_cover"
},
[0, 21]
]
},
{
"op": "between",
"args": [
{
"property": "datetime"
},
[start, end]
]
},
{
"op": "s_intersects",
"args": [
{ "property": "geometry" } ,
{
"type": "Polygon", # Baden-Württemberg
"coordinates": [[
[7.5113934084, 47.5338000528],
[10.4918239143, 47.5338000528],
[10.4918239143, 49.7913749328],
[7.5113934084, 49.7913749328],
[7.5113934084, 47.5338000528]
]]
}
]
}
]
}
sql_where = to_sql_where(json_parse(cql2_filter), IdempotentDict())
%%time
# Define geoparquet files
geoparquet = geoparquet_files[collection]
# Define and execute query
# Note: union_by_name slows down the query process, but is necessary when there are properties not available in all STAC items
sql_query = f"SELECT * FROM read_parquet('{geoparquet}', union_by_name=False) WHERE {sql_where}"
print(f"DuckDB Query:\n{sql_query}\n")
db = duckdb.query(sql_query)
## Convert DuckDB result to Arrow table
table = db.fetch_arrow_table()
## Convert Arrow table to List of PyStac-Items
items = []
for item in stac_table_to_items(table):
item['assets'] = json.loads(item['assets'])
items.append(pystac.Item.from_dict(item))
print("%s items found\n" % len(items))
DuckDB Query: SELECT * FROM read_parquet('/dss/dsstbyfs01/pn56su/pn56su-dss-0008/Sentinel-2-Col-1/L2A/geoparquet/*.parquet', union_by_name=False) WHERE ((("eo:cloud_cover" BETWEEN 0 AND 21) AND ("datetime" BETWEEN '2023-02-01T00:00:00Z' AND '2023-02-28T23:59:59Z')) AND ST_Intersects(ST_GeomFromWKB(geometry),ST_GeomFromHEXEWKB('0103000000010000000500000034DFB1B6AA0B1E4085B0648F53C44740509E1658D0FB244085B0648F53C44740509E1658D0FB244006A017C64BE5484034DFB1B6AA0B1E4006A017C64BE5484034DFB1B6AA0B1E4085B0648F53C44740'))) 35 items found CPU times: user 29.8 s, sys: 1min 54s, total: 2min 24s Wall time: 19.3 s
items[0]
import geopandas as gpd
dataframe = gpd.GeoDataFrame.from_features(items)
dataframe
geometry | constellation | eo:cloud_cover | grid:code | instruments | mgrs:grid_square | mgrs:latitude_band | mgrs:utm_zone | platform | proj:centroid | ... | s2:water_percentage | sat:orbit_state | sat:relative_orbit | terrabyte:stactools_id | view:azimuth | view:incidence_angle | view:sun_azimuth | view:sun_elevation | created | datetime | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | POLYGON ((7.57204 48.74304, 6.28064 48.72091, ... | sentinel-2 | 7.996309 | MGRS-32ULU | [msi] | LU | U | 32 | sentinel-2a | {'lat': 48.27686, 'lon': 6.83282} | ... | 0.222254 | descending | 8 | S2A_T32ULU_20230211T104302_L2A | 288.551167 | 8.836733 | 164.146943 | 26.377804 | 2024-05-20T16:52:14.584596Z | 2023-02-11T11:41:51.024000Z |
1 | POLYGON ((7.75088 46.85850, 9.12806 46.86563, ... | sentinel-2 | 3.603994 | MGRS-32TMT | [msi] | MT | T | 32 | sentinel-2b | {'lat': 47.33211, 'lon': 8.52417} | ... | 4.238812 | descending | 65 | S2B_T32TMT_20230210T102051_L2A | 105.386213 | 8.326560 | 160.311293 | 26.162376 | 2024-05-20T18:44:59.158467Z | 2023-02-10T11:20:49.024000Z |
2 | POLYGON ((8.99973 47.85370, 8.99974 46.86570, ... | sentinel-2 | 12.093081 | MGRS-32TNT | [msi] | NT | T | 32 | sentinel-2b | {'lat': 47.35663, 'lon': 9.72673} | ... | 4.375875 | descending | 65 | S2B_T32TNT_20230210T102051_L2A | 152.988379 | 2.962180 | 161.691112 | 26.452285 | 2024-05-20T18:44:59.851764Z | 2023-02-10T11:20:49.024000Z |
3 | POLYGON ((11.75191 46.84844, 11.80285 47.81947... | sentinel-2 | 1.939114 | MGRS-32TPT | [msi] | PT | T | 32 | sentinel-2b | {'lat': 47.3406, 'lon': 11.05059} | ... | 0.904028 | descending | 65 | S2B_T32TPT_20230210T102051_L2A | 285.736790 | 6.642694 | 163.076612 | 26.736361 | 2024-05-20T18:45:00.391288Z | 2023-02-10T11:20:49.024000Z |
4 | POLYGON ((8.07584 47.75956, 9.13025 47.76509, ... | sentinel-2 | 0.597896 | MGRS-32UMU | [msi] | MU | U | 32 | sentinel-2b | {'lat': 48.22222, 'lon': 8.68893} | ... | 0.434245 | descending | 65 | S2B_T32UMU_20230210T102051_L2A | 106.277863 | 9.309764 | 160.382539 | 25.299265 | 2024-05-20T18:45:00.672984Z | 2023-02-10T11:20:49.024000Z |
5 | POLYGON ((8.41111 48.66112, 9.13255 48.66495, ... | sentinel-2 | 16.493364 | MGRS-32UMV | [msi] | MV | U | 32 | sentinel-2b | {'lat': 49.09985, 'lon': 8.85464} | ... | 0.173872 | descending | 65 | S2B_T32UMV_20230210T102051_L2A | 105.922841 | 10.255324 | 160.447572 | 24.435612 | 2024-05-20T18:45:00.753325Z | 2023-02-10T11:20:49.024000Z |
6 | POLYGON ((8.99973 48.75301, 8.99973 47.76517, ... | sentinel-2 | 3.414702 | MGRS-32UNU | [msi] | NU | U | 32 | sentinel-2b | {'lat': 48.25592, 'lon': 9.73938} | ... | 0.563901 | descending | 65 | S2B_T32UNU_20230210T102051_L2A | 115.135146 | 3.936790 | 161.778088 | 25.588092 | 2024-05-20T18:45:01.190912Z | 2023-02-10T11:20:49.024000Z |
7 | POLYGON ((10.36028 48.74498, 10.33433 47.75741... | sentinel-2 | 4.758111 | MGRS-32UPU | [msi] | PU | U | 32 | sentinel-2b | {'lat': 48.23937, 'lon': 11.0863} | ... | 1.520126 | descending | 65 | S2B_T32UPU_20230210T102051_L2A | 269.702743 | 4.830915 | 163.179111 | 25.871311 | 2024-05-20T18:45:01.848092Z | 2023-02-10T11:20:49.024000Z |
8 | POLYGON ((6.23438 49.55801, 6.23590 49.53173, ... | sentinel-2 | 0.471554 | MGRS-32ULA | [msi] | LA | U | 32 | sentinel-2a | {'lat': 50.01406, 'lon': 7.07489} | ... | 0.806024 | descending | 108 | S2A_T32ULA_20230208T103552_L2A | 104.936734 | 8.202581 | 161.814501 | 23.196688 | 2024-05-20T16:35:12.733615Z | 2023-02-08T11:32:11.024000Z |
9 | POLYGON ((6.28064 48.72091, 6.33246 47.73416, ... | sentinel-2 | 1.271214 | MGRS-32ULU | [msi] | LU | U | 32 | sentinel-2a | {'lat': 48.24168, 'lon': 7.04561} | ... | 0.747165 | descending | 108 | S2A_T32ULU_20230208T103552_L2A | 105.077485 | 4.668500 | 161.762893 | 24.944530 | 2024-05-20T16:35:13.023435Z | 2023-02-08T11:32:11.024000Z |
10 | POLYGON ((6.23434 49.55791, 6.28537 48.63303, ... | sentinel-2 | 0.076697 | MGRS-32ULV | [msi] | LV | U | 32 | sentinel-2a | {'lat': 49.14065, 'lon': 7.01092} | ... | 0.480214 | descending | 108 | S2A_T32ULV_20230208T103552_L2A | 106.142678 | 6.720451 | 161.792025 | 24.070592 | 2024-05-20T16:35:13.096762Z | 2023-02-08T11:32:11.024000Z |
11 | POLYGON ((7.58809 50.54373, 7.61676 49.55649, ... | sentinel-2 | 0.778742 | MGRS-32UMA | [msi] | MA | U | 32 | sentinel-2a | {'lat': 50.05597, 'lon': 8.36939} | ... | 1.031012 | descending | 108 | S2A_T32UMA_20230208T103552_L2A | 157.587104 | 2.901423 | 163.239998 | 23.447721 | 2024-05-20T16:35:13.168731Z | 2023-02-08T11:32:11.024000Z |
12 | POLYGON ((7.63918 48.74498, 7.66513 47.75740, ... | sentinel-2 | 3.689634 | MGRS-32UMU | [msi] | MU | U | 32 | sentinel-2a | {'lat': 48.25669, 'lon': 8.39183} | ... | 0.782247 | descending | 108 | S2A_T32UMU_20230208T103552_L2A | 250.085489 | 4.005848 | 163.153684 | 25.197415 | 2024-05-20T16:35:13.804422Z | 2023-02-08T11:32:11.024000Z |
13 | POLYGON ((7.61427 49.64443, 7.64155 48.65702, ... | sentinel-2 | 0.337591 | MGRS-32UMV | [msi] | MV | U | 32 | sentinel-2a | {'lat': 49.1564, 'lon': 8.38089} | ... | 1.175628 | descending | 108 | S2A_T32UMV_20230208T103552_L2A | 202.284176 | 2.910406 | 163.199482 | 24.322516 | 2024-05-20T16:35:13.881227Z | 2023-02-08T11:32:11.024000Z |
14 | POLYGON ((10.52110 49.65647, 10.54933 50.54198... | sentinel-2 | 1.062858 | MGRS-32UNA | [msi] | NA | U | 32 | sentinel-2a | {'lat': 50.05586, 'lon': 9.76554} | ... | 0.421863 | descending | 108 | S2A_T32UNA_20230208T103552_L2A | 287.534457 | 6.748504 | 164.672067 | 23.693833 | 2024-05-20T16:35:13.972960Z | 2023-02-08T11:32:11.024000Z |
15 | POLYGON ((10.08905 48.74596, 8.99973 48.75301,... | sentinel-2 | 8.408582 | MGRS-32UNU | [msi] | NU | U | 32 | sentinel-2a | {'lat': 48.29935, 'lon': 9.4407} | ... | 0.544980 | descending | 108 | S2A_T32UNU_20230208T103552_L2A | 288.533829 | 9.284919 | 164.551231 | 25.444921 | 2024-05-20T16:35:14.577067Z | 2023-02-08T11:32:11.024000Z |
16 | POLYGON ((10.51451 49.64278, 8.99972 49.65272,... | sentinel-2 | 1.204115 | MGRS-32UNV | [msi] | NV | U | 32 | sentinel-2a | {'lat': 49.18463, 'lon': 9.64688} | ... | 0.188082 | descending | 108 | S2A_T32UNV_20230208T103552_L2A | 287.171497 | 8.192749 | 164.613594 | 24.569290 | 2024-05-20T16:35:14.677184Z | 2023-02-08T11:32:11.024000Z |
17 | POLYGON ((10.95037 50.53362, 10.41135 50.54374... | sentinel-2 | 0.771424 | MGRS-32UPA | [msi] | PA | U | 32 | sentinel-2a | {'lat': 50.16494, 'lon': 10.58385} | ... | 0.292618 | descending | 108 | S2A_T32UPA_20230208T103552_L2A | 292.890996 | 10.782747 | 166.108427 | 23.934725 | 2024-05-20T16:35:14.753524Z | 2023-02-08T11:32:11.024000Z |
18 | POLYGON ((10.51416 49.64205, 10.38517 49.64444... | sentinel-2 | 2.012247 | MGRS-32UPV | [msi] | PV | U | 32 | sentinel-2a | {'lat': 49.54781, 'lon': 10.42551} | ... | 0.071741 | descending | 108 | S2A_T32UPV_20230208T103552_L2A | 294.559430 | 11.577531 | 166.032167 | 24.810613 | 2024-05-20T16:35:15.328768Z | 2023-02-08T11:32:11.024000Z |
19 | POLYGON ((7.75715 46.85854, 9.12806 46.86563, ... | sentinel-2 | 13.766459 | MGRS-32TMT | [msi] | MT | T | 32 | sentinel-2a | {'lat': 47.33196, 'lon': 8.52769} | ... | 2.715510 | descending | 65 | S2A_T32TMT_20230215T102115_L2A | 104.584525 | 8.337052 | 159.880835 | 27.789336 | 2024-05-20T17:15:45.052075Z | 2023-02-15T11:21:21.024000Z |
20 | POLYGON ((8.99973 47.85370, 8.99974 46.86570, ... | sentinel-2 | 9.103514 | MGRS-32TNT | [msi] | NT | T | 32 | sentinel-2a | {'lat': 47.35663, 'lon': 9.72673} | ... | 1.435123 | descending | 65 | S2A_T32TNT_20230215T102115_L2A | 152.210026 | 2.961223 | 161.289708 | 28.085337 | 2024-05-20T17:15:45.887293Z | 2023-02-15T11:21:21.024000Z |
21 | POLYGON ((11.75144 46.83934, 11.80285 47.81947... | sentinel-2 | 0.021178 | MGRS-32TPT | [msi] | PT | T | 32 | sentinel-2a | {'lat': 47.34059, 'lon': 11.05061} | ... | 0.902982 | descending | 65 | S2A_T32TPT_20230215T102115_L2A | 286.934241 | 6.614693 | 162.704684 | 28.375089 | 2024-05-20T17:15:46.471697Z | 2023-02-15T11:21:21.024000Z |
22 | POLYGON ((8.08333 47.75960, 9.13025 47.76509, ... | sentinel-2 | 2.368895 | MGRS-32UMU | [msi] | MU | U | 32 | sentinel-2a | {'lat': 48.22188, 'lon': 8.69234} | ... | 0.185890 | descending | 65 | S2A_T32UMU_20230215T102115_L2A | 105.588766 | 9.317489 | 159.964515 | 26.928148 | 2024-05-20T17:15:46.751932Z | 2023-02-15T11:21:21.024000Z |
23 | POLYGON ((6.32793 47.82259, 6.37728 46.83564, ... | sentinel-2 | 15.273316 | MGRS-32TLT | [msi] | LT | T | 32 | sentinel-2b | {'lat': 47.34283, 'lon': 7.07904} | ... | 0.398934 | descending | 108 | S2B_T32TLT_20230213T103136_L2A | 137.470871 | 3.216299 | 161.309055 | 27.407870 | 2024-05-20T19:09:14.241958Z | 2023-02-13T11:30:39.024000Z |
24 | POLYGON ((6.23434 49.55873, 6.23590 49.53173, ... | sentinel-2 | 1.137276 | MGRS-32ULA | [msi] | LA | U | 32 | sentinel-2b | {'lat': 50.01414, 'lon': 7.07444} | ... | 0.749760 | descending | 108 | S2B_T32ULA_20230213T103136_L2A | 105.775182 | 8.197802 | 161.428029 | 24.791311 | 2024-05-20T19:09:14.835251Z | 2023-02-13T11:30:39.024000Z |
25 | POLYGON ((7.58809 50.54373, 7.61676 49.55649, ... | sentinel-2 | 0.630424 | MGRS-32UMA | [msi] | MA | U | 32 | sentinel-2b | {'lat': 50.05597, 'lon': 8.36939} | ... | 1.009667 | descending | 108 | S2B_T32UMA_20230213T103136_L2A | 157.679238 | 2.905556 | 162.881224 | 25.047869 | 2024-05-20T19:09:15.286539Z | 2023-02-13T11:30:39.024000Z |
26 | POLYGON ((7.61427 49.64443, 7.64155 48.65702, ... | sentinel-2 | 15.516013 | MGRS-32UMV | [msi] | MV | U | 32 | sentinel-2b | {'lat': 49.1564, 'lon': 8.38089} | ... | 0.796612 | descending | 108 | S2B_T32UMV_20230213T103136_L2A | 201.936845 | 2.915446 | 162.830796 | 25.921286 | 2024-05-20T19:09:15.847356Z | 2023-02-13T11:30:39.024000Z |
27 | POLYGON ((10.51648 49.64276, 8.99972 49.65272,... | sentinel-2 | 5.884475 | MGRS-32UNV | [msi] | NV | U | 32 | sentinel-2b | {'lat': 49.18454, 'lon': 9.6479} | ... | 0.183773 | descending | 108 | S2B_T32UNV_20230213T103136_L2A | 286.290677 | 8.192585 | 164.273265 | 26.173327 | 2024-05-20T19:09:16.539593Z | 2023-02-13T11:30:39.024000Z |
28 | POLYGON ((7.57441 48.74308, 6.28064 48.72091, ... | sentinel-2 | 3.802932 | MGRS-32ULU | [msi] | LU | U | 32 | sentinel-2a | {'lat': 48.27679, 'lon': 6.834} | ... | 0.322455 | descending | 8 | S2A_T32ULU_20230221T104156_L2A | 288.421940 | 8.841063 | 163.553699 | 29.804166 | 2024-05-20T17:51:12.743999Z | 2023-02-21T11:40:41.024000Z |
29 | POLYGON ((7.76299 49.14599, 7.75054 49.64598, ... | sentinel-2 | 0.001089 | MGRS-32ULV | [msi] | LV | U | 32 | sentinel-2a | {'lat': 49.15422, 'lon': 6.98231} | ... | 0.487465 | descending | 8 | S2A_T32ULV_20230221T104156_L2A | 287.359875 | 7.501864 | 163.591716 | 28.923838 | 2024-05-20T17:51:12.810061Z | 2023-02-21T11:40:41.024000Z |
30 | POLYGON ((8.00234 49.64653, 7.61427 49.64443, ... | sentinel-2 | 0.001835 | MGRS-32UMV | [msi] | MV | U | 32 | sentinel-2a | {'lat': 49.38917, 'lon': 7.75027} | ... | 0.053606 | descending | 8 | S2A_T32UMV_20230221T104156_L2A | 294.403151 | 11.111383 | 165.091299 | 29.147910 | 2024-05-20T17:51:13.332970Z | 2023-02-21T11:40:41.024000Z |
31 | POLYGON ((7.75822 46.85854, 9.12806 46.86563, ... | sentinel-2 | 7.724092 | MGRS-32TMT | [msi] | MT | T | 32 | sentinel-2b | {'lat': 47.33196, 'lon': 8.52799} | ... | 3.673277 | descending | 65 | S2B_T32TMT_20230220T101948_L2A | 105.386143 | 8.341995 | 159.511466 | 29.519776 | 2024-05-20T20:05:05.328255Z | 2023-02-20T11:19:49.024000Z |
32 | POLYGON ((8.99973 47.85370, 8.99974 46.86570, ... | sentinel-2 | 14.072865 | MGRS-32TNT | [msi] | NT | T | 32 | sentinel-2b | {'lat': 47.35663, 'lon': 9.72673} | ... | 3.210768 | descending | 65 | S2B_T32TNT_20230220T101948_L2A | 152.600151 | 2.968600 | 160.952256 | 29.820931 | 2024-05-20T20:05:05.935668Z | 2023-02-20T11:19:49.024000Z |
33 | POLYGON ((11.75120 46.83482, 11.80285 47.81947... | sentinel-2 | 8.209906 | MGRS-32TPT | [msi] | PT | T | 32 | sentinel-2b | {'lat': 47.34059, 'lon': 11.05061} | ... | 0.861821 | descending | 65 | S2B_T32TPT_20230220T101948_L2A | 285.655287 | 6.594657 | 162.399624 | 30.115381 | 2024-05-20T20:05:06.381118Z | 2023-02-20T11:19:49.024000Z |
34 | POLYGON ((8.08376 47.75960, 9.13025 47.76509, ... | sentinel-2 | 19.237934 | MGRS-32UMU | [msi] | MU | U | 32 | sentinel-2b | {'lat': 48.22185, 'lon': 8.69272} | ... | 0.334085 | descending | 65 | S2B_T32UMU_20230220T101948_L2A | 106.241496 | 9.323031 | 159.608452 | 28.660273 | 2024-05-20T20:05:06.648969Z | 2023-02-20T11:19:49.024000Z |
35 rows × 43 columns
import folium
import folium.plugins as folium_plugins
map = folium.Map()
layer_control = folium.LayerControl(position='topright', collapsed=True)
fullscreen = folium_plugins.Fullscreen()
style = {'fillColor': '#00000000', "color": "#0000ff", "weight": 1}
footprints = folium.GeoJson(
dataframe.to_json(),
name='Stac Item footprints',
style_function=lambda x: style,
control=True
)
footprints.add_to(map)
layer_control.add_to(map)
fullscreen.add_to(map)
map.fit_bounds(map.get_bounds())
map