Python bindings for H3, a hierarchical hexagonal geospatial indexing system
84
Operations for working with directed edges between adjacent H3 cells. H3 directed edges represent connections between neighboring cells and enable analysis of cell boundaries, adjacency relationships, and edge-based operations.
Create and validate H3 directed edges between adjacent cells.
def cells_to_directed_edge(origin: str, destination: str) -> str:
"""
Create a directed edge between two adjacent H3 cells.
Creates an H3 directed edge identifier representing the connection
from origin cell to destination cell.
Args:
origin: Starting H3 cell identifier
destination: Ending H3 cell identifier
Returns:
H3 directed edge identifier
Raises:
H3CellInvalidError: If either cell identifier is invalid
H3NotNeighborsError: If cells are not adjacent neighbors
H3ResMismatchError: If cells have different resolutions
Note:
Cells must be immediate neighbors (grid_distance = 1).
Both cells must be at the same resolution.
Edge direction matters: edge(A,B) ≠ edge(B,A).
"""
def is_valid_directed_edge(edge: str) -> bool:
"""
Check if an H3 directed edge identifier is valid.
Args:
edge: H3 directed edge identifier (string or int)
Returns:
True if valid H3 directed edge, False otherwise
Note:
Returns False for any input that cannot be parsed as H3 edge,
including H3 cells or vertices.
"""Extract information from H3 directed edges.
def directed_edge_to_cells(e: str) -> tuple[str, str]:
"""
Get the origin and destination cells from a directed edge.
Args:
e: H3 directed edge identifier
Returns:
Tuple of (origin_cell, destination_cell)
Raises:
H3DirEdgeInvalidError: If e is not a valid H3 directed edge
Note:
This is the inverse operation of cells_to_directed_edge().
"""
def get_directed_edge_origin(e: str) -> str:
"""
Get the origin cell from a directed edge.
Args:
e: H3 directed edge identifier
Returns:
Origin H3 cell identifier
Raises:
H3DirEdgeInvalidError: If e is not a valid H3 directed edge
"""
def get_directed_edge_destination(e: str) -> str:
"""
Get the destination cell from a directed edge.
Args:
e: H3 directed edge identifier
Returns:
Destination H3 cell identifier
Raises:
H3DirEdgeInvalidError: If e is not a valid H3 directed edge
"""Find all directed edges associated with a cell.
def origin_to_directed_edges(origin: str) -> list[str]:
"""
Get all directed edges starting from an origin cell.
Returns edges from the origin cell to each of its neighbors.
Args:
origin: H3 cell identifier
Returns:
List of H3 directed edge identifiers starting from origin.
Order is not guaranteed.
Raises:
H3CellInvalidError: If origin is not a valid H3 cell
Note:
Hexagon cells return 6 edges, pentagon cells return 5 edges.
Each edge connects to one of the cell's immediate neighbors.
"""Extract geometric information from directed edges.
def directed_edge_to_boundary(edge: str) -> tuple[tuple[float, float], ...]:
"""
Get the boundary points of a directed edge.
Returns the line segments that form the edge boundary between
two adjacent cells.
Args:
edge: H3 directed edge identifier
Returns:
Tuple of (lat, lng) coordinate pairs defining the edge boundary.
Typically returns 2 points (start and end of the edge line).
Raises:
H3DirEdgeInvalidError: If edge is not a valid H3 directed edge
Note:
Points are ordered from origin cell boundary toward destination cell.
The edge represents the shared boundary between the two cells.
"""import h3
# Create two adjacent cells
origin = h3.latlng_to_cell(37.7749, -122.4194, 9)
neighbors = h3.grid_ring(origin, k=1)
destination = neighbors[0] # Pick first neighbor
print(f"Origin: {origin}")
print(f"Destination: {destination}")
# Verify they are neighbors
is_neighbor = h3.are_neighbor_cells(origin, destination)
print(f"Are neighbors: {is_neighbor}")
# Create directed edge
edge = h3.cells_to_directed_edge(origin, destination)
print(f"Directed edge: {edge}")
# Validate the edge
is_valid = h3.is_valid_directed_edge(edge)
print(f"Edge is valid: {is_valid}")import h3
# Start with a known edge
origin = h3.latlng_to_cell(40.7589, -73.9851, 8) # NYC
all_edges = h3.origin_to_directed_edges(origin)
edge = all_edges[0] # Pick first edge
print(f"Working with edge: {edge}")
# Extract components
extracted_origin = h3.get_directed_edge_origin(edge)
extracted_dest = h3.get_directed_edge_destination(edge)
print(f"Extracted origin: {extracted_origin}")
print(f"Extracted destination: {extracted_dest}")
print(f"Origin matches: {origin == extracted_origin}")
# Use combined extraction
origin_dest = h3.directed_edge_to_cells(edge)
print(f"Combined extraction: {origin_dest}")
print(f"Matches individual: {(extracted_origin, extracted_dest) == origin_dest}")
# Verify round-trip
reconstructed_edge = h3.cells_to_directed_edge(extracted_origin, extracted_dest)
print(f"Reconstructed edge: {reconstructed_edge}")
print(f"Round-trip success: {edge == reconstructed_edge}")import h3
# Analyze edges for different cell types
cells = [
h3.latlng_to_cell(37.7749, -122.4194, 7), # Regular hexagon
h3.get_pentagons(7)[0] # Pentagon at same resolution
]
for i, cell in enumerate(cells):
cell_type = "pentagon" if h3.is_pentagon(cell) else "hexagon"
print(f"\nCell {i+1} ({cell_type}): {cell}")
# Get all outgoing edges
edges = h3.origin_to_directed_edges(cell)
print(f" Outgoing edges: {len(edges)}")
# Analyze each edge
for j, edge in enumerate(edges):
dest = h3.get_directed_edge_destination(edge)
print(f" Edge {j}: {edge} -> {dest}")
# Verify neighbor relationship
is_neighbor = h3.are_neighbor_cells(cell, dest)
assert is_neighbor, f"Edge destination should be neighbor"
# Expected: hexagon has 6 edges, pentagon has 5 edges
expected_count = 5 if h3.is_pentagon(cell) else 6
print(f" Expected edges: {expected_count}, actual: {len(edges)}")
assert len(edges) == expected_countimport h3
# Create an edge and examine its geometry
center = h3.latlng_to_cell(51.5074, -0.1278, 9) # London
neighbors = h3.grid_ring(center, k=1)
edge = h3.cells_to_directed_edge(center, neighbors[0])
print(f"Analyzing edge: {edge}")
# Get edge boundary
boundary = h3.directed_edge_to_boundary(edge)
print(f"Edge boundary points: {len(boundary)}")
for i, (lat, lng) in enumerate(boundary):
print(f" Point {i}: {lat:.6f}, {lng:.6f}")
# Compare with cell boundaries
origin_boundary = h3.cell_to_boundary(center)
dest_boundary = h3.cell_to_boundary(neighbors[0])
print(f"\nOrigin cell boundary: {len(origin_boundary)} points")
print(f"Destination cell boundary: {len(dest_boundary)} points")
# Edge boundary should be part of both cell boundaries
print(f"\nEdge represents shared boundary between cells")import h3
# Build a local edge network
center = h3.latlng_to_cell(37.7749, -122.4194, 8)
region = h3.grid_disk(center, k=2)
print(f"Analyzing edge network for {len(region)} cells")
# Collect all edges within the region
all_edges = []
edge_count_by_cell = {}
for cell in region:
edges = h3.origin_to_directed_edges(cell)
# Filter edges to only include those within our region
internal_edges = []
for edge in edges:
dest = h3.get_directed_edge_destination(edge)
if dest in region:
internal_edges.append(edge)
all_edges.extend(internal_edges)
edge_count_by_cell[cell] = len(internal_edges)
print(f"Total internal edges: {len(all_edges)}")
# Analyze edge distribution
edge_counts = list(edge_count_by_cell.values())
print(f"Edge count per cell - min: {min(edge_counts)}, max: {max(edge_counts)}, avg: {sum(edge_counts)/len(edge_counts):.1f}")
# Verify each edge connects cells within region
print("\nValidating edge network:")
valid_edges = 0
for edge in all_edges:
origin, dest = h3.directed_edge_to_cells(edge)
if origin in region and dest in region:
valid_edges += 1
print(f"Valid internal edges: {valid_edges}/{len(all_edges)}")import h3
# Analyze bidirectional relationships
cell_a = h3.latlng_to_cell(40.7589, -73.9851, 9)
neighbors = h3.grid_ring(cell_a, k=1)
cell_b = neighbors[0]
print(f"Cell A: {cell_a}")
print(f"Cell B: {cell_b}")
# Create edges in both directions
edge_a_to_b = h3.cells_to_directed_edge(cell_a, cell_b)
edge_b_to_a = h3.cells_to_directed_edge(cell_b, cell_a)
print(f"A->B edge: {edge_a_to_b}")
print(f"B->A edge: {edge_b_to_a}")
print(f"Edges are different: {edge_a_to_b != edge_b_to_a}")
# Verify both edges represent the same geometric boundary
boundary_a_to_b = h3.directed_edge_to_boundary(edge_a_to_b)
boundary_b_to_a = h3.directed_edge_to_boundary(edge_b_to_a)
print(f"\nBoundary A->B: {len(boundary_a_to_b)} points")
print(f"Boundary B->A: {len(boundary_b_to_a)} points")
# Boundaries should be related (possibly reversed)
print(f"Same boundary points: {set(boundary_a_to_b) == set(boundary_b_to_a)}")
# Check all pairs of neighbors have symmetric edges
cell_edges = h3.origin_to_directed_edges(cell_a)
print(f"\nSymmetric edge verification:")
for edge in cell_edges:
neighbor = h3.get_directed_edge_destination(edge)
reverse_edge = h3.cells_to_directed_edge(neighbor, cell_a)
print(f" {cell_a} -> {neighbor}: {edge}")
print(f" {neighbor} -> {cell_a}: {reverse_edge}")
print(f" Both valid: {h3.is_valid_directed_edge(edge) and h3.is_valid_directed_edge(reverse_edge)}")import h3
# Calculate edge lengths using the edge measurement functions
center = h3.latlng_to_cell(0, 0, 10) # Equator, high resolution
edges = h3.origin_to_directed_edges(center)
print(f"Edge length analysis for resolution 10 cell at equator:")
print(f"Cell has {len(edges)} edges")
# Calculate length of each edge
edge_lengths = []
for i, edge in enumerate(edges):
length_km = h3.edge_length(edge, 'km')
length_m = h3.edge_length(edge, 'm')
edge_lengths.append(length_km)
print(f" Edge {i}: {length_km:.3f} km ({length_m:.1f} m)")
# Compare to average for this resolution
avg_edge_length = h3.average_hexagon_edge_length(10, 'km')
actual_avg = sum(edge_lengths) / len(edge_lengths)
print(f"\nAverage edge length (H3 system): {avg_edge_length:.3f} km")
print(f"Average edge length (this cell): {actual_avg:.3f} km")
print(f"Match: {abs(avg_edge_length - actual_avg) < 0.001}")
# Variation in edge lengths (should be minimal for regular hexagon)
max_length = max(edge_lengths)
min_length = min(edge_lengths)
variation = (max_length - min_length) / avg_edge_length
print(f"Edge length variation: {variation:.1%}")Install 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