Căutare în catalogul STAC¶
Catalogul EOCube.Ro este un API STAC standard, deci se interoghează cu
uneltele obișnuite din ecosistem: pystac-client
pentru căutare și geopandas pentru geometrii.
Nu este nevoie de cont pentru colecțiile deschise.
In [1]:
Copied!
from pystac_client import Client
STAC_URL = "https://stac.eocube.ro"
catalog = Client.open(STAC_URL)
print(catalog.title or catalog.id)
from pystac_client import Client
STAC_URL = "https://stac.eocube.ro"
catalog = Client.open(STAC_URL)
print(catalog.title or catalog.id)
STAC API for EOCube.RO
Colecțiile disponibile¶
In [2]:
Copied!
import warnings
import pandas as pd
def first_date(c):
try:
iv = c.extent.temporal.intervals[0][0]
return iv.date().isoformat() if iv else "—"
except Exception:
return "—"
# Unele colecții din catalog au metadate de extent incomplete; pystac emite
# un UserWarning la citirea lor. Îl suprimăm aici ca să nu umple pagina --
# datele afișate nu sunt afectate.
with warnings.catch_warnings():
warnings.simplefilter("ignore", UserWarning)
rows = [
{"id": c.id, "titlu": (c.title or "")[:44], "interval": first_date(c)}
for c in catalog.get_collections()
]
pd.DataFrame(sorted(rows, key=lambda r: r["id"]))
import warnings
import pandas as pd
def first_date(c):
try:
iv = c.extent.temporal.intervals[0][0]
return iv.date().isoformat() if iv else "—"
except Exception:
return "—"
# Unele colecții din catalog au metadate de extent incomplete; pystac emite
# un UserWarning la citirea lor. Îl suprimăm aici ca să nu umple pagina --
# datele afișate nu sunt afectate.
with warnings.catch_warnings():
warnings.simplefilter("ignore", UserWarning)
rows = [
{"id": c.id, "titlu": (c.title or "")[:44], "interval": first_date(c)}
for c in catalog.get_collections()
]
pd.DataFrame(sorted(rows, key=lambda r: r["id"]))
Out[2]:
| id | titlu | interval | |
|---|---|---|---|
| 0 | copernicus-dem-30 | Copernicus DEM 30m | 2021-04-22 |
| 1 | esa-worldcover-2020 | ESA WorldCover 2020 | — |
| 2 | esa-worldcover-2021 | ESA WorldCover 2021 | — |
| 3 | sage-s2l1c-exp-1 | SAGE Internal Experiments 1 | 2024-01-05 |
| 4 | sentinel-1-slc | Sentinel-1 SLC | 2018-04-09 |
| 5 | sentinel-2-l1c | Sentinel-2 Level-1C | 2017-06-17 |
| 6 | sentinel-2-l1c-cog | Sentinel-2 Level-1C COGs | 2017-06-17 |
| 7 | sentinel-2-l2a | Sentinel-2 L2A | 2024-11-01 |
Căutare peste Timișoara¶
search() acceptă filtrele STAC uzuale; item_collection() întoarce
obiecte pystac.Item gata de folosit.
In [3]:
Copied!
TIMISOARA = {"type": "Point", "coordinates": [21.23, 45.75]}
search = catalog.search(
collections=["sentinel-2-l2a"],
intersects=TIMISOARA,
sortby=[{"field": "properties.datetime", "direction": "desc"}],
max_items=6,
)
items = search.item_collection()
print(f"{len(items)} produse")
for it in items:
print(f"{it.id[:46]:48s} {it.datetime:%Y-%m-%d} "
f"nori {it.properties.get('eo:cloud_cover', float('nan')):5.1f}%")
TIMISOARA = {"type": "Point", "coordinates": [21.23, 45.75]}
search = catalog.search(
collections=["sentinel-2-l2a"],
intersects=TIMISOARA,
sortby=[{"field": "properties.datetime", "direction": "desc"}],
max_items=6,
)
items = search.item_collection()
print(f"{len(items)} produse")
for it in items:
print(f"{it.id[:46]:48s} {it.datetime:%Y-%m-%d} "
f"nori {it.properties.get('eo:cloud_cover', float('nan')):5.1f}%")
6 produse S2C_MSIL2A_20260727T094031_N9999_R036_T34TER.S 2026-07-27 nori 77.5% S2A_MSIL2A_20260726T093051_N9999_R136_T34TER.S 2026-07-26 nori 23.9% S2C_MSIL2A_20260724T093031_N9999_R136_T34TER.S 2026-07-24 nori 52.0% S2B_MSIL2A_20260722T094029_N9999_R036_T34TER.S 2026-07-22 nori 40.6% S2A_MSIL2A_20260719T094051_N9999_R036_T34TER.S 2026-07-19 nori 66.2% S2B_MSIL2A_20260719T093029_N9999_R136_T34TER.S 2026-07-19 nori 30.8%
Amprentele, ca GeoDataFrame¶
ItemCollection se convertește direct în GeoDataFrame — de aici încolo
aveți la dispoziție tot ecosistemul geopandas (reproiectare, intersecții,
export GeoPackage/PostGIS).
In [4]:
Copied!
import geopandas as gpd
gdf = gpd.GeoDataFrame.from_features(items.to_dict(), crs="EPSG:4326")
gdf["datetime"] = pd.to_datetime(gdf["datetime"]).dt.date
gdf[["datetime", "eo:cloud_cover", "geometry"]].head()
import geopandas as gpd
gdf = gpd.GeoDataFrame.from_features(items.to_dict(), crs="EPSG:4326")
gdf["datetime"] = pd.to_datetime(gdf["datetime"]).dt.date
gdf[["datetime", "eo:cloud_cover", "geometry"]].head()
Out[4]:
| datetime | eo:cloud_cover | geometry | |
|---|---|---|---|
| 0 | 2026-07-27 | 77.455246 | POLYGON ((21.47331 46.05064, 21.44677 45.98826... |
| 1 | 2026-07-26 | 23.932140 | POLYGON ((20.99974 46.05357, 22.4189 46.04477,... |
| 2 | 2026-07-24 | 51.959765 | POLYGON ((20.99974 46.05357, 22.4189 46.04477,... |
| 3 | 2026-07-22 | 40.638587 | POLYGON ((21.48087 46.05059, 21.47841 46.04478... |
| 4 | 2026-07-19 | 66.166836 | POLYGON ((21.48322 46.05057, 21.44659 45.96419... |
In [5]:
Copied!
import matplotlib.pyplot as plt
ax = gdf.plot(figsize=(7, 6), alpha=0.25, edgecolor="#3949ab", linewidth=1.4)
ax.plot(*TIMISOARA["coordinates"], "r*", markersize=15, label="Timișoara")
ax.set(xlabel="lon", ylabel="lat",
title="Amprente Sentinel-2 L2A peste Timișoara")
ax.legend()
plt.tight_layout(); plt.show()
import matplotlib.pyplot as plt
ax = gdf.plot(figsize=(7, 6), alpha=0.25, edgecolor="#3949ab", linewidth=1.4)
ax.plot(*TIMISOARA["coordinates"], "r*", markersize=15, label="Timișoara")
ax.set(xlabel="lon", ylabel="lat",
title="Amprente Sentinel-2 L2A peste Timișoara")
ax.legend()
plt.tight_layout(); plt.show()
Ce urmează¶
- Acces la date COG — citire parțială direct din obiect storage, fără descărcarea produsului întreg.
- Colecții private și scriere în catalog: autentificați-vă cu
eocube(eocube auth login).