CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-h3

Python bindings for H3, a hierarchical hexagonal geospatial indexing system

84

0.95x
Overview
Eval results
Files

grid-navigation.mddocs/

Grid Navigation

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.

Capabilities

Distance Calculation

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.
    """

Neighbor Discovery

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
    """

Neighbor Testing

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.
    """

Pathfinding

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.
    """

Usage Examples

Basic Distance and Neighbors

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}")  # 1

Multi-Ring Analysis

import 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 cells

Pathfinding Example

import 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}")

Large Area Coverage

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)}")

Performance Considerations

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 chunks

Install with Tessl CLI

npx tessl i tessl/pypi-h3

docs

advanced-operations.md

cell-hierarchy.md

core-cell-operations.md

directed-edges.md

grid-navigation.md

index.md

measurements.md

polygon-operations.md

tile.json