Skip to content

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']
The station, its 500 m service area, and the three tutorial blocks.
A station anchors a 500 m service area drawn over the three tutorial blocks it will be tested against.
  • 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']
Two blocks intersect the service area; the third is out of range.
The query returns the two blocks that intersect the service area and excludes the out-of-range block.
  • 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
H3 cells cover the service area; the geometry still decides membership.
H3 cells are join keys that can extend beyond the source service area, so the source geometry decides exact membership.
  • 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