> For the complete documentation index, see [llms.txt](https://satdocs.hydrosat.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://satdocs.hydrosat.com/stac-api-how-to-guides/walkthrough-common-workflows.md).

# Walkthrough: Common Workflows

{% hint style="info" %}
You can download this notebook here: <https://github.com/Hydrosat/vz-tutorials>
{% endhint %}

## 1. Import dependencies.

```python
import json
import pystac
from pystac_client import Client
```

## 2. Generate a valid API token

Visit the [Authentication](/stac-api-reference-and-specification/authentication.md) page for information on how to get a valid API token.

## 3. Define your search terms.

Let's start with a simple search of the catalog limited only by the collection of interest and the maximum total number of items.

Be patient! You may need to wait several seconds for the response to your query.

```python
collection_id = "vz-l2"
```

```python
search = catalog.search(
        collections = collection_id,
        max_items=100
    ) # Return a maximum of 100 items in collection

items_in_collection = list(search.item_collection())

print(f"Found {len(items_in_collection)} items.\n")
```

We'll write a function called `show_footprints` that uses `geopandas` to plot the bounding boxes for each item returned from our search.

**⚠️ Note:** Certain IDEs will render this map differently.

* If you're using VSCode, you'll see multiple interactive maps in this Jupyter notebook.
* If you're using Spyder, you'll need to run through entire notebook and open `search-map.html`, which is saved at the end, in a browser window.

```python
import geopandas as gpd

def show_footprints(items, color, map=None):
    gdf = gpd.GeoDataFrame.from_features(items, crs="epsg:4326")[["geometry"]]
    gdf['ID'] = [item.id for item in items]
    gdf['Date'] = [item.datetime.date().strftime('%Y-%m-%d') for item in items]
    gdf['Time (UTC)'] = [item.datetime.time().strftime('%H:%M:%S') for item in items]

    if map is None: # if this is the first call, create a new map
        return gdf.explore(color=color, style_kwds={"fillOpacity": 0.7, "weight": 1})
    else: # if we have already created a map, add to it
        return gdf.explore(m=map, color=color, style_kwds={"fillOpacity": 0.7, "weight": 1})
```

Let's try it out.

```python
items_in_collection_color = 'red'

m = show_footprints(items_in_collection, color=items_in_collection_color)
m
```

<figure><img src="/files/XZeuzPz3B8fSAJ70ijtc" alt=""><figcaption></figcaption></figure>

In the map, the red squares represent scenes available in the `vz-l2` collection.

## 3.1 Searching by area of interest

We can add more criteria to `catalog.search()` to find data that intersects a specific location.

### 3.1.1 Searching with a point geometry

We'll start by defining a point geometry. This geometry will be used as an input to `catalog.search()`. Any imagery that overlaps this point will be returned.

```python
point_geom = {'type': 'Point', 'coordinates': [116.7478, -32.7153]}
```

```python
search = catalog.search(
    collections = collection_id,
    intersects = point_geom
)

items_intersecting_point = list(search.item_collection())

print(f"Found {len(items_intersecting_point)} items.\n")
```

```
Found 1 items.
```

We'll plot the item footprint on a map, as before.

```python
items_intersecting_point_color = 'orange'
m = show_footprints(items_intersecting_point, color=items_intersecting_point_color, map=m)
m
```

<figure><img src="/files/qIZcNsh1xjqrd7s35Lmd" alt=""><figcaption></figcaption></figure>

### 3.1.2 Searching with a polygon geometry

We can use any GeoJSON geometry type with `intersects`, including a MultiPoint, LineString, MultiLineString, Polygon, or MultiPolygon. For example, we can define:

```python
poly_geom = {'type': 'Polygon', 'coordinates': [[
            [
              -115.02617069030356,
              33.51297730941181
            ],
            [
              -108.63401434955702,
              33.51297730941181
            ],
            [
              -108.63401434955702,
              39.09484428364607
            ],
            [
              -115.02617069030356,
              39.09484428364607
            ],
            [
              -115.02617069030356,
              33.51297730941181
            ]
          ]]}
```

And repeat the search:

```python
search = catalog.search(
    collections = collection_id,
    intersects = poly_geom
)

items_intersecting_poly = list(search.item_collection())

print(f"Found {len(items_intersecting_poly)} items.\n")
```

```
Found 6 items.
```

Let's plot the items we found.

```python
items_intersecting_poly_color = 'yellow'
m = show_footprints(items_intersecting_poly, color=items_intersecting_poly_color, map=m)
m
```

<figure><img src="/files/KQgmJBqKC3sp66G67XvJ" alt=""><figcaption></figcaption></figure>

### 3.1.3 Searching with a bounding box

Alternatively, we can search with a bounding box instead of using `intersects`.

```python
# [west, south, east, north]
bbox = [-123.044, 35.907, -118.834, 40.053]
```

```python
search = catalog.search(
    collections = collection_id,
    bbox = bbox
)

items_intersecting_bbox = list(search.item_collection())

print(f"Found {len(items_intersecting_bbox)} items.\n")
```

```
Found 12 items.
```

Let's map the items.

```python
items_intersecting_bbox_color = 'lime'
m = show_footprints(items_intersecting_bbox, color=items_intersecting_bbox_color, map=m)
m
```

<figure><img src="/files/cm6jbRHif7ACa7bsLLTo" alt=""><figcaption></figcaption></figure>

## 3.2. Searching by date range

We can also specify the start and end dates (and times) for the search. Let's try another search.

```python
start_date = "2025-07-01"
start_time = "T00:00:00Z"

end_date = "2025-07-15"
end_time = "T00:00:00Z"
```

```python
search = catalog.search(
    collections = collection_id,
    datetime = [start_date+start_time, end_date+end_time]
)

items_in_daterange = list(search.item_collection())

print(f"Found {len(items_in_daterange)} items.\n")
```

```
Found 6 items.
```

Again, we'll visualize the scene footprints.

```python
items_in_daterange_color = 'cyan'
m = show_footprints(items_in_daterange, color=items_in_daterange_color, map=m)
m
```

<figure><img src="/files/k7onm5VJXRVWorMriJCe" alt=""><figcaption></figcaption></figure>

## 3.3 Searching by metadata tag

Anything listed under an item's `properties` is acceptable for use as a search filter (although some are more sensible filters than others). Let's look at an individual item to see the available `properties`.

```python
items_in_daterange[0].properties
```

```
{'start_datetime': '2025-07-14T02:23:28.436021Z',
 'end_datetime': '2025-07-14T02:23:38.388531Z',
 'created': '2025-07-23T23:03:32.797Z',
 'hydrosat:scene_id': 'VZ01_L2_20250714_022333',
 'datetime': '2025-07-14T02:23:33.412276Z',
 'processing:lineage': 'Hydrosat Level-2 LST and SR processing',
 'eo:cloud_cover': 0.4135154214440202,
 'eo:snow_cover': 0,
 'hydrosat:capture_type': 'image',
 'hydrosat:day_night': 'day',
 'instruments': ['liri-v1-01', 'viri-v1-01'],
 'platform': 'vanzyl-01',
 'processing:software': {'vz-l1b': 'hydrosat.vz_l1b==0.0.0+dev-2025-07-14T16:56:16+0000',
  'vz-liri-l0': 'hydrosat.vz_liri_l0==0.18.2.dev133+g9f3cc60',
  'vz-liri-l0b': 'hydrosat.vz_liri_l0b==0.18.2.dev32+g1debc9d',
  'vz-liri-l1a': 'hydrosat.vz_liri_l1a==0.0.0+dev-2025-07-14T16:48:42+0000',
  'vz-telemetry': 'hydrosat.vz_telemetry==0.18.2.dev18+ga0564b2',
  'vz-viri-l0': 'hydrosat.vz_viri_l0==0.18.2.dev47+g16aefb1',
  'vz-viri-l1a': 'hydrosat.vz_viri_l1a==0.0.0+dev-2025-07-14T16:43:48+0000',
  'vz-l2': 'hydrosat.vz_l2==0.0.0+dev-2025-07-14T17:07:52+0000'},
 'proj:centroid': {'lat': -31.928, 'lon': 119.885},
 'proj:epsg': 32750,
 'sat:orbit_state': 'descending',
 'sat:platform_international_designator': '2024-149AN',
 'updated': '2025-07-23T23:03:32.797Z',
 'version': '0.18.1-86-gdbf5836',
 'view:azimuth': 91.194,
 'view:off_nadir': 0.167,
 'view:sun_azimuth': 28.053,
 'view:sun_elevation': 31.07}
```

Let's try it out.

We'll use the `view:off_nadir` property to constrain our search. Specifically, we only want images acquired with a predetermined off-nadir angle. To streamline our result, we'll use `sortby` to sort the items by increasing off-nadir angle. If we wanted to sort in descending order, we could substitute the "+" character in `sortby` for "-".

We'll also use the `max_items` argument to limit our search. Only that number of items with the smallest off-nadir angles in the collection will be returned.

```python
search = catalog.search(
    collections = collection_id,
    query = {"view:off_nadir": {"gte": -2, "lte": 2}},
    sortby=["+properties.view:off_nadir"],
    max_items=5
)

items_nadir = list(search.item_collection())

print(f"Found {len(items_nadir)} items.\n")
```

```
Found 5 items.
```

Time to plot.

```python
items_nadir_color = 'fuchsia'
m = show_footprints(items_nadir, color=items_nadir_color, map=m)
m.save("search-map.html")
m
```

<figure><img src="/files/Dk9GfE68VAeIJCOedrlx" alt=""><figcaption></figcaption></figure>

## 4. Summary of approaches

Whether you're interested in searching for data by AOI, date range, metadata tag, or all of the above, you can configure `catalog.search()` to find what you need.

Let's summarize the number of items we retrieved with each search above.

```python
n_items = [len(i) for i in [items_in_collection, items_intersecting_point, items_intersecting_poly, items_intersecting_bbox, items_in_daterange, items_nadir]]
colors = [items_in_collection_color, items_intersecting_point_color, items_intersecting_poly_color, items_intersecting_bbox_color, items_in_daterange_color, items_nadir_color]
```

```python
from matplotlib import pyplot as plt

plt.figure(figsize=(12,3))
plt.barh(y=range(len(n_items)), width=n_items[::-1], height=0.6,
         color=colors[::-1],
         edgecolor='k',
         zorder=2);
plt.yticks(range(len(n_items)),
          ['In collection', 'Intersects point geometry', 'Intersects polygon geometry', 'Intersects bounding box', 'In date range', 'Within ± off-nadir angle°'][::-1]);
plt.xlabel('Number of items')
plt.grid(which='major', axis='x', color='lightgray')
plt.tight_layout()
plt.show()
```

<figure><img src="/files/PIfDzv1LU66kl0Zji7gk" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://satdocs.hydrosat.com/stac-api-how-to-guides/walkthrough-common-workflows.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
