Multi Spatial Subdivision System - A unified Python package for working with spatial grid systems
Project description
M3S - Multi Spatial Subdivision System
A unified package for working with hierarchical spatial grid systems in Python and JavaScript (via WASM). Both bindings call one shared Rust core, so a cell encoded in one language decodes identically in the other. M3S (Multi Spatial Subdivision System) provides a consistent interface for working with different spatial indexing systems including Geohash, MGRS, H3, Quadkey, S2, Slippy Map tiles, C-squares, GARS, Maidenhead, Plus Codes, EA-Quad, rHEALPix, and A5.
Features
Direct grid access
- 🎯 No instantiation needed: just
m3s.H3,m3s.Geohash, etc. - 🌐 Universal Geometry: Single
from_geometry()handles points, polygons, bboxes, GeoDataFrames - 🔍 Smart Precision: Auto-select optimal precision or choose by use case, area, or cell count
- 🔄 Easy Conversion: Convert between grids with
.to_h3(),.to_geohash(), etc. - 📦 Powerful Collections: Filter, map, export with
GridCellCollection
Core Capabilities
- 13 Grid Systems: Geohash, MGRS, H3, Quadkey, S2, Slippy, C-squares, GARS, Maidenhead, Plus Codes, EA-Quad, rHEALPix, A5
- Area Calculations: All grids support
area_km2property - GeoPandas Integration: Native GeoDataFrame support with automatic CRS transformation
- UTM Zone Integration: Automatic UTM zone detection and inclusion
- Polygon Intersection: Find grid cells intersecting any Shapely polygon or GeoDataFrame
- Hierarchical Operations: Parent/child relationships and multi-resolution analysis
- Neighbor Finding: Get neighboring cells across all grid systems
- Parallel Processing: Threaded parallelism and streaming for large datasets
- Modern Python: Type hints, comprehensive documentation and test suite
Installation
Python — from PyPI:
uv pip install m3s # or: pip install m3s
JavaScript — from npm:
npm install @nkarasiak/m3s
The npm package bundles both a Node (CommonJS WASM) and a browser (ESM WASM)
build; the right one is selected automatically through the exports map. See
bindings/js/README.md for the JS API and how to build
from source.
For development:
git clone https://github.com/nkarasiak/m3s.git
cd m3s
uv sync # create the dev environment (.venv) from uv.lock
Quick Start
M3S gives direct access to grid systems, auto-precision selection, and universal geometry handling:
import m3s
from shapely.geometry import Polygon
# Direct access to grid systems (no instantiation needed!)
# Coordinate tuples use GIS-native (lon, lat) / (x, y) order, like shapely.
cell = m3s.Geohash.from_geometry((-74.0060, 40.7128)) # Point tuple (lon, lat)
print(f"Cell: {cell.id}, Area: {cell.area_km2:.2f} km²")
# Output: Cell: dr5re, Area: 18.11 km²
# Works with any geometry type: points, polygons, GeoDataFrames, bbox tuples
polygon = Polygon([(-74.1, 40.7), (-73.9, 40.7), (-73.9, 40.8), (-74.1, 40.8)])
cells = m3s.H3.from_geometry(polygon) # Uses default precision (7)
print(f"Found {len(cells)} H3 cells with total area {cells.total_area_km2:.2f} km²")
# Output: Found 47 H3 cells with total area 244.01 km²
# For optimal precision with large areas, find it explicitly first:
precision = m3s.H3.find_precision(polygon, method='auto') # Minimizes coverage variance
cells = m3s.H3.from_geometry(polygon, precision=precision)
# Get neighbors
neighbors = m3s.Geohash.neighbors(cell, depth=1)
print(f"Cell has {len(neighbors)} neighbors (including itself)")
# Output: Cell has 9 neighbors (including itself)
# Or find optimal precision
precision = m3s.H3.find_precision(polygon, method='auto') # Minimizes coverage variance
cells = m3s.H3.from_geometry(polygon, precision=precision)
# Easy conversions between grid systems
h3_cells = cells.to_geohash() # Convert H3 → Geohash
gdf = h3_cells.to_gdf() # Convert to GeoDataFrame
# Collection operations
large_cells = cells.filter(lambda c: c.area_km2 > 10.0)
ids = cells.to_ids()
polygons = cells.to_polygons()
# Find precision by use case
precision = m3s.Geohash.find_precision_for_use_case('neighborhood') # ~1-10 km²
# Other use cases: 'building', 'block', 'city', 'region', 'country'
# Dynamic, config-driven grid access by name
grid = m3s.grid('h3', precision=7) # -> same wrapper as m3s.H3
print(m3s.grids()) # ['csquares', 'eaquad', 'gars', 'h3', ...]
# Visualize straight from a collection (delegates to GeoPandas/folium)
cells.explore() # interactive Leaflet map
cells.plot(edgecolor='black') # static matplotlib axes
# Persist and reload (round-trips through ids or a vector file)
cells.save('cells.geojson')
same = m3s.H3.from_ids(cells.to_ids()) # ids -> wrapper-aware collection
Available grid systems:
m3s.Geohash- Base32-encoded spatial indexm3s.MGRS- Military Grid Reference Systemm3s.H3- Uber's hexagonal gridm3s.S2- Google's spherical geometrym3s.Quadkey- Microsoft Bing Maps tilesm3s.Slippy- OpenStreetMap tilesm3s.CSquares- Marine data indexingm3s.GARS- Global Area Reference Systemm3s.Maidenhead- Amateur radio locatorm3s.PlusCode- Open Location Codesm3s.EAQuad- Equal-area quadtree (power-of-two km cells)m3s.RHEALPix- rHEALPix equal-area DGGS (aperture 9)m3s.A5- Pentagonal equal-area DGGS
Coordinate order: M3S uses GIS-native (lon, lat) / (x, y) order for coordinate tuples — matching shapely, geopandas and pyproj.
GridCell.bounds,GridCell.centroidandfrom_bboxall follow the same order, sogrid.from_bbox(collection.bounds)round-trips correctly.
JavaScript
The JS API mirrors the Python facade in camelCase and produces identical cells. The wrapper is thin — polygon fill, precision strategies, GeoPandas export and cross-grid conversion stay Python-only.
import * as m3s from "@nkarasiak/m3s";
await m3s.ready(); // awaits WASM init (no-op on Node)
// Direct grid access — (lon, lat, precision)
const cell = m3s.Geohash.fromPoint(-74.0060, 40.7128, 6);
console.log(`Cell: ${cell.id}, Area: ${cell.areaKm2.toFixed(2)} km²`);
// Cells across a bounding box [minLon, minLat, maxLon, maxLat]
const cells = m3s.H3.fromBbox([-74.1, 40.7, -73.9, 40.8], 8);
console.log(`${cells.length} cells`, cells.toIds());
Grid Systems
Geohash
Hierarchical spatial data structure using Base32 encoding. Each character represents 5 bits of spatial precision.
- Precision Levels: 1-12
- Cell Shape: Rectangular
- Use Cases: Databases, simple spatial indexing
MGRS (Military Grid Reference System)
Coordinate system based on UTM with standardized square cells.
- Precision Levels: 0-5 (100km to 1m)
- Cell Shape: Square
- Use Cases: Military, surveying, precise location reference
H3 (Uber's Hexagonal Hierarchical Spatial Index)
Hexagonal grid system with uniform neighbor relationships and excellent area representation.
- Resolution Levels: 0-15
- Cell Shape: Hexagonal
- Use Cases: Spatial analysis, ride-sharing, logistics
Quadkey (Microsoft Bing Maps)
Quadtree-based square tiles used by Microsoft Bing Maps.
- Levels: 1-23
- Cell Shape: Square
- Use Cases: Web mapping, tile-based applications
S2 (Google's Spherical Geometry)
Spherical geometry cells using Hilbert curve for optimal spatial locality.
- Levels: 0-30
- Cell Shape: Curved (spherical quadrilaterals)
- Use Cases: Large-scale applications, global spatial indexing
Slippy Map Tiles
Standard web map tiles used by OpenStreetMap and most web mapping services.
- Zoom Levels: 0-22
- Cell Shape: Square (in Web Mercator projection)
- Use Cases: Web mapping, tile servers, caching
API Reference
Parallel Processing
from m3s.parallel import ParallelGridEngine, ParallelConfig
# Configure parallel processing
config = ParallelConfig(
n_workers=4,
chunk_size=10000
)
# Process large datasets in parallel
engine = ParallelGridEngine(config)
result = engine.intersect_parallel(grid, large_gdf)
Development
Setup
git clone https://github.com/nkarasiak/m3s.git
cd m3s
uv sync # create the dev environment (.venv) from uv.lock
Running Tests
uv run pytest
Code Formatting
uv run black m3s tests examples
Type Checking
uv run mypy m3s
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Dependencies
Required
- Shapely - Geometric operations
- PyProj - Coordinate transformations
- GeoPandas - Geospatial data manipulation
- mgrs - MGRS coordinate conversions
- h3 - H3 hexagonal grid operations
- s2sphere - S2 spherical geometry operations
Notes:
- Geohash, Quadkey, and Slippy Map Tiles are implemented using pure Python (no external dependencies)
- S2 functionality requires the s2sphere library for proper spherical geometry calculations
Acknowledgments
- Built for geospatial analysis and location intelligence applications
- Thanks to the maintainers of the underlying spatial libraries
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file m3s-0.6.0.tar.gz.
File metadata
- Download URL: m3s-0.6.0.tar.gz
- Upload date:
- Size: 145.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe29effd0b62f0fd1f101838fb81968d663dad205566e021998aaf781cf3946f
|
|
| MD5 |
bf49a0b9dff62329a8f884bb27208aaf
|
|
| BLAKE2b-256 |
f83e4d9279cf921fb868e5d68629e2bb40e54e886faafe964ef624bcd148cc83
|
File details
Details for the file m3s-0.6.0-py3-none-any.whl.
File metadata
- Download URL: m3s-0.6.0-py3-none-any.whl
- Upload date:
- Size: 112.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e51edd5c708f1624e09209102a32f9a74b47cdf9b6d814de3de43f567b17f2a
|
|
| MD5 |
3c370aec54ce6f5aa01949b30dd84259
|
|
| BLAKE2b-256 |
0870dba8601d19d10ddc1288951d10d9c7e744f5a141b3f9110f815d595f2878
|