Quickstart¶
Find which blocks intersect a station's 500-meter radius, then cover the area with H3 cells. We'll use three fictional blocks near the Eiffel Tower. Requires CPython 3.11 or newer; see the installation requirements for supported runtimes and platforms.
Install¶
uv add gometry
pip install gometry
1. A station¶
Create a Point for a station from its
longitude and latitude, and tag it with a CRS so gometry knows the coordinates are
degrees on the WGS 84 ellipsoid (EPSG:4326):
import gometry as gm
station = gm.Point(
2.2945,
48.8584,
crs=4326,
)
print(station)
POINT (2.2945 48.8584)
2. A proximity radius¶
A buffer models straight-line proximity, not travel time or route distance. On a
geographic CRS, buffer(500) uses a local-projection radial
distance of 500 meters rather than 500 degrees; unit='planar' instead uses
native angular units as Cartesian coordinates:
service_area = station.buffer(500)
print('service area m²:', round(service_area.area))
service area m²: 780935
3. Ingest named tutorial blocks¶
gm.from_geojson(..., features=True) parses a GeoJSON feature collection into a Features
result with geometries in a GeometryArray and parallel
properties as ordinary Python mappings.
payload = '''
{"type":"FeatureCollection","features":[
{"type":"Feature","id":"champ-edge","properties":{"name":"Champ-de-Mars edge"},
"geometry":{"type":"Polygon","coordinates":[[[2.290,48.855],[2.296,48.855],[2.296,48.858],[2.290,48.858],[2.290,48.855]]]}},
{"type":"Feature","id":"trocadero-side","properties":{"name":"Trocadero side"},
"geometry":{"type":"Polygon","coordinates":[[[2.287,48.860],[2.293,48.860],[2.293,48.864],[2.287,48.864],[2.287,48.860]]]}},
{"type":"Feature","id":"out-of-range","properties":{"name":"Out-of-range block"},
"geometry":{"type":"Polygon","coordinates":[[[2.305,48.865],[2.311,48.865],[2.311,48.870],[2.305,48.870],[2.305,48.865]]]}}
]}
'''
features = gm.from_geojson(payload, crs=4326, features=True)
blocks, properties, ids = features.geometries, features.properties, features.ids
names = [row['name'] for row in properties]
print(len(blocks), 'tutorial blocks loaded:', names)
3 tutorial blocks loaded: ['Champ-de-Mars edge', 'Trocadero side', 'Out-of-range block']
- input
- query
- anchor
4. Which blocks are in reach?¶
Build a spatial index over the blocks, then ask which ones intersects
the service area. The index runs a bounding-box prefilter and then an exact
geometry test; query returns row indices for intersecting geometries rather
than candidate envelopes, while SpatialIndex.candidates
returns prefilter row indices:
idx = gm.SpatialIndex(blocks)
reachable = idx.query(service_area, predicate='intersects')
print('rows intersecting the radius:', reachable.tolist())
matched_names = [names[i] for i in reachable]
print('matched names:', matched_names)
rows intersecting the radius: [0, 1]
matched names: ['Champ-de-Mars edge', 'Trocadero side']
- query
- result
- excluded
- anchor
5. Bucket the service area into grid cells¶
gm.h3_cover returns H3 cells for joining tiled datasets or binning at global
scale; exact membership uses the source geometry with gm.covers:
cells = gm.h3_cover(service_area, resolution=10)
print('H3 cells:', len(cells))
print('source covers the station:', gm.covers(service_area, station))
H3 cells: 76
source covers the station: True
- candidates
- input
- anchor
Where to go next¶
| If you want to... | Read |
|---|---|
| understand the planar / geodesic / grid models | The gometry mental model |
| get a specific job done | The user guide |
| see why metrics follow the CRS | CRS, units & measurement |
| migrate existing Shapely code | Coming from Shapely |
replace pyproj Transformer / Geod workflows |
Coming from pyproj |
| tune joins and candidate/refine pipelines | Spatial indexing & joins |
| look up any callable | API reference |