diff --git a/assets/guides/sentinel2/sandwich-harbour-true-color.webp b/assets/guides/sentinel2/sandwich-harbour-true-color.webp
new file mode 100644
index 0000000..b7ae626
Binary files /dev/null and b/assets/guides/sentinel2/sandwich-harbour-true-color.webp differ
diff --git a/changelog.mdx b/changelog.mdx
index 80f8c04..6cf00d2 100644
--- a/changelog.mdx
+++ b/changelog.mdx
@@ -39,8 +39,8 @@ mode: center
This makes it practical to move from catalog search to image processing in one workflow: find a low-cloud scene, select a band, crop it to a geographic region, and pass the resulting data into your analysis without first downloading an entire scene.
-
- Query Sentinel-2 scenes, resolve their assets, and read or download image data.
+
+ Query a Sentinel-2 scene, read RGB band windows, and display a true-color image.
diff --git a/datasets/assets-and-storage/read-and-download.mdx b/datasets/assets-and-storage/read-and-download.mdx
index 21df02a..8e57781 100644
--- a/datasets/assets-and-storage/read-and-download.mdx
+++ b/datasets/assets-and-storage/read-and-download.mdx
@@ -148,8 +148,8 @@ Asset locations can reference authentication metadata. The storage client curren
## Next steps
-
- Query Sentinel-2 and read a selected image region.
+
+ Query Sentinel-2, read RGB band windows, and display a true-color image.
Attach file references to datapoints you ingest.
diff --git a/guides/cookbook.mdx b/guides/cookbook.mdx
index 31155ec..37fd55b 100644
--- a/guides/cookbook.mdx
+++ b/guides/cookbook.mdx
@@ -21,13 +21,13 @@ export const cookbookSections = [
tags: ["Open data", "Sentinel-2", "Metadata queries", "Spatial filters"],
},
{
- title: "Access Sentinel-2 assets",
+ title: "Visualize Sentinel-2 imagery",
href: "/guides/datasets/access-sentinel2-data",
- description: "Read a COG window or download a Sentinel-2 image with the storage client.",
+ description: "Query a Sentinel-2 scene, read its RGB bands, and display a true-color image.",
icon: "magnifying-glass-location",
level: "Beginner",
time: "10 min",
- tags: ["Assets", "COG", "Sentinel-2", "Storage client"],
+ tags: ["Assets", "COG", "Sentinel-2", "True color"],
},
{
title: "Build a spatio-temporal catalog",
diff --git a/guides/datasets/access-sentinel2-data.mdx b/guides/datasets/access-sentinel2-data.mdx
index 08bbd2b..c9529e1 100644
--- a/guides/datasets/access-sentinel2-data.mdx
+++ b/guides/datasets/access-sentinel2-data.mdx
@@ -1,10 +1,10 @@
---
-title: Access Sentinel-2 assets
-description: Query Sentinel-2 metadata and read or download the corresponding image assets.
+title: Visualize Sentinel-2 imagery
+description: Query a Sentinel-2 scene, read its RGB bands, and display a true-color image.
icon: satellite
---
-Tilebox indexes Sentinel-2 metadata and asset locations in the `open_data.aws_earth.sentinel2` dataset. Query the metadata first, then use the storage client to read only the image data you need.
+Tilebox indexes Sentinel-2 metadata and asset locations in the `open_data.aws_earth.sentinel2` dataset. In this guide, you query a low-cloud scene over Sandwich Harbour in Namibia, read its RGB bands, and display a true-color image.
Asset collections and the storage client are currently available in the Python SDK.
@@ -16,86 +16,102 @@ Tilebox indexes Sentinel-2 metadata and asset locations in the `open_data.aws_ea
- You have installed the [Python SDK](/sdks/python/install) with Python 3.11 or newer.
```bash
-uv add tilebox shapely
+uv add tilebox shapely numpy matplotlib
```
## Select a Sentinel-2 datapoint
-Query a small time and area of interest, then select one low-cloud observation:
+Define a small area around the Sandwich Harbour lagoon and dune coast. Query Level-2A observations from a known clear period, sort them by scene-level cloud cover, and select the clearest result:
```python Python
from shapely import box
from tilebox.datasets import Client, field
+area_bounds = (14.42, -23.43, 14.58, -23.25) # west, south, east, north
+area = box(*area_bounds)
+
datasets = Client()
collection = datasets.dataset("open_data.aws_earth.sentinel2").collection("L2A")
scenes = collection.query(
- temporal_extent=("2025-10-01", "2025-11-01"),
- spatial_extent=box(-106.0, 38.0, -105.9, 38.1),
- filter=field("cloud_cover") < 10,
+ temporal_extent=("2024-06-17", "2024-06-18"),
+ spatial_extent=area,
+ filter=field("cloud_cover") < 1,
)
-datapoint = scenes.isel(time=0)
-print(datapoint.stac_id.item())
+datapoint = scenes.sortby("cloud_cover").isel(time=0)
+print(datapoint.stac_id.item(), datapoint.cloud_cover.item())
```
+The selected observation is `S2B_T33KVQ_20240617T090616_L2A`, acquired on June 17, 2024, with `0.008524` percent scene-level cloud cover. The cloud-cover value describes the complete Sentinel-2 tile, not only the area of interest.
+
See [Query open data metadata](/guides/datasets/query-satellite-data) for more query patterns.
-## Resolve the assets
+## Resolve the RGB assets
-Turn the selected datapoint into an asset collection. Each asset describes one file and the locations from which it can be accessed.
+Turn the selected datapoint into an asset collection, then resolve its 10-meter red, green, and blue COGs:
```python Python
from tilebox.datasets.assets import AssetCollection
assets = AssetCollection.from_datapoint(datapoint)
-
-for key, asset in assets.items():
- print(key, asset.media_type)
-
red = assets["red"]
+green = assets["green"]
+blue = assets["blue"]
```
-## Read a Cloud Optimized GeoTIFF window
+## Read the COG windows
-The Sentinel-2 image assets are Cloud Optimized GeoTIFFs (COGs). Open an image remotely and request a pixel window without downloading the complete file:
+Use the storage client to read the area of interest from each COG:
```python Python
import asyncio
-from tilebox.storage.aio import Client
+import numpy as np
+from tilebox.storage.aio import Client as StorageClient
from tilebox.storage.geotiff import window_from_bounds
-async def read_area():
- storage = Client()
- geotiff = await storage.open_geotiff(red)
- window = window_from_bounds(
- geotiff,
- (-106.0, 38.0, -105.9, 38.1),
- crs="EPSG:4326",
- )
- return await geotiff.read(window=window)
-
-pixels = asyncio.run(read_area())
-print(pixels.shape)
+async def read_rgb():
+ storage = StorageClient()
+ bands = []
+
+ for asset in (red, green, blue):
+ geotiff = await storage.open_geotiff(asset)
+ window = window_from_bounds(geotiff, area_bounds, crs="EPSG:4326")
+ raster = await geotiff.read(window=window)
+ bands.append(raster.data[0])
+
+ return np.stack(bands, axis=-1).astype(np.float32)
+
+rgb = asyncio.run(read_rgb())
```
-`window_from_bounds` transforms geographic bounds into the image coordinate system and clips the resulting window to the image.
+`window_from_bounds` converts the longitude and latitude bounds to the COG's pixel grid. Each read returns a `(2000, 1643)` array of `uint16` values; stacking the bands creates a `(2000, 1643, 3)` RGB array.
-## Download an asset
+## Display the true-color image
-Use `download` when you need the complete file locally:
+Apply one contrast stretch across all three channels to preserve their relative color balance, then display the image:
```python Python
-async def download_red_band():
- storage = Client()
- return await storage.download(red, "data/sentinel-2-red.tif")
+import matplotlib.pyplot as plt
+
+low, high = np.percentile(rgb, (2, 98))
+display_rgb = np.clip((rgb - low) / (high - low), 0, 1)
+display_rgb = display_rgb ** (1 / 1.1)
-path = asyncio.run(download_red_band())
-print(path)
+fig, ax = plt.subplots(figsize=(8, 10))
+ax.imshow(display_rgb)
+ax.set_axis_off()
+plt.tight_layout(pad=0)
+plt.show()
```
+The percentile stretch and gamma correction bring out the coastline, lagoon, and dune textures in a beautiful true-color visualization.
+
+
+
+
+
## Next steps
diff --git a/guides/datasets/query-satellite-data.mdx b/guides/datasets/query-satellite-data.mdx
index 584af04..1926443 100644
--- a/guides/datasets/query-satellite-data.mdx
+++ b/guides/datasets/query-satellite-data.mdx
@@ -60,8 +60,8 @@ print(latest.cloud_cover.item())
## Next steps
-
- Read a COG window or download an image from a selected datapoint.
+
+ Read RGB band windows and display a true-color image.
Learn more dataset query patterns.