0
# Cell Hierarchy
1
2
Operations for working with H3's hierarchical structure, including parent-child relationships, cell compaction, and resolution changes. H3's multi-resolution hierarchy enables efficient storage and analysis across different scales.
3
4
## Capabilities
5
6
### Parent-Child Relationships
7
8
Navigate up and down the hierarchical structure between different resolution levels.
9
10
```python { .api }
11
def cell_to_parent(h: str, res: int = None) -> str:
12
"""
13
Get the parent cell at a coarser resolution.
14
15
Args:
16
h: H3 cell identifier
17
res: Target parent resolution. If None, uses resolution(h) - 1
18
19
Returns:
20
Parent H3 cell identifier at target resolution
21
22
Raises:
23
H3CellInvalidError: If h is not a valid H3 cell
24
H3ResDomainError: If res < 0 or res >= resolution(h)
25
26
Note:
27
Parent resolution must be coarser (lower number) than child.
28
Each cell has exactly one parent at each coarser resolution.
29
"""
30
31
def cell_to_children(h: str, res: int = None) -> list[str]:
32
"""
33
Get all child cells at a finer resolution.
34
35
Args:
36
h: H3 cell identifier
37
res: Target child resolution. If None, uses resolution(h) + 1
38
39
Returns:
40
List of child H3 cell identifiers at target resolution
41
42
Raises:
43
H3CellInvalidError: If h is not a valid H3 cell
44
H3ResDomainError: If res > 15 or res <= resolution(h)
45
46
Note:
47
Child resolution must be finer (higher number) than parent.
48
Most cells have 7 children, but some have different counts due to
49
the spherical geometry and pentagon locations.
50
"""
51
52
def cell_to_children_size(h: str, res: int = None) -> int:
53
"""
54
Get the count of child cells at a finer resolution.
55
56
Args:
57
h: H3 cell identifier
58
res: Target child resolution. If None, uses resolution(h) + 1
59
60
Returns:
61
Number of child cells at target resolution
62
63
Raises:
64
H3CellInvalidError: If h is not a valid H3 cell
65
H3ResDomainError: If res > 15 or res <= resolution(h)
66
67
Note:
68
More efficient than len(cell_to_children(h, res)) for large child counts.
69
"""
70
71
def cell_to_center_child(h: str, res: int = None) -> str:
72
"""
73
Get the center child cell at a finer resolution.
74
75
The center child is the child cell whose center is closest to
76
the parent cell's center.
77
78
Args:
79
h: H3 cell identifier
80
res: Target child resolution. If None, uses resolution(h) + 1
81
82
Returns:
83
Center child H3 cell identifier
84
85
Raises:
86
H3CellInvalidError: If h is not a valid H3 cell
87
H3ResDomainError: If res > 15 or res <= resolution(h)
88
"""
89
```
90
91
### Child Positioning
92
93
Work with child position indices within parent cells.
94
95
```python { .api }
96
def cell_to_child_pos(child: str, res_parent: int) -> int:
97
"""
98
Get the position index of a child cell within its parent.
99
100
Args:
101
child: Child H3 cell identifier
102
res_parent: Resolution of the parent cell
103
104
Returns:
105
Integer position index of child relative to parent
106
107
Raises:
108
H3CellInvalidError: If child is not a valid H3 cell
109
H3ResDomainError: If res_parent >= resolution(child)
110
111
Note:
112
Position indices are stable: the same child always has the same
113
position within its parent across different operations.
114
"""
115
116
def child_pos_to_cell(parent: str, res_child: int, child_pos: int) -> str:
117
"""
118
Get a specific child cell by position index.
119
120
Args:
121
parent: Parent H3 cell identifier
122
res_child: Resolution of desired child cell
123
child_pos: Position index of desired child
124
125
Returns:
126
Child H3 cell identifier at specified position
127
128
Raises:
129
H3CellInvalidError: If parent is not a valid H3 cell
130
H3ResDomainError: If res_child <= resolution(parent) or res_child > 15
131
ValueError: If child_pos is outside valid range for this parent
132
133
Note:
134
Valid child_pos range is 0 to cell_to_children_size(parent, res_child) - 1.
135
"""
136
```
137
138
### Cell Compaction
139
140
Optimize cell collections by combining child cells into parents where possible.
141
142
```python { .api }
143
def compact_cells(cells: list[str]) -> list[str]:
144
"""
145
Compact a collection of cells by combining children into parents.
146
147
When all children of a parent cell are present in the input collection,
148
they are replaced by their parent cell. This process continues recursively
149
up the hierarchy until no further compaction is possible.
150
151
Args:
152
cells: Collection of H3 cell identifiers (must all be same resolution)
153
154
Returns:
155
Compacted list of H3 cell identifiers (mixed resolutions)
156
157
Raises:
158
H3ResMismatchError: If input cells have different resolutions
159
H3CellInvalidError: If any cell identifier is invalid
160
161
Note:
162
Input cells must all be at the same resolution.
163
Output may contain cells at various resolutions.
164
Compaction reduces storage and improves query performance.
165
"""
166
167
def uncompact_cells(cells: list[str], res: int) -> list[str]:
168
"""
169
Expand a collection of cells to a uniform resolution.
170
171
All cells in the collection are expanded to their children at the
172
target resolution. This reverses the compact_cells operation.
173
174
Args:
175
cells: Collection of H3 cell identifiers (mixed resolutions allowed)
176
res: Target resolution for all output cells
177
178
Returns:
179
List of H3 cell identifiers all at target resolution
180
181
Raises:
182
H3ResDomainError: If res > 15
183
H3CellInvalidError: If any cell identifier is invalid
184
ValueError: If any input cell has resolution > res
185
186
Note:
187
All input cells must have resolution <= target resolution.
188
Output cells provide complete coverage of input area at uniform resolution.
189
"""
190
```
191
192
### System Introspection
193
194
Get information about cells at specific resolutions and system structure.
195
196
```python { .api }
197
def get_res0_cells() -> list[str]:
198
"""
199
Get all H3 cells at resolution 0 (base cells).
200
201
Returns:
202
List of all 122 base H3 cells covering the Earth
203
204
Note:
205
These are the coarsest cells in the H3 system.
206
All other cells are descendants of these base cells.
207
Order is not guaranteed.
208
"""
209
210
def get_pentagons(res: int) -> list[str]:
211
"""
212
Get all pentagon cells at a given resolution.
213
214
Args:
215
res: H3 resolution (0-15)
216
217
Returns:
218
List of all 12 pentagon H3 cells at the specified resolution
219
220
Raises:
221
H3ResDomainError: If res < 0 or res > 15
222
223
Note:
224
There are exactly 12 pentagons at every resolution level.
225
All other cells at that resolution are hexagons.
226
Pentagons occur at the 12 vertices of the icosahedron.
227
"""
228
```
229
230
## Usage Examples
231
232
### Basic Parent-Child Navigation
233
234
```python
235
import h3
236
237
# Start with a high-resolution cell
238
child_cell = h3.latlng_to_cell(37.7749, -122.4194, 9)
239
print(f"Child cell (res 9): {child_cell}")
240
print(f"Resolution: {h3.get_resolution(child_cell)}")
241
242
# Get parent at resolution 7
243
parent = h3.cell_to_parent(child_cell, res=7)
244
print(f"Parent cell (res 7): {parent}")
245
246
# Get all children of the parent back at resolution 9
247
children = h3.cell_to_children(parent, res=9)
248
print(f"Parent has {len(children)} children at resolution 9")
249
print(f"Original child in children: {child_cell in children}") # True
250
251
# Get just the center child
252
center_child = h3.cell_to_center_child(parent, res=9)
253
print(f"Center child: {center_child}")
254
print(f"Center child is original: {center_child == child_cell}")
255
```
256
257
### Multi-Level Hierarchy
258
259
```python
260
import h3
261
262
# Trace a cell through multiple resolution levels
263
original = h3.latlng_to_cell(51.5074, -0.1278, 10) # London, res 10
264
265
print("Hierarchy from coarse to fine:")
266
current = original
267
268
# Go up to resolution 0
269
while h3.get_resolution(current) > 0:
270
parent = h3.cell_to_parent(current)
271
res = h3.get_resolution(parent)
272
print(f" Resolution {res}: {parent}")
273
current = parent
274
275
print(f" Resolution 0: {current} (base cell)")
276
277
# Go back down showing child counts
278
current = h3.cell_to_parent(original, res=5) # Start from res 5
279
print(f"\nChild expansion from resolution 5:")
280
281
for target_res in range(6, 11):
282
children = h3.cell_to_children(current, res=target_res)
283
print(f" Res {target_res}: {len(children)} children")
284
285
# For next iteration, use the center child
286
if target_res < 10:
287
current = h3.cell_to_center_child(current, res=target_res)
288
```
289
290
### Child Positioning
291
292
```python
293
import h3
294
295
# Work with child positions
296
parent = h3.latlng_to_cell(40.7589, -73.9851, 6) # NYC, res 6
297
children = h3.cell_to_children(parent)
298
299
print(f"Parent: {parent}")
300
print(f"Children ({len(children)}):")
301
302
# Show each child with its position
303
positions = []
304
for child in children:
305
pos = h3.cell_to_child_pos(child, res_parent=6)
306
positions.append((child, pos))
307
print(f" Position {pos}: {child}")
308
309
# Sort by position and verify we can reconstruct
310
positions.sort(key=lambda x: x[1])
311
print(f"\nReconstructing children by position:")
312
313
for child, pos in positions:
314
reconstructed = h3.child_pos_to_cell(parent, res_child=7, child_pos=pos)
315
print(f" Position {pos}: {reconstructed} (matches: {child == reconstructed})")
316
```
317
318
### Cell Compaction
319
320
```python
321
import h3
322
import random
323
324
# Create a region with some complete families of children
325
center = h3.latlng_to_cell(37.7749, -122.4194, 6)
326
region_cells = h3.grid_disk(center, k=2) # Get area around center
327
328
# Expand all to resolution 8
329
expanded = h3.uncompact_cells(region_cells, res=8)
330
print(f"Original region: {len(region_cells)} cells at res 6")
331
print(f"Expanded region: {len(expanded)} cells at res 8")
332
333
# Add some random cells at resolution 8 to create incomplete families
334
random_cells = []
335
for _ in range(20):
336
lat = 37.7749 + random.uniform(-0.1, 0.1)
337
lng = -122.4194 + random.uniform(-0.1, 0.1)
338
cell = h3.latlng_to_cell(lat, lng, 8)
339
random_cells.append(cell)
340
341
all_cells = expanded + random_cells
342
print(f"With random additions: {len(all_cells)} cells")
343
344
# Compact back down
345
compacted = h3.compact_cells(all_cells)
346
print(f"After compaction: {len(compacted)} cells")
347
348
# Verify coverage is preserved by expanding back
349
verification = h3.uncompact_cells(compacted, res=8)
350
original_set = set(all_cells)
351
verification_set = set(verification)
352
353
print(f"Coverage preserved: {original_set == verification_set}")
354
print(f"Compression ratio: {len(compacted) / len(all_cells):.2f}")
355
```
356
357
### Pentagon Analysis
358
359
```python
360
import h3
361
362
# Analyze pentagons across resolutions
363
print("Pentagon analysis:")
364
for res in range(0, 6):
365
pentagons = h3.get_pentagons(res)
366
print(f"Resolution {res}: {len(pentagons)} pentagons")
367
368
# Show some pentagon properties
369
pentagon = pentagons[0] # Pick first pentagon
370
neighbors = h3.grid_ring(pentagon, k=1)
371
372
print(f" Example pentagon {pentagon}:")
373
print(f" Has {len(neighbors)} neighbors (vs 6 for hexagons)")
374
print(f" Boundary has {len(h3.cell_to_boundary(pentagon))} vertices")
375
376
# Find pentagon children behavior
377
res0_pentagon = h3.get_pentagons(0)[0]
378
children = h3.cell_to_children(res0_pentagon, res=1)
379
print(f"\nResolution 0 pentagon has {len(children)} children at res 1")
380
381
# Compare to a hexagon at res 0
382
res0_cells = h3.get_res0_cells()
383
res0_hexagons = [cell for cell in res0_cells if not h3.is_pentagon(cell)]
384
hexagon = res0_hexagons[0]
385
hex_children = h3.cell_to_children(hexagon, res=1)
386
print(f"Resolution 0 hexagon has {len(hex_children)} children at res 1")
387
```
388
389
### Base Cell Analysis
390
391
```python
392
import h3
393
394
# Analyze the base H3 system structure
395
base_cells = h3.get_res0_cells()
396
print(f"Total base cells: {len(base_cells)}")
397
398
pentagon_count = sum(1 for cell in base_cells if h3.is_pentagon(cell))
399
hexagon_count = len(base_cells) - pentagon_count
400
401
print(f" Pentagons: {pentagon_count}")
402
print(f" Hexagons: {hexagon_count}")
403
404
# Show base cell numbers
405
print(f"\nBase cell number range:")
406
base_numbers = [h3.get_base_cell_number(cell) for cell in base_cells]
407
print(f" Min: {min(base_numbers)}")
408
print(f" Max: {max(base_numbers)}")
409
print(f" Unique count: {len(set(base_numbers))}")
410
411
# Verify all base cells are resolution 0
412
resolutions = [h3.get_resolution(cell) for cell in base_cells]
413
print(f"\nAll resolution 0: {all(res == 0 for res in resolutions)}")
414
415
# Show some base cell coverage
416
print(f"\nSample base cells with centers:")
417
for i, cell in enumerate(base_cells[:5]):
418
lat, lng = h3.cell_to_latlng(cell)
419
is_pent = "pentagon" if h3.is_pentagon(cell) else "hexagon"
420
base_num = h3.get_base_cell_number(cell)
421
print(f" Base {base_num}: {cell} -> {lat:.1f}, {lng:.1f} ({is_pent})")
422
```