Skip to content

Catalog search

The UmbraCatalog is the entry point for discovery: it searches Umbra's static STAC catalog by area, date range, product type, place name, or polygon, and can read through a local index for fast, repeatable, offline queries.

UmbraCatalog

UmbraCatalog(bucket=S3_BUCKET, region=S3_REGION, session=None, *, token=None, archive_url=CANOPY_ARCHIVE_URL, collections=None)

Client for searching Umbra SAR data.

By default this searches Umbra's open data by crawling the public S3 bucket (a static STAC catalog with no search API). Pass a Canopy token and the same :meth:search interface instead queries Umbra's authenticated commercial archive over its real STAC API (:data:~umbra_py.constants.CANOPY_ARCHIVE_URL)::

# open data (default) -- no account needed
UmbraCatalog().search(area="Centerfield", limit=5)

# commercial archive -- same call, one extra argument
UmbraCatalog(token="...").search(bbox=bbox, start="2024", limit=5)

Both paths yield :class:~umbra_py.UmbraItem objects, so every downstream verb (download, quicklook, change, chips, ...) works unchanged against either archive. That is the funnel made literal: a user onboarded on the free bucket is already holding the tool they'd use as a paying customer. Get a token from https://docs.canopy.umbra.space/.

search

search(*, bbox=None, intersects=None, start=None, end=None, product_types=None, area=None, fuzzy=False, polarizations=None, min_incidence=None, max_incidence=None, max_resolution=None, limit=None, max_per_task=None)

Yield items matching the filters.

Parameters

bbox: (min_lon, min_lat, max_lon, max_lat) footprint filter. intersects: A polygon geometry (the exterior-ring form from :func:umbra_py._geometry.parse_geometry); keep only items whose footprint intersects it. A tighter spatial filter than the rectangular bbox -- the standard STAC intersects. Combines with bbox (both must match) when both are given. start, end: Inclusive acquisition-date bounds. Accepts date / datetime objects or ISO YYYY-MM-DD strings. The walker still has to list each task to discover what's published in range, so even a narrow window takes a few seconds; provide limit to stop as soon as you have enough. product_types: Keep only items exposing at least one of these assets (e.g. ["GEC"]). area: Case-insensitive substring matched against each sar-data/tasks/<task>/ directory name. Umbra files every pass of a site under one named task directory (e.g. "Centerfield, Utah"), so area="centerfield" returns just that site's acquisitions. Non-matching task directories are skipped before they're listed, so this also makes the search much faster -- the ergonomic way to gather the co-located passes a change composite needs. fuzzy: Widen area from a literal substring to a deterministic token-wise fuzzy match (:func:umbra_py.fuzzy.task_matches): word-order- and punctuation-independent, tolerant of a small typo, and a strict superset of the substring match (it never drops a result). So area="utah centerfield" or area="centrfield" still reaches "Centerfield, Utah". No model call -- the C1 deterministic first step. polarizations: Keep only items exposing at least one of these polarizations (case-insensitive, e.g. ["VV"]) -- the SAR-native filter that keeps a change comparison like-with-like (HH and VV image different physics). An item with no polarization metadata is excluded. min_incidence, max_incidence: Inclusive bounds (degrees) on the view incidence angle (:attr:UmbraItem.incidence_angle). An item with no incidence metadata is excluded when either bound is set. max_resolution: Keep only items at least this fine -- both range and azimuth resolution <= max_resolution metres. An item missing either resolution value is excluded. See :meth:UmbraItem.matches_filters for the exact acquisition-property semantics (a set filter excludes items lacking that property, matching the STAC Query extension). limit: Stop after yielding this many items. max_per_task: Cap the number of items yielded from any one sar-data/tasks/<task>/ directory. Each task is a tasking campaign over the same area, so max_per_task=1 swaps the usual "every revisit of a few sites" output for "one acquisition per distinct site" -- much better diversity on a map.

Notes

When this catalog was created with a Canopy token, the search runs against Umbra's commercial STAC API instead of the open bucket. The filters mean the same thing; bbox and the date bounds are sent to the API, while product_types and area/fuzzy are applied to the returned items (exactly as they are on the open-bucket path), so the interface is identical across both archives.

get_item

get_item(item_id)

Fetch a single acquisition from the Canopy commercial archive by id.

The keyed-retrieval complement to :meth:search's listing: given a STAC item id, return that one :class:~umbra_py.UmbraItem, or None when the archive has no such item. It is implemented with the STAC API ids search extension over the same /archive/search endpoint :meth:search already POSTs to -- POST {"ids": [item_id], "limit": 1} -- so it introduces no new endpoint to guess and stays offline-testable against a mocked API, exactly like the search path. Bearer auth, the helpful 401/403 "token rejected" message and the 500 wrap are all inherited from :meth:_archive_page.

Requires a Canopy token. The open bucket is a static catalog with no id-to-item index, so a keyed lookup isn't meaningful there -- resolve an open-data item from its sidecar URL instead (:meth:UmbraItem.from_dict / umbra info <url>) or from a built index (:meth:umbra_py.CatalogIndex.get).