Python helper functions for manipulating GeoJSON
Project description
geojson-python-utils
Python utilities for working with GeoJSON dictionaries. The package covers common geometry checks, distance calculations, polygon helpers, coordinate conversion, FeatureCollection utilities, and point-line simplification.
The project began as a Python port inspired by geojson-js-utils. It now targets Python 3.8+ and ships inline type annotations.
Why This Package
- Works with plain Python dictionaries that follow the GeoJSON shape.
- Keeps dependencies small;
requestsis only used by the optional geocoding helper. - Includes typed public functions and a
py.typedmarker for downstream type checkers. - Provides tested helpers for common GIS tasks without requiring a full geospatial stack.
Features
- LineString intersection detection.
- Point-in-Polygon and Point-in-MultiPolygon checks.
- Circle polygon generation from a center point and radius.
- Polygon area, centroid, and rectangle centroid helpers.
- Spherical and ellipsoidal distance calculations.
- Radius checks for Point, LineString, and Polygon geometries.
- Destination point calculation from bearing and distance.
- FeatureCollection merging and endpoint extraction.
- Point array simplification with a meter-based tolerance.
- Coordinate conversion between WGS84, GCJ-02, and BD-09.
- Validation and normalization helpers for GeoJSON geometries, Features, and FeatureCollections.
Requirements
- Python 3.8 or newer.
requests>=2.9.1.
Python 2 is not supported.
Installation
pip install geojson_utils
You can also copy the geojson_utils/ package into a project and import from it directly.
Quick Start
from geojson_utils import point_distance, point_in_polygon
point = {"type": "Point", "coordinates": [5, 5]}
polygon = {
"type": "Polygon",
"coordinates": [[[0, 0], [10, 0], [10, 10], [0, 10]]],
}
print(point_in_polygon(point, polygon))
oakland = {"type": "Point", "coordinates": [-122.260000705719, 37.80919060818706]}
naval_base = {"type": "Point", "coordinates": [-122.32083320617676, 37.78774223089045]}
print(point_distance(oakland, naval_base))
Most functions accept and return plain GeoJSON dictionaries. The package does not require custom geometry classes.
Validation and Normalization
from geojson_utils import normalize_geojson, validate_geojson
polygon = {
"type": "Polygon",
"coordinates": [[[0, 0], [10, 0], [10, 10], [0, 10]]],
}
normalized = normalize_geojson(polygon, close_rings=True)
validate_geojson(normalized)
validate_geojson() supports every standard GeoJSON geometry type plus Feature and FeatureCollection objects. Invalid objects raise GeoJSONValidationError with a path to the failing field.
normalize_geojson() returns a copy. It can close polygon rings, orient exterior rings and holes, and optionally remove bbox or id fields.
Geometry Helpers
LineString Intersection
from geojson_utils import linestrings_intersect
diagonal_up = {"type": "LineString", "coordinates": [[0, 0], [10, 10]]}
diagonal_down = {"type": "LineString", "coordinates": [[10, 0], [0, 10]]}
far_away = {"type": "LineString", "coordinates": [[100, 100], [110, 110]]}
print(linestrings_intersect(diagonal_up, diagonal_down))
print(linestrings_intersect(diagonal_up, far_away))
Point in Polygon
from geojson_utils import point_in_multipolygon, point_in_polygon
point = {"type": "Point", "coordinates": [5, 5]}
polygon = {
"type": "Polygon",
"coordinates": [[[0, 0], [10, 0], [10, 10], [0, 10]]],
}
print(point_in_polygon(point, polygon))
multi_polygon = {
"type": "MultiPolygon",
"coordinates": [
[[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]],
[[[10, 10], [10, 20], [20, 20], [20, 10], [10, 10]]],
],
}
print(point_in_multipolygon(point, multi_polygon))
Polygon holes are handled for point-in-polygon checks, area, and centroid calculations. Boundary points count as inside.
Draw a Circle Polygon
from geojson_utils import draw_circle
center = {"type": "Point", "coordinates": [0, 0]}
circle = draw_circle(10, center, steps=50)
print(circle["type"])
print(len(circle["coordinates"][0]))
Distance and Radius Checks
from geojson_utils import geometry_within_radius, point_distance
center = {"type": "Point", "coordinates": [-122.260000705719, 37.80919060818706]}
candidate = {"type": "Point", "coordinates": [-122.32083320617676, 37.78774223089045]}
print(point_distance(center, candidate))
print(geometry_within_radius(candidate, center, 5853))
Area and Centroid
from geojson_utils import area, centroid, rectangle_centroid
polygon = {
"type": "Polygon",
"coordinates": [[[0, 0], [10, 0], [10, 10], [0, 10]]],
}
print(area(polygon))
print(centroid(polygon))
print(rectangle_centroid(polygon))
Use close_ring(), ring_is_clockwise(), and orient_ring() when normalizing polygon topology before export.
Destination Point
from geojson_utils import destination_point
start = {"type": "Point", "coordinates": [-122.260000705719, 37.80919060818706]}
print(destination_point(start, 180, 2000))
FeatureCollection Helpers
from geojson_utils import merge_featurecollection, simplify_other
merged = merge_featurecollection(first_feature_collection, second_feature_collection)
deduped = simplify_other(major_points, minor_points, dist=50)
simplify_other() works on Point FeatureCollections. It appends points from the minor collection only when they are farther than dist meters from every point in the major collection.
Simplify Point Arrays
simplify() reduces a list of GeoJSON Point objects with the Ramer-Douglas-Peucker algorithm. The kink value is measured in meters.
from geojson_utils import simplify
points = [
{"type": "Point", "coordinates": [0, 0]},
{"type": "Point", "coordinates": [0.001, 0.00001]},
{"type": "Point", "coordinates": [0.002, 0]},
]
print(simplify(points, kink=20))
The function preserves the first and last point and keeps intermediate points whose perpendicular distance is greater than the kink tolerance.
Coordinate Conversion
convertor() supports Geometry, Feature, FeatureCollection, and GeometryCollection inputs. It mutates the input by default for backwards compatibility; pass inplace=False to return a converted copy.
| Method | Conversion |
|---|---|
wgs2gcj |
WGS84 to GCJ-02 |
gcj2wgs |
GCJ-02 to WGS84 |
wgs2bd |
WGS84 to BD-09 |
bd2wgs |
BD-09 to WGS84 |
gcj2bd |
GCJ-02 to BD-09 |
bd2gcj |
BD-09 to GCJ-02 |
import json
from geojson_utils import convertor
with open("tests/province_wgs.geojson", encoding="utf-8") as fp:
geojson = json.load(fp)
for feature in geojson["features"]:
converted = convertor(feature["geometry"], method="wgs2gcj")
print(converted["type"])
converted = convertor(geojson, method="gcj2bd", inplace=False)
The coordinate-transform layer keeps the base install lightweight. EPSG/projection based transforms can be added later behind an optional extra such as geojson_utils[crs].
Format Conversion API
The conversion layer provides a small registry so the package can grow new adapters without a large monolithic conversion function.
from geojson_utils import convert, read_geojson, write_geojson
point = read_geojson("point.geojson")
text = convert(point, from_format="geojson", to_format="json")
round_tripped = convert(text, from_format="json", to_format="geojson")
write_geojson(round_tripped, "round-trip.geojson")
You can add adapters with register_converter(from_format, to_format, callable). Built-in adapters currently cover GeoJSON file IO and GeoJSON dictionary <-> JSON text conversion.
WKT / WKB
from geojson_utils import geojson_to_wkt, wkt_to_geojson
wkt = geojson_to_wkt({"type": "Point", "coordinates": [1, 2]})
geometry = wkt_to_geojson("POINT (1 2)")
WKT support is implemented for standard GeoJSON geometry types. WKB helpers are available through optional Shapely support and raise a clear error when Shapely is not installed.
CSV Points
from geojson_utils import csv_to_feature_collection, feature_collection_to_csv
collection = csv_to_feature_collection(
"id,longitude,latitude,name\n1,120.1,30.2,Hangzhou\n",
id_column="id",
)
text = feature_collection_to_csv(collection, id_column="id")
CSV conversion targets Point FeatureCollections. Coordinate columns default to longitude and latitude, and all other columns are preserved as Feature properties.
Shapefile / GeoPackage
Heavier desktop GIS formats are exposed through optional adapters so the base package stays small.
pip install "geojson_utils[files]"
from geojson_utils import read_geopackage, read_shapefile, write_geopackage, write_shapefile
collection = read_shapefile("roads.shp")
write_geopackage(collection, "roads.gpkg", layer="roads")
These adapters use GeoPandas when installed. Without the optional dependency, they raise OptionalAdapterError with installation guidance.
Streaming and NDJSON
For large datasets, use feature iterators and newline-delimited GeoJSON helpers instead of loading everything into memory.
from geojson_utils import read_ndjson_features, write_ndjson_features
with open("features.ndjson", encoding="utf-8") as source:
features = read_ndjson_features(source)
for feature in features:
print(feature["geometry"]["type"])
iter_features() yields Feature objects from a Feature, FeatureCollection, or bare Geometry. write_ndjson_features() writes one Feature per line for pipeline-friendly processing.
Bounding Boxes and Spatial Filtering
from geojson_utils import BBoxIndex, bbox, filter_features_by_bbox
bounds = bbox(collection)
nearby = filter_features_by_bbox(collection, [120, 30, 121, 31])
indexed = BBoxIndex(collection).search([120, 30, 121, 31])
bbox() returns [min_lon, min_lat, max_lon, max_lat] for Geometry, Feature, and FeatureCollection objects. The lightweight BBoxIndex keeps precomputed feature bounds for repeated bbox searches without requiring an optional R-tree dependency.
Command Line
Installing the package exposes geojson-utils for common pipeline tasks.
geojson-utils validate input.geojson
geojson-utils convert input.geojson --to json --output output.json
geojson-utils transform input.geojson --method wgs2gcj --output gcj.geojson
geojson-utils simplify line.geojson --tolerance 20 --output simplified.geojson
geojson-utils bbox input.geojson
Use - as the input path to read GeoJSON from stdin. Commands write to stdout unless --output is provided.
Type Checking
The package includes inline annotations and a py.typed marker. Type checkers can read the installed package signatures without separate stub files.
Development
The active development branch is develop.
Run the test suite:
python3 -m unittest discover -v
Run a syntax check:
python3 -m py_compile geojson_utils/*.py test.py setup.py
Documentation
License
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 geojson_utils-0.0.3.tar.gz.
File metadata
- Download URL: geojson_utils-0.0.3.tar.gz
- Upload date:
- Size: 31.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b45105fcdb185b3883b16d5439ca090b43452c2b138825642ed7da7b632bfbb5
|
|
| MD5 |
a812125a44df5ce100804728b44beb16
|
|
| BLAKE2b-256 |
fc3d9a766562ff3fce2e1579575f47ef526b263dbfa294b199f61e61b25e6410
|
File details
Details for the file geojson_utils-0.0.3-py3-none-any.whl.
File metadata
- Download URL: geojson_utils-0.0.3-py3-none-any.whl
- Upload date:
- Size: 26.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e259576e39b6eb4af3011340eb045314207b53e15c287bb4e1e97749e40c6c1
|
|
| MD5 |
36486c73ad4207046057fb12197a1d06
|
|
| BLAKE2b-256 |
5493329567c8ef7f14e8c903f064b0f67c8c0d0a4f0ea9b5fbe733f6f422cf41
|