Python bindings for H3, a hierarchical hexagonal geospatial indexing system
84
Functions for calculating areas, lengths, and distances within the H3 system. These functions provide precise measurements for cells, edges, and distances using spherical geometry calculations, supporting multiple units of measurement.
Calculate the surface area of H3 cells and average areas at different resolutions.
def cell_area(h: str, unit: str = 'km^2') -> float:
"""
Calculate the surface area of a specific H3 cell.
Uses spherical geometry to compute the exact area of the cell
on the Earth's surface.
Args:
h: H3 cell identifier
unit: Unit for area result:
- 'km^2': Square kilometers (default)
- 'm^2': Square meters
- 'rads^2': Square radians
Returns:
Cell area in specified units
Raises:
H3CellInvalidError: If h is not a valid H3 cell
ValueError: If unit is not supported
Note:
Pentagons have slightly different areas than hexagons at the same resolution.
Calculation uses spherical triangulation for accuracy.
"""
def average_hexagon_area(res: int, unit: str = 'km^2') -> float:
"""
Get the average area of hexagon cells at a given resolution.
This average excludes pentagons and represents typical cell area.
Args:
res: H3 resolution (0-15)
unit: Unit for area result:
- 'km^2': Square kilometers (default)
- 'm^2': Square meters
- 'rads^2': Square radians
Returns:
Average hexagon area in specified units
Raises:
H3ResDomainError: If res < 0 or res > 15
ValueError: If unit is not supported
Note:
Pentagon areas may differ from this average.
Higher resolutions have smaller cell areas (~1/7 per resolution level).
"""Calculate the length of H3 edges and average edge lengths at different resolutions.
def edge_length(e: str, unit: str = 'km') -> float:
"""
Calculate the length of a specific H3 directed edge.
Uses spherical geometry to compute the exact length of the edge
on the Earth's surface.
Args:
e: H3 directed edge identifier
unit: Unit for length result:
- 'km': Kilometers (default)
- 'm': Meters
- 'rads': Radians
Returns:
Edge length in specified units
Raises:
H3DirEdgeInvalidError: If e is not a valid H3 directed edge
ValueError: If unit is not supported
Note:
Edge lengths may vary slightly within a resolution due to
spherical projection effects and pentagon locations.
"""
def average_hexagon_edge_length(res: int, unit: str = 'km') -> float:
"""
Get the average edge length of hexagon cells at a given resolution.
This average excludes pentagon edges and represents typical edge length.
Args:
res: H3 resolution (0-15)
unit: Unit for length result:
- 'km': Kilometers (default)
- 'm': Meters
- 'rads': Radians
Returns:
Average hexagon edge length in specified units
Raises:
H3ResDomainError: If res < 0 or res > 15
ValueError: If unit is not supported
Note:
Pentagon edge lengths may differ from this average.
Higher resolutions have shorter edges (~1/√7 ≈ 0.378 per resolution level).
"""Calculate spherical distances between geographic points.
def great_circle_distance(
latlng1: tuple[float, float],
latlng2: tuple[float, float],
unit: str = 'km'
) -> float:
"""
Calculate the great circle (spherical) distance between two points.
Uses the haversine formula to compute the shortest distance between
two points on the Earth's surface.
Args:
latlng1: First point as (latitude, longitude) in degrees
latlng2: Second point as (latitude, longitude) in degrees
unit: Unit for distance result:
- 'km': Kilometers (default)
- 'm': Meters
- 'rads': Radians
Returns:
Spherical distance between points in specified units
Raises:
H3LatLngDomainError: If any coordinate is outside valid range
ValueError: If unit is not supported
Note:
This is the same distance calculation used internally by H3
for all spherical geometry operations.
"""import h3
# Compare cell areas across resolutions
print("Cell area comparison across resolutions:")
lat, lng = 37.7749, -122.4194 # San Francisco
for res in range(0, 11, 2): # Every other resolution
cell = h3.latlng_to_cell(lat, lng, res)
# Get actual cell area
area_km2 = h3.cell_area(cell, 'km^2')
area_m2 = h3.cell_area(cell, 'm^2')
# Compare to system average
avg_area = h3.average_hexagon_area(res, 'km^2')
cell_type = "pentagon" if h3.is_pentagon(cell) else "hexagon"
print(f"Resolution {res:2d} ({cell_type:7}): {area_km2:10.3f} km² ({area_m2:12,.0f} m²)")
print(f" Average: {avg_area:10.3f} km² (ratio: {area_km2/avg_area:.3f})")
print()
# Show area scaling between resolutions
print("Area scaling factors:")
for res in range(1, 6):
area_coarse = h3.average_hexagon_area(res-1, 'km^2')
area_fine = h3.average_hexagon_area(res, 'km^2')
scaling = area_coarse / area_fine
print(f"Resolution {res-1} -> {res}: {scaling:.2f}x smaller")import h3
# Compare pentagon and hexagon areas at the same resolution
resolution = 6
# Get pentagons and a regular hexagon
pentagons = h3.get_pentagons(resolution)
all_cells = h3.get_res0_cells()
hexagon_res0 = [cell for cell in all_cells if not h3.is_pentagon(cell)][0]
hexagon = h3.cell_to_children(hexagon_res0, resolution)[0]
print(f"Area comparison at resolution {resolution}:")
# Calculate pentagon areas
pentagon_areas = []
for i, pentagon in enumerate(pentagons[:5]): # Just first 5 pentagons
area = h3.cell_area(pentagon, 'km^2')
pentagon_areas.append(area)
print(f"Pentagon {i+1}: {area:.3f} km²")
# Calculate hexagon area
hexagon_area = h3.cell_area(hexagon, 'km^2')
print(f"Hexagon: {hexagon_area:.3f} km²")
# Statistics
avg_pentagon_area = sum(pentagon_areas) / len(pentagon_areas)
system_avg = h3.average_hexagon_area(resolution, 'km^2')
print(f"\nAverage pentagon area: {avg_pentagon_area:.3f} km²")
print(f"System average (hexagon): {system_avg:.3f} km²")
print(f"Pentagon vs hexagon ratio: {avg_pentagon_area / hexagon_area:.3f}")
print(f"Pentagon vs system avg: {avg_pentagon_area / system_avg:.3f}")import h3
# Analyze edge lengths for different cell types
resolution = 8
# Get a regular hexagon
center = h3.latlng_to_cell(0, 0, resolution) # Equator
pentagon = h3.get_pentagons(resolution)[0]
print(f"Edge length analysis at resolution {resolution}:")
# Analyze hexagon edges
hex_edges = h3.origin_to_directed_edges(center)
hex_edge_lengths = []
print(f"\nHexagon edges ({len(hex_edges)}):")
for i, edge in enumerate(hex_edges):
length_km = h3.edge_length(edge, 'km')
length_m = h3.edge_length(edge, 'm')
hex_edge_lengths.append(length_km)
print(f" Edge {i}: {length_km:.3f} km ({length_m:.0f} m)")
# Analyze pentagon edges
pent_edges = h3.origin_to_directed_edges(pentagon)
pent_edge_lengths = []
print(f"\nPentagon edges ({len(pent_edges)}):")
for i, edge in enumerate(pent_edges):
length_km = h3.edge_length(edge, 'km')
length_m = h3.edge_length(edge, 'm')
pent_edge_lengths.append(length_km)
print(f" Edge {i}: {length_km:.3f} km ({length_m:.0f} m)")
# Compare to system averages
system_avg = h3.average_hexagon_edge_length(resolution, 'km')
hex_avg = sum(hex_edge_lengths) / len(hex_edge_lengths)
pent_avg = sum(pent_edge_lengths) / len(pent_edge_lengths)
print(f"\nComparison:")
print(f"System average: {system_avg:.3f} km")
print(f"Hexagon average: {hex_avg:.3f} km (variation: {abs(hex_avg - system_avg) / system_avg:.1%})")
print(f"Pentagon average: {pent_avg:.3f} km (vs system: {pent_avg / system_avg:.3f})")import h3
# Calculate distances between famous landmarks
landmarks = {
"San Francisco": (37.7749, -122.4194),
"New York": (40.7589, -73.9851),
"London": (51.5074, -0.1278),
"Tokyo": (35.6762, 139.6503),
"Sydney": (-33.8688, 151.2093)
}
print("Great circle distances between major cities:")
cities = list(landmarks.keys())
for i in range(len(cities)):
for j in range(i+1, len(cities)):
city1, city2 = cities[i], cities[j]
coord1, coord2 = landmarks[city1], landmarks[city2]
# Calculate distance in different units
dist_km = h3.great_circle_distance(coord1, coord2, 'km')
dist_m = h3.great_circle_distance(coord1, coord2, 'm')
dist_rads = h3.great_circle_distance(coord1, coord2, 'rads')
print(f"{city1:12} - {city2:12}: {dist_km:7.0f} km ({dist_m:10,.0f} m, {dist_rads:.4f} rads)")
# Verify against H3 cell center distances
print(f"\nVerification using H3 cell centers:")
resolution = 4 # Coarse resolution for global coverage
sf_cell = h3.latlng_to_cell(*landmarks["San Francisco"], resolution)
ny_cell = h3.latlng_to_cell(*landmarks["New York"], resolution)
sf_center = h3.cell_to_latlng(sf_cell)
ny_center = h3.cell_to_latlng(ny_cell)
direct_dist = h3.great_circle_distance(landmarks["San Francisco"], landmarks["New York"], 'km')
cell_dist = h3.great_circle_distance(sf_center, ny_center, 'km')
print(f"SF-NY direct: {direct_dist:.0f} km")
print(f"SF-NY via H3 cells (res {resolution}): {cell_dist:.0f} km")
print(f"Difference: {abs(direct_dist - cell_dist):.0f} km ({abs(direct_dist - cell_dist) / direct_dist:.1%})")import h3
# Analyze how measurements scale across resolutions
print("H3 Resolution Scaling Analysis:")
print("Resolution | Avg Area (km²) | Avg Edge (km) | Area Ratio | Edge Ratio")
print("-" * 70)
prev_area = None
prev_edge = None
for res in range(0, 16):
avg_area = h3.average_hexagon_area(res, 'km^2')
avg_edge = h3.average_hexagon_edge_length(res, 'km')
area_ratio = prev_area / avg_area if prev_area else None
edge_ratio = prev_edge / avg_edge if prev_edge else None
print(f"{res:8d} | {avg_area:12.6f} | {avg_edge:10.6f} | "
f"{area_ratio:8.2f} | {edge_ratio:8.2f}" if area_ratio else
f"{res:8d} | {avg_area:12.6f} | {avg_edge:10.6f} | - | - ")
prev_area = avg_area
prev_edge = avg_edge
print(f"\nTheoretical scaling factors:")
print(f"Area ratio: ~7.0 (each level has ~1/7 the area)")
print(f"Edge ratio: ~√7 ≈ 2.65 (each level has ~1/√7 the edge length)")import h3
import math
# Compare H3 measurements with theoretical calculations
print("Measurement precision analysis:")
# Test at different latitudes to see projection effects
test_points = [
("Equator", 0, 0),
("Tropical", 23.5, 0), # Tropic of Cancer
("Mid-latitude", 45, 0),
("High latitude", 60, 0),
("Arctic", 80, 0)
]
resolution = 7
print(f"Resolution {resolution} analysis:")
print("Location | Cell Area (km²) | Avg Area | Ratio | Edge Length (km) | Avg Edge | Ratio")
print("-" * 95)
for name, lat, lng in test_points:
# Get cell measurements
cell = h3.latlng_to_cell(lat, lng, resolution)
cell_area = h3.cell_area(cell, 'km^2')
# Get an edge from this cell
edges = h3.origin_to_directed_edges(cell)
edge_length = h3.edge_length(edges[0], 'km')
# Compare to system averages
avg_area = h3.average_hexagon_area(resolution, 'km^2')
avg_edge = h3.average_hexagon_edge_length(resolution, 'km')
area_ratio = cell_area / avg_area
edge_ratio = edge_length / avg_edge
print(f"{name:12} | {cell_area:13.6f} | {avg_area:8.6f} | {area_ratio:.3f} | "
f"{edge_length:14.6f} | {avg_edge:8.6f} | {edge_ratio:.3f}")import h3
# Calculate total area coverage for different scenarios
print("Area coverage calculations:")
# Scenario 1: City coverage
city_center = h3.latlng_to_cell(37.7749, -122.4194, 8) # San Francisco
city_cells = h3.grid_disk(city_center, k=5)
total_area = sum(h3.cell_area(cell, 'km^2') for cell in city_cells)
avg_area = h3.average_hexagon_area(8, 'km^2')
approx_area = len(city_cells) * avg_area
print(f"City coverage (k=5 at resolution 8):")
print(f" Cells: {len(city_cells)}")
print(f" Exact total area: {total_area:.2f} km²")
print(f" Approximate area: {approx_area:.2f} km²")
print(f" Difference: {abs(total_area - approx_area):.2f} km² ({abs(total_area - approx_area) / total_area:.1%})")
# Scenario 2: Country-scale coverage
country_polygon = h3.LatLngPoly([
(49.0, -125.0), (49.0, -66.0), (25.0, -66.0), (25.0, -125.0) # Rough USA bounds
])
country_cells = h3.h3shape_to_cells(country_polygon, 4) # Coarse resolution
country_area = sum(h3.cell_area(cell, 'km^2') for cell in country_cells)
usa_actual_area = 9834000 # km² (approximate)
print(f"\nCountry coverage (USA approximation at resolution 4):")
print(f" Cells: {len(country_cells)}")
print(f" H3 calculated area: {country_area:,.0f} km²")
print(f" Actual USA area: {usa_actual_area:,.0f} km²")
print(f" Coverage ratio: {country_area / usa_actual_area:.3f}")
# Show the impact of resolution on coverage accuracy
print(f"\nResolution impact on area calculation:")
for res in [3, 4, 5, 6]:
cells = h3.h3shape_to_cells(country_polygon, res)
area = sum(h3.cell_area(cell, 'km^2') for cell in cells)
ratio = area / usa_actual_area
print(f" Resolution {res}: {len(cells):6,} cells, {area:9,.0f} km² (ratio: {ratio:.3f})")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