Python bindings for H3, a hierarchical hexagonal geospatial indexing system
84
Functions for navigating the hexagonal grid system, including distance calculations, finding neighboring cells, and pathfinding between cells. H3's hexagonal grid enables efficient spatial queries and navigation operations.
Calculate grid distance between cells in the hexagonal coordinate system.
def grid_distance(h1: str, h2: str) -> int:
"""
Calculate grid distance between two H3 cells.
Grid distance is the minimum number of grid steps needed to reach
one cell from another, following adjacent cell connections.
Args:
h1: First H3 cell identifier
h2: Second H3 cell identifier
Returns:
Grid distance as integer (minimum steps between cells)
Raises:
H3CellInvalidError: If either cell identifier is invalid
H3GridNavigationError: If cells are too far apart to compute distance
Note:
Both cells must be at the same resolution.
Maximum computable distance depends on resolution but is typically
several thousand grid steps.
"""Find cells within a specified grid distance, creating disk and ring patterns.
def grid_disk(h: str, k: int = 1) -> list[str]:
"""
Get all cells within grid distance k from origin cell (filled disk).
Returns the origin cell plus all cells reachable within k grid steps,
forming a filled hexagonal pattern.
Args:
h: Origin H3 cell identifier
k: Maximum grid distance (default 1 for immediate neighbors)
Returns:
List of H3 cell identifiers including origin and all cells within distance k.
Order is not guaranteed.
Raises:
H3CellInvalidError: If h is not a valid H3 cell
H3GridNavigationError: If k is too large or operation fails
Note:
k=0 returns just the origin cell [h]
k=1 returns origin + 6 immediate neighbors (7 total)
k=2 returns origin + 6 + 12 neighbors (19 total)
Cell count follows pattern: 3k² + 3k + 1
"""
def grid_ring(h: str, k: int = 1) -> list[str]:
"""
Get all cells at exactly grid distance k from origin cell (hollow ring).
Returns only cells that are exactly k grid steps away, forming
a hexagonal ring around the origin.
Args:
h: Origin H3 cell identifier
k: Exact grid distance (default 1)
Returns:
List of H3 cell identifiers at distance k from origin.
Order is not guaranteed.
Raises:
H3CellInvalidError: If h is not a valid H3 cell
H3GridNavigationError: If k is too large or operation fails
Note:
k=0 returns just the origin cell [h]
k=1 returns 6 immediate neighbors
k=2 returns 12 cells in the second ring
Ring size follows pattern: 6k for k > 0
"""Check if two cells are adjacent neighbors.
def are_neighbor_cells(h1: str, h2: str) -> bool:
"""
Check if two H3 cells are immediate neighbors.
Two cells are neighbors if they share an edge (grid distance = 1).
Args:
h1: First H3 cell identifier
h2: Second H3 cell identifier
Returns:
True if cells are immediate neighbors, False otherwise
Raises:
H3CellInvalidError: If either cell identifier is invalid
Note:
Cells must be at the same resolution.
Each hexagon has exactly 6 neighbors.
Each pentagon has exactly 5 neighbors.
"""Find paths between cells in the hexagonal grid.
def grid_path_cells(start: str, end: str) -> list[str]:
"""
Find a path of cells from start to end cell.
Returns an ordered sequence of adjacent cells forming a minimum-length
path from start to end. The path includes both start and end cells.
Args:
start: Starting H3 cell identifier
end: Ending H3 cell identifier
Returns:
Ordered list of H3 cell identifiers from start to end.
First cell is start, last cell is end.
Raises:
H3CellInvalidError: If either cell identifier is invalid
H3GridNavigationError: If path cannot be computed (cells too far apart)
Note:
Cells must be at the same resolution.
Path length equals grid_distance(start, end) + 1.
Multiple valid paths may exist; this returns one of minimum length.
"""import h3
# Create a cell and find its neighbors
origin = h3.latlng_to_cell(37.7749, -122.4194, 9)
print(f"Origin cell: {origin}")
# Get immediate neighbors (k=1)
neighbors = h3.grid_disk(origin, k=1)
print(f"Cell + neighbors: {len(neighbors)} cells") # 7 cells (1 + 6 neighbors)
# Get just the neighboring ring
ring = h3.grid_ring(origin, k=1)
print(f"Neighbor ring: {len(ring)} cells") # 6 cells
# Test if specific cells are neighbors
neighbor = ring[0] # Pick first neighbor
is_neighbor = h3.are_neighbor_cells(origin, neighbor)
print(f"Are neighbors: {is_neighbor}") # True
# Calculate distance
distance = h3.grid_distance(origin, neighbor)
print(f"Grid distance: {distance}") # 1import h3
origin = h3.latlng_to_cell(40.7589, -73.9851, 8) # NYC
# Analyze expanding rings
for k in range(5):
disk = h3.grid_disk(origin, k)
ring = h3.grid_ring(origin, k) if k > 0 else [origin]
print(f"k={k}: disk={len(disk)} cells, ring={len(ring)} cells")
# Verify the mathematical relationship
expected_disk_size = 3 * k * k + 3 * k + 1
expected_ring_size = 6 * k if k > 0 else 1
assert len(disk) == expected_disk_size
assert len(ring) == expected_ring_size
# Output:
# k=0: disk=1 cells, ring=1 cells
# k=1: disk=7 cells, ring=6 cells
# k=2: disk=19 cells, ring=12 cells
# k=3: disk=37 cells, ring=18 cells
# k=4: disk=61 cells, ring=24 cellsimport h3
# Create start and end points
start_cell = h3.latlng_to_cell(37.7749, -122.4194, 9) # San Francisco
end_cell = h3.latlng_to_cell(37.7849, -122.4094, 9) # Slightly northeast
# Calculate distance
distance = h3.grid_distance(start_cell, end_cell)
print(f"Grid distance: {distance} steps")
# Find a path
path = h3.grid_path_cells(start_cell, end_cell)
print(f"Path length: {len(path)} cells")
print(f"Path distance matches: {len(path) - 1 == distance}") # True
# Verify path integrity
for i in range(len(path) - 1):
current = path[i]
next_cell = path[i + 1]
assert h3.are_neighbor_cells(current, next_cell), f"Path broken at step {i}"
print("Path verified: all consecutive cells are neighbors")
# Print path coordinates
print("\nPath coordinates:")
for i, cell in enumerate(path):
lat, lng = h3.cell_to_latlng(cell)
print(f" Step {i}: {cell} -> {lat:.6f}, {lng:.6f}")import h3
# Find all cells within 3km of a point (approximate)
center_lat, center_lng = 51.5074, -0.1278 # London
resolution = 8 # ~500m edge length
center_cell = h3.latlng_to_cell(center_lat, center_lng, resolution)
# Experiment with different k values to find ~3km coverage
# At resolution 8, each cell is ~500m across, so k=6 gives ~3km radius
coverage_cells = h3.grid_disk(center_cell, k=6)
print(f"Coverage area: {len(coverage_cells)} cells")
print(f"Approximate area: {len(coverage_cells) * 0.25:.1f} km²")
# Rough estimate: each res-8 cell is ~0.25 km²
# Get the boundary cells only (perimeter)
perimeter = h3.grid_ring(center_cell, k=6)
print(f"Perimeter: {len(perimeter)} cells")
# Convert coverage to lat/lng boundaries for visualization
boundary_points = []
for cell in coverage_cells:
boundary = h3.cell_to_boundary(cell)
boundary_points.extend(boundary)
print(f"Total boundary points: {len(boundary_points)}")import h3
import time
# Large grid operations can be expensive
origin = h3.latlng_to_cell(0, 0, 7) # Equator, resolution 7
# Time expanding disk operations
for k in [5, 10, 15, 20]:
start_time = time.time()
try:
disk = h3.grid_disk(origin, k)
elapsed = time.time() - start_time
print(f"k={k}: {len(disk)} cells in {elapsed:.3f}s")
except Exception as e:
print(f"k={k}: Failed - {e}")
# Note: Very large k values may fail or be slow
# Consider breaking large areas into smaller chunksInstall with Tessl CLI
npx tessl i tessl/pypi-h3docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10