https://github.com/filimoa/polars-h3
🌎 Polars H3 Geospatial Plugin
https://github.com/filimoa/polars-h3
geospatial h3 polars
Last synced: 6 months ago
JSON representation
🌎 Polars H3 Geospatial Plugin
- Host: GitHub
- URL: https://github.com/filimoa/polars-h3
- Owner: Filimoa
- License: mit
- Created: 2024-12-03T05:48:05.000Z (10 months ago)
- Default Branch: master
- Last Pushed: 2025-03-09T01:34:57.000Z (7 months ago)
- Last Synced: 2025-04-10T05:52:47.486Z (6 months ago)
- Topics: geospatial, h3, polars
- Language: Python
- Homepage: https://filimoa.github.io/polars-h3/
- Size: 1.63 MB
- Stars: 65
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
![]()
This is a [Polars](https://docs.pola.rs/) extension that adds support for the [H3 discrete global grid system](https://github.com/uber/h3/), so you can index points and geometries to hexagons directly in Polars. All credits goes to the [h3o](https://github.com/HydroniumLabs/h3o) for doing the heavy lifting.
# Highlights
- 🚀 **Blazing Fast:** Built entirely in Rust, offering vectorized, multi-core H3 operations within Polars. Ideal for high-performance data processing.
- 25X faster than [h3-py](https://github.com/uber/h3-py)
- 5X faster than [H3 DuckDB](https://github.com/isaacbrodsky/h3-duckdb) _(See [notebook](notebooks/benchmarking.ipynb) for more details)_- 🌍 **H3 Feature Parity:** Comprehensive support for H3 functions, covering almost everything the standard H3 library provides, excluding geometric functions.
- 📋 **Fully Tested:** Thoroughly tested against the standard H3 library.
- 🔍 **Data Type Agnostic:** Supports string and integer H3 indexes natively, eliminating format conversion hassles.
# Get started
You can get started by installing it with pip (or [uv](https://github.com/astral-sh/uv)):
```bash
pip install polars-h3
```You can use the extension as a drop-in replacement for the standard H3 functions.
```python
import polars_h3 as plh3
import polars as pl>>> df = pl.DataFrame(
... {
... "lat": [37.7749],
... "long": [-122.4194],
... }
... ).with_columns(
... plh3.latlng_to_cell(
... "lat",
... "long",
... resolution=7,
... return_dtype=pl.Utf8
... ).alias("h3_cell"),
... )
>>> df
shape: (1, 3)
┌─────────┬───────────┬─────────────────┐
│ lat ┆ long ┆ h3_cell │
│ --- ┆ --- ┆ --- │
│ f64 ┆ f64 ┆ str │
╞═════════╪═══════════╪═════════════════╡
│ 37.7749 ┆ -122.4194 ┆ 872830828ffffff │
└─────────┴───────────┴─────────────────┘
```Check out the [quickstart notebook](notebooks/quickstart.ipynb) for more examples.
🌟 You can also find the advanced notebooks [here](notebooks/).
# Implemented functions
This extension implements most of the [H3 API](https://h3geo.org/docs/api/indexing). The full list of functions is below - you can find full docs [here](https://filimoa.github.io/open-parse).
> ⚠️ **Performance Note:** When possible, prefer using `pl.UInt64` for H3 indices instead of the `pl.Utf8` representation. String representations require casting operations which impact performance. Working directly with the native 64-bit integer format provides better computational efficiency.
We are unable to support the functions that work with geometries.
### Full list of functions
✅ = Supported
🚧 = Pending
🛑 = Not supported| Function | Description | Supported |
| :----------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------- | :-------- |
| [`latlng_to_cell`](https://filimoa.github.io/polars-h3/api-reference/indexing/#latlng_to_cell) | Convert latitude/longitude coordinate to cell ID | ✅ |
| [`cell_to_lat`](https://filimoa.github.io/polars-h3/api-reference/indexing/#cell_to_lat) | Convert cell ID to latitude | ✅ |
| [`cell_to_lng`](https://filimoa.github.io/polars-h3/api-reference/indexing/#cell_to_lng) | Convert cell ID to longitude | ✅ |
| [`cell_to_latlng`](https://filimoa.github.io/polars-h3/api-reference/indexing/#cell_to_latlng) | Convert cell ID to latitude/longitude | ✅ |
| [`get_resolution`](https://filimoa.github.io/polars-h3/api-reference/inspection/#get_resolution) | Get resolution number of cell ID | ✅ |
| [`str_to_int`](https://filimoa.github.io/polars-h3/api-reference/inspection/#str_to_int) | Convert pl.Utf8 cell ID to pl.UInt64 | ✅ |
| [`int_to_str`](https://filimoa.github.io/polars-h3/api-reference/inspection/#int_to_str) | Convert pl.UInt64 or pl.Int64 cell ID to pl.Utf8 | ✅ |
| [`is_valid_cell`](https://filimoa.github.io/polars-h3/api-reference/inspection/#is_valid_cell) | True if this is a valid cell ID | ✅ |
| [`is_res_class_iii`](https://filimoa.github.io/polars-h3/api-reference/inspection/#is_res_class_iii) | True if the cell's resolution is class III | ✅ |
| [`is_pentagon`](https://filimoa.github.io/polars-h3/api-reference/inspection/#is_pentagon) | True if the cell is a pentagon | ✅ |
| [`get_icosahedron_faces`](https://filimoa.github.io/polars-h3/api-reference/inspection/#get_icosahedron_faces) | List of icosahedron face IDs the cell is on | ✅ |
| [`cell_to_parent`](https://filimoa.github.io/polars-h3/api-reference/inspection/#cell_to_parent) | Get coarser cell for a cell | ✅ |
| [`cell_to_children`](https://filimoa.github.io/polars-h3/api-reference/inspection/#cell_to_children) | Get finer cells for a cell | ✅ |
| [`cell_to_center_child`](https://filimoa.github.io/polars-h3/api-reference/inspection/#cell_to_center_child) | Provides the center child (finer) cell contained by cell at resolution childRes. | ✅ |
| [`cell_to_child_pos`](https://filimoa.github.io/polars-h3/api-reference/inspection/#cell_to_child_pos) | Position of the child cell within the ordered list of all children of its parent at the specified resolution | ✅ |
| [`child_pos_to_cell`](https://filimoa.github.io/polars-h3/api-reference/inspection/#child_pos_to_cell) | Child cell at a given position within the ordered list of children for a specified parent/resolution | ✅ |
| [`compact_cells`](https://filimoa.github.io/polars-h3/api-reference/inspection/#compact_cells) | Compacts a collection of H3 cells (all same resolution) by replacing child cells with their parent if all children exist | ✅ |
| [`uncompact_cells`](https://filimoa.github.io/polars-h3/api-reference/inspection/#uncompact_cells) | Uncompacts a set of H3 cells to the resolution `res` | ✅ |
| [`grid_ring`](https://filimoa.github.io/polars-h3/api-reference/traversal/#grid_ring) | Produces the "hollow ring" of cells which are exactly grid distance k from the origin cell | ✅ |
| [`grid_disk`](https://filimoa.github.io/polars-h3/api-reference/traversal/#grid_disk) | Produces the "filled-in disk" of cells at most grid distance k from the origin cell | ✅ |
| [`grid_path_cells`](https://filimoa.github.io/polars-h3/api-reference/traversal/#grid_path_cells) | Find a grid path to connect two cells | ✅ |
| [`grid_distance`](https://filimoa.github.io/polars-h3/api-reference/traversal/#grid_distance) | Find the grid distance between two cells | ✅ |
| [`cell_to_local_ij`](https://filimoa.github.io/polars-h3/api-reference/indexing/#cell_to_local_ij) | Convert a cell ID to a local I,J coordinate space | ✅ |
| [`local_ij_to_cell`](https://filimoa.github.io/polars-h3/api-reference/indexing/#local_ij_to_cell) | Convert a local I,J coordinate to a cell ID | ✅ |
| [`cell_to_boundary`](https://filimoa.github.io/polars-h3/api-reference/indexing/#cell_to_boundary) | Convert cell ID to its boundary lat/lng coordinates | ✅ |
| [`cell_to_vertex`](https://filimoa.github.io/polars-h3/api-reference/vertexes/#cell_to_vertex) | Get the vertex ID for a cell ID and vertex number | ✅ |
| [`cell_to_vertexes`](https://filimoa.github.io/polars-h3/api-reference/vertexes/#cell_to_vertexes) | Get all vertex IDs for a cell ID (5 for pentagon, 6 for hex) | ✅ |
| [`vertex_to_latlng`](https://filimoa.github.io/polars-h3/api-reference/vertexes/#vertex_to_latlng) | Convert a vertex ID to latitude/longitude coordinates | ✅ |
| [`is_valid_vertex`](https://filimoa.github.io/polars-h3/api-reference/vertexes/#is_valid_vertex) | True if passed a valid vertex ID | ✅ |
| [`is_valid_directed_edge`](https://filimoa.github.io/polars-h3/api-reference/edge/#is_valid_directed_edge) | True if passed a valid directed edge ID | ✅ |
| [`origin_to_directed_edges`](https://filimoa.github.io/polars-h3/api-reference/edge/#origin_to_directed_edges) | Get all directed edge IDs for a cell ID | ✅ |
| [`directed_edge_to_cells`](https://filimoa.github.io/polars-h3/api-reference/edge/#directed_edge_to_cells) | Convert a directed edge ID to origin/destination cell IDs | ✅ |
| [`get_directed_edge_origin`](https://filimoa.github.io/polars-h3/api-reference/edge/#get_directed_edge_origin) | Convert a directed edge ID to origin cell ID | ✅ |
| [`get_directed_edge_destination`](https://filimoa.github.io/polars-h3/api-reference/edge/#get_directed_edge_destination) | Convert a directed edge ID to destination cell ID | ✅ |
| [`cells_to_directed_edge`](https://filimoa.github.io/polars-h3/api-reference/edge/#cells_to_directed_edge) | Convert an origin/destination pair to directed edge ID | ✅ |
| [`are_neighbor_cells`](https://filimoa.github.io/polars-h3/api-reference/edge/#are_neighbor_cells) | True if the two cell IDs share an edge | ✅ |
| [`average_hexagon_area`](https://filimoa.github.io/polars-h3/api-reference/metrics/#average_hexagon_area) | Get average area of a hexagon cell at resolution | ✅ |
| [`cell_area`](https://filimoa.github.io/polars-h3/api-reference/metrics/#cell_area) | Get the area of a cell ID | ✅ |
| [`average_hexagon_edge_length`](https://filimoa.github.io/polars-h3/api-reference/metrics/#average_hexagon_edge_length) | Average hexagon edge length at resolution | ✅ |
| [`edge_length`](https://filimoa.github.io/polars-h3/api-reference/metrics/#edge_length) | Get the length of a directed edge ID | ✅ |
| [`get_num_cells`](https://filimoa.github.io/polars-h3/api-reference/metrics/#get_num_cells) | Get the number of cells at a resolution | ✅ |
| [`get_pentagons`](https://filimoa.github.io/polars-h3/api-reference/metrics/#get_pentagons) | Get all pentagons at a resolution | ✅ |
| [`great_circle_distance`](https://filimoa.github.io/polars-h3/api-reference/metrics/#great_circle_distance) | Compute the great circle distance between two points (haversine) | ✅ |
| `cells_to_multi_polygon_wkt` | Convert a set of cells to multipolygon WKT | 🛑 |
| `polygon_wkt_to_cells` | Convert polygon WKT to a set of cells | 🛑 |
| `directed_edge_to_boundary_wkt` | Convert directed edge ID to linestring WKT | 🛑 |### Plotting
The library also comes with helper functions to plot hexes on a Folium map.
```python
import polars_h3 as plh3
import polars as plhex_map = plh3.graphing.plot_hex_outlines(df, "h3_cell")
display(hex_map)# or if you have a metric to plot
hex_map = plh3.graphing.plot_hex_fills(df, "h3_cell", "metric_col")
display(hex_map)
```
### Development
It's recommended to use [uv](https://github.com/astral-sh/uv) to manage the extension dependencies. If you modify rust code, you will need to run `uv run maturin develop --uv` to see changes. If you're looking to benchmark the performance of the extension, build the release version with `maturin develop --release --uv` and then run `uv run -m benchmarks.engine` (assuming you have the benchmark dependencies installed). Benchmarking with the development version will lead to misleading results.