H3 Export Demo¶
This notebook demonstrates TerraFlow's H3-indexed export workflow.
H3 is Uber's hierarchical hexagonal geospatial indexing system. By converting TerraFlow suitability results to H3 cells, you can:
- Directly visualize results in H3-native tools such as DeckGL and Kepler.gl
- Join with other H3-indexed datasets (land use, population, climate normals)
- Aggregate at multiple resolutions without reprojection
TerraFlow uses the H3 v4 API (h3.latlng_to_cell). Install the optional extra with:
pip install terraflow-agro[h3]
In [1]:
Copied!
try:
import h3
except ImportError:
raise ImportError(
"h3 is required for this notebook. Install it with: pip install terraflow-agro[h3]"
)
import pandas as pd
import numpy as np
from terraflow.export import to_h3
# Synthetic features DataFrame mimicking TerraFlow pipeline output
rng = np.random.default_rng(42)
n = 10
features_df = pd.DataFrame({
"lat": rng.uniform(39.9, 40.1, n),
"lon": rng.uniform(-100.1, -99.9, n),
"score": rng.uniform(0.2, 0.9, n),
"v_index": rng.uniform(0.0, 25.0, n),
"mean_temp": rng.uniform(10.0, 30.0, n),
"total_rain": rng.uniform(50.0, 300.0, n),
"label": rng.choice(["Low", "Medium", "High"], n),
})
print(f"Synthetic features: {len(features_df)} rows")
features_df.head()
try:
import h3
except ImportError:
raise ImportError(
"h3 is required for this notebook. Install it with: pip install terraflow-agro[h3]"
)
import pandas as pd
import numpy as np
from terraflow.export import to_h3
# Synthetic features DataFrame mimicking TerraFlow pipeline output
rng = np.random.default_rng(42)
n = 10
features_df = pd.DataFrame({
"lat": rng.uniform(39.9, 40.1, n),
"lon": rng.uniform(-100.1, -99.9, n),
"score": rng.uniform(0.2, 0.9, n),
"v_index": rng.uniform(0.0, 25.0, n),
"mean_temp": rng.uniform(10.0, 30.0, n),
"total_rain": rng.uniform(50.0, 300.0, n),
"label": rng.choice(["Low", "Medium", "High"], n),
})
print(f"Synthetic features: {len(features_df)} rows")
features_df.head()
Synthetic features: 10 rows
Out[1]:
| lat | lon | score | v_index | mean_temp | total_rain | label | |
|---|---|---|---|---|---|---|---|
| 0 | 40.054791 | -100.025840 | 0.730661 | 18.619054 | 18.743038 | 99.977051 | Medium |
| 1 | 39.987776 | -99.914647 | 0.448168 | 24.187743 | 26.653564 | 51.840567 | High |
| 2 | 40.071720 | -99.971227 | 0.879489 | 8.145634 | 24.005302 | 246.731094 | Medium |
| 3 | 40.039474 | -99.935448 | 0.825185 | 9.261493 | 16.247333 | 216.212714 | Medium |
| 4 | 39.918835 | -100.011317 | 0.744868 | 11.738895 | 26.645196 | 226.291345 | High |
In [2]:
Copied!
# Convert to H3 cells at resolution 8 (~0.74 km² per cell)
h3_df = to_h3(features_df, resolution=8)
print(f"H3 cells at resolution 8: {len(h3_df)} unique cells from {len(features_df)} input rows")
h3_df
# Convert to H3 cells at resolution 8 (~0.74 km² per cell)
h3_df = to_h3(features_df, resolution=8)
print(f"H3 cells at resolution 8: {len(h3_df)} unique cells from {len(features_df)} input rows")
h3_df
H3 cells at resolution 8: 10 unique cells from 10 input rows
Out[2]:
| score | v_index | mean_temp | total_rain | label | |
|---|---|---|---|---|---|
| h3_cell | |||||
| 88261a249bfffff | 0.879489 | 8.145634 | 24.005302 | 246.731094 | Medium |
| 88261a25b3fffff | 0.230663 | 11.892623 | 15.766562 | 192.185299 | High |
| 88261a25dbfffff | 0.336247 | 4.736784 | 26.095287 | 245.182258 | Medium |
| 88261b431dfffff | 0.308003 | 5.672734 | 23.649910 | 84.949250 | Medium |
| 88261b5153fffff | 0.825185 | 9.261493 | 16.247333 | 216.212714 | Medium |
| 88261b5161fffff | 0.526705 | 3.248038 | 17.749568 | 164.728944 | Low |
| 88261b518bfffff | 0.448168 | 24.187743 | 26.653564 | 51.840567 | High |
| 88261b5891fffff | 0.744868 | 11.738895 | 26.645196 | 226.291345 | High |
| 88261b5a4bfffff | 0.730661 | 18.619054 | 18.743038 | 99.977051 | Medium |
| 88261b5ad1fffff | 0.678134 | 16.745350 | 12.795050 | 78.632518 | Medium |
In [3]:
Copied!
# Compare at a coarser resolution (resolution 4 ~ 1,770 km² per cell)
h3_coarse = to_h3(features_df, resolution=4)
print(f"Resolution 8: {len(h3_df)} cells")
print(f"Resolution 4: {len(h3_coarse)} cells (coarser — more rows merged per cell)")
h3_coarse
# Compare at a coarser resolution (resolution 4 ~ 1,770 km² per cell)
h3_coarse = to_h3(features_df, resolution=4)
print(f"Resolution 8: {len(h3_df)} cells")
print(f"Resolution 4: {len(h3_coarse)} cells (coarser — more rows merged per cell)")
h3_coarse
Resolution 8: 10 cells Resolution 4: 2 cells (coarser — more rows merged per cell)
Out[3]:
| score | v_index | mean_temp | total_rain | label | |
|---|---|---|---|---|---|
| h3_cell | |||||
| 84261a3ffffffff | 0.283455 | 8.314704 | 20.930925 | 218.683778 | High |
| 84261b5ffffffff | 0.642652 | 12.202368 | 20.811120 | 146.170435 | Medium |
Visualization with DeckGL / Kepler.gl¶
H3 cells can be directly consumed by H3-native visualization tools:
- DeckGL H3HexagonLayer: pass the
h3_cellindex column directly — no geometry conversion needed. Color-mapscoreto visualize suitability across the region. - Kepler.gl: import the exported Parquet as a dataset, select the H3 index column, and choose "H3" as the layer type.
- pandas-h3 / h3pandas: supports
to_h3,h3_to_geo_boundary, and resolution changes directly on DataFrames.
Because H3 uses a consistent hexagonal grid, adjacent cells always share edges — eliminating distortion artifacts common in rectangular pixel grids at high latitudes.
In [4]:
Copied!
# CLI equivalent — run this after a successful `terraflow run -c config.yml`
# !terraflow export --format h3 -c config.yml
# Override resolution:
# !terraflow export --format h3 --resolution 4 -c config.yml
print("CLI: terraflow export --format h3 -c config.yml")
print("Output: outputs/runs/<fingerprint>/h3_resolution_8.parquet")
# CLI equivalent — run this after a successful `terraflow run -c config.yml`
# !terraflow export --format h3 -c config.yml
# Override resolution:
# !terraflow export --format h3 --resolution 4 -c config.yml
print("CLI: terraflow export --format h3 -c config.yml")
print("Output: outputs/runs/<fingerprint>/h3_resolution_8.parquet")
CLI: terraflow export --format h3 -c config.yml Output: outputs/runs/<fingerprint>/h3_resolution_8.parquet