Skip to main content

geoClassy

Label GPS points with the area that contains them — a neighbourhood, a municipality, a district — using boundary polygons you already have as GeoJSON, typically exported from OpenStreetMap.

import geoClassy

areas = geoClassy.load("nyc-neighborhoods.geojson")

areas.locate(40.748417, -73.985833)  # 'Midtown South'
areas.locate(38.897699, -77.036553)  # None — outside every area

df["zone"] = areas.locate_many(df.latitude, df.longitude)

That is the whole library. len(areas) counts them, areas.names lists them.

pip install geoClassy

Why not geopandas?

Because putting a point in an area shouldn't cost you GDAL and PROJ. geoClassy does this one job with Shapely and NumPy — no geospatial system libraries, no network calls, no API keys, and answers that don't change between runs.

geoClassy geopandas reverse-geocoding API
Install 2 wheels GDAL + PROJ —
Works offline yes yes no
Your own boundaries yes yes no
Rate limits none none yes

If you already run geopandas, use sjoin — it is the right tool and geoClassy adds nothing. This is for everyone else.

Speed

locate_many runs one spatial-index query for the whole batch instead of one per point. Use it instead of df.apply(...) row by row.

  • 5,000 points against 500 areas: 3 ms (the same work took 24 s in 0.1.x).
  • 1,000,000 points against a 5,000-area partition where every point lands in one: 1.1 s, after an 83 ms load.

Rows with missing coordinates come back as None rather than raising, so a dataframe with gaps still classifies in one call.

Overlapping areas

A point can legitimately fall inside several areas at once — a district inside a city inside a region, which is what you get when an Overpass query returns more than one admin_level. By default geoClassy returns the smallest matching area, that is, the most specific one:

areas.locate(45.472, 9.188)  # 'Brera', not 'Milano' or 'Lombardia'

Change it with on_overlap, either for the whole dataset or per call:

on_overlap result
"smallest" the smallest matching area (default)
"first" / "last" first or last match in file order
"all" every match, smallest first
"error" raise OverlapError

To find out whether this affects your data at all, ask:

areas.overlapping_pairs()  # [] means no policy can change anything

Loading

geoClassy.load(path, *, name_key="name", only_boundaries=False, on_overlap="smallest")
  • .geojson, .json, and .gz versions of either are read transparently.
  • name_key picks the property to label with — "ISO3166-2", "ref", whatever your export carries. If it is missing, the error tells you which keys exist.
  • only_boundaries=True keeps only features tagged properties.type == "boundary". Off by default: most export tools don't set it.
  • Areas.from_geojson(data) takes an already-parsed dict.
  • locate(..., full=True) returns the feature's whole properties dict rather than just the name, so you keep admin_level, wikidata, ISO codes.

Coordinates are WGS84 degrees, the system GeoJSON mandates. Arguments are (lat, lon); GeoJSON stores [lon, lat], and out-of-range values are rejected with a message pointing at that swap. Points exactly on a boundary count as inside. Invalid polygons — endemic in OSM exports — are repaired on load.

Where to get the boundaries

Fetching straight from Overpass is planned for 0.3 as an optional command, so the library itself stays offline.

Upgrading from 0.1.x

The old function API still works, with a DeprecationWarning, and will be removed in 1.0. It keeps 0.1.x semantics exactly, so upgrading changes no results before you migrate:

0.1.x 0.2
loadFile(path) areas = geoClassy.load(path)
getNames(lat, lon) areas.locate(lat, lon) — returns None, not 'unknown'
numPoly() len(areas)
polyList() areas.names
checkPoly() gone: load() validates and repairs, and raises if it can't
requisites() gone: just import geoClassy

Three of those crashed with TypeError on Shapely 2.x, and getNames returned whichever overlapping area happened to come last in the file. See CHANGELOG.md.

Contact

Written by Nicola Simboli — support@simboli.eu, simboli.eu. MIT licensed.

Release files for geoClassy 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for geoClassy 0.2.0
File Size Uploaded
geoclassy-0.2.0.tar.gz 17.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for geoClassy 0.2.0
File Interpreter ABI Platform
geoclassy-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 28.5 kB

Release files / geoclassy-0.2.0.tar.gz

Download URL geoclassy-0.2.0.tar.gz
Size 17.0 kB
Tags Source
SHA-256 checksum
How to use checksums
3a7c4eb3b6ea201e413506e71ab07d31875b447c4f6ab7b9a267f4de74ac0524
BLAKE2b-256 checksum
How to use checksums
2825cf2beae6484c56c807d60d0bfff1fe9e6f51022afd674ea7b8a3ff350d4e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Release files / geoclassy-0.2.0-py3-none-any.whl

Download URL geoclassy-0.2.0-py3-none-any.whl
Size 11.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
295e9638065ad3b079472467dc9694dfd9d501ce3c6564167b28f2082e3cf28c
BLAKE2b-256 checksum
How to use checksums
fe3bf66019329e4f98e8972eacc0cff9eb923c108c22cc311895f7b4faa2bd35
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.1

2 release files

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.7

2 release files

0.0.4

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page