conscientious and compliant GeoJSON

GeoJSON is a specification for encoding geographical features in JSON. GeoJSON is simple, reasonably flexible, and can be read using any stdlib JSON package.

picogeojson is a pure-Python package that ensures that the GeoJSON you create adheres to the 2016 GeoJSON specification, taking care of details such as polygon closing, winding order, and antimeridian-cutting. For a more full-featured Python geospatial package, take a look at Karta. It handles unmarshaling GeoJSON strings from unknown sources, allowing you to skip a lot of boilerplate and key-checking.


pip install -U picogeojson

Encoding and Decoding

GeoJSON objects are serialized with tostring(), tofile(), or todict().

    picogeojson.Point([1.0, 3.0])
# -> {"coordinates": [1.0, 3.0], "type": "Point"}'

All of the serialization functions accept the following options:

antimeridian_cutting: bool: Cuts geometries at the 180th meridian so that they plot well on standard world maps.

write_bbox: bool: Write an optional bbox member to the GeoJSON object.

write_crs: bool: Write a non-standard crs member for non-WGS84 longitude-latitude coordinates.

precision: int: Restrict the number of decimal digits in the written coordinates (5 results in precision of 1 meter or better for longitude-latitude coordinates).

GeoJSON files, strings and dicts are deserialized using fromstring(), fromfile(), or fromdict().

picogeojson.fromstring('{"type": "Point", "coordinates": [1.0, 3.0]}')
# -> <picogeojson.map.Map object at ...>

When reading GeoJSON, picogeojson returns a Map object, which is a container for GeoJSON. Useful methods on Map objects include:

Map.extract(geotype): creates a generator for geometries of type geotype, as in

geojson = picogeojson.loads(...)

for linestring in geojson.extract(picogeojson.LineString):

Map.extract_features(geotype=None, properties=None): similar to Map.extract, this extracts GeoJSON features, optionally filtering by properties.

geojson = picogeojson.loads(...)

for lake in geojson.features("Polygon", {"type": "Lake", "state": "Oregon"}):

Map.map(function, geotype): returns a new Map with function applied to every contained GeoJSON geometry of type geotype.

Map.map_features(function, geotype): returns a new Map with function applied to every contained GeoJSON feature containing geometry geotype and matching properties.

Types and transformations

In order to create or work with GeoJSON, picogeojson defines constructors for all GeoJSON types:

pt = picogeojson.Point([1.0, 3.5])

polygon = picogeojson.Polygon([[[100.0, 20.0], [102.0, 19.7], [102.3, 23.0],
                                [100.1, 22.8], [100.0, 20.0]]])

feature = picojson.Feature(polygon, {"id": "example polygon"})

When constructing geometries, picogeojson takes care of ensuring that coordinate rings are closed and oriented correctly and that coordinates are nested to the correct depth.

The following methods are available:

Type .transform .map .flatmap
Point ✔️
LineString ✔️
Polygon ✔️
MultiPoint ✔️
MultiLineString ✔️
MultiPolygon ✔️
GeometryCollection ✔️ ✔️ ✔️
Feature ✔️ ✔️
FeatureCollection ✔️ ✔️ ✔️

.transform operates on coordinates, returning a new geometry or feature with a function applied to each coordinate pair.

.map applies a function to each member of a GeometryCollection or FeatureCollection. Features have a .map_geometry and a .map_properties that apply functions to the underlying geometry or properties dict, respectively.

.flatmap applies a function to each member of a collection, constructing a new collection by concatenating the result of each application.


GeoJSON objects may be composed (merge()) or split (burst()).

points = [picogeojson.Point((1, 2)),
          picogeojson.Point((3, 4)),
          picogeojson.Point((5, 6))]

merged_points = picogeojson.merge(points)
# -> MultiPoint(coordinates=[(1, 2), (3, 4), (5, 6)])

split_points = picogeojson.burst(merged_points)
# -> [Point((1, 2)), Point((3, 4)), Point((5, 6))]

Source code