Fetch and stream grid data
You are viewing in-progress documentation for v2 (Beta). Switch to the stable version for the current production release.
A grid’s raster values are read back per band, per chunk. Large grids are tiled into chunks so you can stream them without pulling the whole array at once; you fetch each chunk and place it into the full array using the chunk’s offset. This guide walks that loop.
Prerequisites
Section titled “Prerequisites”-
An API key: my-api-key.
-
A domain and a completed grid: your-domain-id and your-grid-id — e.g. the fuel-load grid from Build a surface fuel grid from LANDFIRE.
Step 1 — Discover the chunk layout
Section titled “Step 1 — Discover the chunk layout”GET the grid. Two fields drive the rest: georeference.shape (the full
(height, width)) and chunks.count (how many chunks to fetch per band).
curl -X 'GET' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/your-grid-id' \ -H 'accept: application/json' \ -H 'api-key: my-api-key'{ "id": "your-grid-id", "domain_id": "your-domain-id", "status": "completed", "bands": [ "fuel_load.1hr", "fuel_load.10hr", "fuel_load.100hr", "fuel_load.live_herb", "fuel_load.live_woody", "fuel_depth" ], "chunks": { "shape": [512, 512], "count": 1, "count_by_axis": { "x": 1, "y": 1 } }}bands lists the band keys you can request. chunks.count here is 1 (this
grid fits in a single tile); a larger grid reports more, laid out
count_by_axis.
Step 2 — Fetch a band’s chunk
Section titled “Step 2 — Fetch a band’s chunk”GET /grids/{{GRID_ID}}/data/{band}/{chunk_index}. The response carries the
chunk’s own shape, an offset into the full array, the chunk’s affine
transform, and the values.
curl -X 'GET' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/your-grid-id/data/fuel_load.1hr/0' \ -H 'accept: application/json' \ -H 'api-key: my-api-key'{ "shape": [30, 45], "order": "C", "metadata": { "index": 0, "shape": [30, 45], "offset": [0, 0], "transform": [ 29.438767164252283, 0.0, 720227.9398802927, 0.0, -29.438767164262632, 5190646.487014395 ] }, "data": { "format": "dense", "values": [ 1.3001821041107178, 0.2129608541727066, 0.2129608541727066, 1.3001821041107178, 1.3001821041107178, 0.2129608541727066, 0.2129608541727066, 0.02241693250834942, 0.11208466440439224, 0.11208466440439224, 0.11208466440439224, 0.11208466440439224 ] }}data.values is the real chunk data — a flat array of shape[0] × shape[1]
values in order ("C", row-major). It’s shown abridged above; the full
chunk here is 30 × 45 = 1350 floats. Two formats:
dense—valuesholds every cell, in order.sparse—valuesholds only the cells that differ fromfill_value, paired withindices. Reconstruct by filling withfill_valuethen scatteringvaluesintoindices. The API uses this automatically when a chunk is mostly one value (e.g. a masked grid that’s largely zero).
Step 3 — Iterate chunks and reassemble
Section titled “Step 3 — Iterate chunks and reassemble”For each band, loop chunk_index from 0 to chunks.count - 1, and drop each
chunk into the full array at its offset:
import numpy as npimport requests
API_KEY = "my-api-key"DOMAIN_ID = "your-domain-id"GRID_ID = "your-grid-id"BAND = "fuel_load.1hr"BASE = "https://api-v2-prod-nyvjyh5ywa-uw.a.run.app"HEADERS = {"api-key": API_KEY}
# 1. Read the grid to learn its full shape and how many chunks it has.grid = requests.get( f"{BASE}/domains/{DOMAIN_ID}/grids/{GRID_ID}", headers=HEADERS).json()height, width = grid["georeference"]["shape"]chunk_count = grid["chunks"]["count"]
# 2. Fetch each chunk and place it into the full array using its offset.full = np.full((height, width), np.nan, dtype="float32")for i in range(chunk_count): chunk = requests.get( f"{BASE}/domains/{DOMAIN_ID}/grids/{GRID_ID}/data/{BAND}/{i}", headers=HEADERS, ).json() ch, cw = chunk["shape"] row0, col0 = chunk["metadata"]["offset"] data = chunk["data"] if data["format"] == "dense": tile = np.array(data["values"], dtype="float32").reshape((ch, cw)) else: # sparse: a fill value plus explicit (index, value) pairs tile = np.full((ch, cw), data["fill_value"], dtype="float32") tile.flat[data["indices"]] = data["values"] full[row0 : row0 + ch, col0 : col0 + cw] = tile
print(full.shape, np.nanmin(full), np.nanmax(full)) # (30, 45) 0.0 1.30018...Common pitfalls
Section titled “Common pitfalls”- Forgetting it’s per band. Each
data/{band}/{chunk_index}call returns one band. Loop overbands(from step 1) as well as over chunks. - Ignoring
offset. Concatenating chunks in fetch order mis-places them. Always position a chunk with itsmetadata.offset— that’s what makes the reassembled array correct for multi-chunk grids. - Assuming dense. Handle both
denseandsparse— the format can vary by chunk, so branch ondata.formatrather than assuming. - Grid not
completed. Data is only readable once the grid finishes;chunksisnulland there’s nothing to fetch while it’s pending.