H3 Hexagonal Indexing — Core Concepts

H3 is Uber’s open-source hierarchical spatial indexing system that partitions Earth’s surface into hexagonal cells at 16 resolution levels. The Python h3 library exposes the full H3 API for geocoding, neighbor traversal, aggregation, and polygon operations.

Coordinate to cell

import h3

lat, lng = 40.748, -73.985
cell = h3.latlng_to_cell(lat, lng, res=9)
print(cell)  # '892a100d2c3ffff'

The cell index is a 64-bit integer encoded as a hex string. It uniquely identifies one hexagon at the given resolution.

Resolution levels

ResolutionAvg edge lengthAvg areaTypical use
01,108 km4.25M km²Continental
359 km12,393 km²Regional
58 km253 km²Metro area
71.2 km5.2 km²Neighborhood
9174 m105,332 m²City block
1125 m2,149 m²Building
133.6 m44 m²Parking space
150.5 m0.9 m²Sub-meter

Choose the resolution that matches your analysis granularity. Too fine wastes computation; too coarse loses detail.

Cell properties

# Center point of a cell
lat, lng = h3.cell_to_latlng(cell)

# Boundary vertices (for drawing the hexagon)
boundary = h3.cell_to_boundary(cell)  # list of (lat, lng) tuples

# Area in square meters
area = h3.cell_area(cell, unit="m^2")

# Resolution
res = h3.get_resolution(cell)

Neighbor traversal

# Immediate neighbors (k-ring with k=1)
neighbors = h3.grid_disk(cell, k=1)  # 7 cells (center + 6 neighbors)

# Ring only (excludes center)
ring = h3.grid_ring(cell, k=1)  # 6 cells

# Larger neighborhood
area = h3.grid_disk(cell, k=3)  # 37 cells

K-ring operations are constant-time — they use index arithmetic, not spatial queries.

Hierarchical operations

# Parent cell (coarser resolution)
parent = h3.cell_to_parent(cell, res=7)

# Children cells (finer resolution)
children = h3.cell_to_children(cell, res=11)
print(len(children))  # ~49 children (7 per level, 2 levels)

This hierarchy enables drill-down analysis: aggregate at resolution 7 for an overview, then expand to resolution 9 for detail in a specific area.

Aggregating data

The most common pattern: group location data by H3 cell and count or sum.

import pandas as pd

df = pd.read_csv("events.csv")
df["h3_cell"] = df.apply(
    lambda row: h3.latlng_to_cell(row["lat"], row["lng"], res=9),
    axis=1,
)

cell_counts = df.groupby("h3_cell").size().reset_index(name="count")

For visualization, convert cells to polygons:

import geopandas as gpd
from shapely.geometry import Polygon

cell_counts["geometry"] = cell_counts["h3_cell"].apply(
    lambda c: Polygon(h3.cell_to_boundary(c))
)
gdf = gpd.GeoDataFrame(cell_counts, geometry="geometry", crs="EPSG:4326")

Polyfill: covering a polygon with hexagons

# GeoJSON polygon defining an area of interest
polygon = {
    "type": "Polygon",
    "coordinates": [[
        [-73.99, 40.75], [-73.95, 40.75],
        [-73.95, 40.70], [-73.99, 40.70], [-73.99, 40.75]
    ]]
}

cells = h3.polygon_to_cells(
    h3.LatLngPoly(polygon["coordinates"][0]),
    res=9,
)
print(len(cells))  # cells covering the polygon

Common misconception

H3 cells are not perfect hexagons everywhere. Due to the icosahedral projection, 12 cells at each resolution are pentagons instead of hexagons. These pentagons sit at the vertices of the underlying icosahedron and rarely appear in practical analysis (they fall in remote ocean areas), but code should handle them gracefully.

The one thing to remember: H3 gives every spot on Earth a hexagonal address at any zoom level — group by that address to instantly aggregate, compare, and visualize spatial data without defining custom boundaries.

pythonh3hexagonal-indexinggeospatial

See Also

  • Python Adaptive Learning Systems How Python builds learning apps that adjust to each student like a personal tutor who knows exactly what you need next.
  • Python Airflow Learn Airflow as a timetable manager that makes sure data tasks run in the right order every day.
  • Python Altair Learn Altair through the idea of drawing charts by describing rules, not by hand-placing every visual element.
  • Python Automated Grading How Python grades homework and exams automatically, from simple answer keys to understanding written essays.
  • Python Batch Vs Stream Processing Batch processing is like doing laundry once a week; stream processing is like a self-cleaning shirt that cleans itself constantly.