PYGEOIF(1)

πŸ“¦
version 1.6.0 Β· 2 versions
, in fedora 43

✨ NAME ✨

pygeoif β€” bestie, this is the manual page for pygeoif version 1.6.0, and it's giving "tiny library, huge slay" πŸ’…


πŸ¦‹ OVERVIEW πŸ¦‹

PyGeoIf provides a GeoJSON-like protocol for geo-spatial (GIS) vector data. Periodt.

Other Python programs and packages you may have heard of that implement this protocol:

  • ArcPy
  • descartes
  • PySAL
  • Shapely
  • pyshp
  • GeoPandas
  • Karta
  • mapnik

When you wanna write your own geospatial library with support for this protocol, you may use pygeoif as a starting point and build your functionality on top of it. It has no requirements outside the Python standard library and is therefore easy to integrate into your project. It is tested on CPython, PyPy and GraalPy, but it should work on alternative Python implementations (that implement the language specification >=3.9) as well. no cap 🫢

You may think of pygeoif as a 'shapely ultralight' which lets you construct geometries and perform very basic operations like reading and writing geometries from/to WKT, constructing line strings out of points, polygons from linear rings, multi polygons from polygons, etc. It was inspired by shapely and implements the geometries in a way that when you are familiar with pygeoif, you will feel right at home with shapely or the other way round. It provides Hypothesis strategies for all geometries for property based testing with Hypothesis. iconic fr fr 🌸

It was written to provide clean and python only geometries for fastkml

Documentation Β· GitHub Actions Β· Codecov Β· Tested with Hypothesis Β· Black Β· Mypy ‐ Openhub Β· CodeFactor Β· pre-commit Β· Supported Python versions Β· Supported Python implementations Β· Latest Version Β· Conda Version Β· License Β· Downloads

πŸŽ€ Installation πŸŽ€

You can install PyGeoIf from pypi using pip:

pip install pygeoif

🌈 EXAMPLE 🌈

>>> from pygeoif import geometry
>>> p = geometry.Point(1,1)
>>> p.__geo_interface__
{'type': 'Point', 'bbox': (1, 1, 1, 1), 'coordinates': (1, 1)}
>>> print(p)
POINT (1 1)
>>> p
Point(1, 1)
>>> l = geometry.LineString([(0.0, 0.0), (1.0, 1.0)])
>>> l.bounds
(0.0, 0.0, 1.0, 1.0)
>>> print(l)
LINESTRING (0.0 0.0, 1.0 1.0)

You find more examples in the tests directory which cover every aspect of pygeoif or in fastkml. go look bestie, they ate πŸ’–


πŸ‘‘ CLASSES πŸ‘‘

All classes implement the attribute:

  • __geo_interface__: as discussed above, an interface to GeoJSON.

All geometry classes implement the attributes:

  • geom_type: Returns a string specifying the Geometry Type of the object
  • bounds: Returns a (minx, miny, maxx, maxy) tuple that bounds the object.
  • wkt: Returns the 'Well Known Text' representation of the object

For two-dimensional geometries the following methods are implemented:

  • convex_hull: Returns a representation of the smallest convex Polygon containing all the points in the object unless the number of points in the object is less than three. For two points, the convex hull collapses to a LineString; for 1, a Point. For three dimensional objects only their projection in the xy plane is taken into consideration. Empty objects without coordinates return None for the convex_hull.

πŸ’œ Point πŸ’œ

A zero dimensional geometry

A point has zero length and zero area. A point cannot be empty. (like, it literally can't, that's the vibe)

Attributes

  • x, y, z (float) β€” Coordinate values

Example

(the original page leaves this one blank, no cap πŸ™ˆ)

πŸ’œ LineString πŸ’œ

A one-dimensional figure comprising one or more line segments

A LineString has non-zero length and zero area. It may approximate a curve and need not be straight. Unlike a LinearRing, a LineString is not closed. she's open, she's free πŸ¦‹

Attributes

  • geoms (sequence) β€” A sequence of Points

πŸ’œ LinearRing πŸ’œ

A closed one-dimensional geometry comprising one or more line segments

A LinearRing that crosses itself or touches itself at a single point is invalid and operations on it may fail. πŸ’€

A LinearRing is self closing.

πŸ’œ Polygon πŸ’œ

A two-dimensional figure bounded by a linear ring

A polygon has a non-zero area. It may have one or more negative-space "holes" which are also bounded by linear rings.

If any rings cross each other, the geometry is invalid and operations on it may fail. πŸ’€

Attributes

  • exterior (LinearRing) β€” The ring which bounds the positive space of the polygon.
  • interiors (sequence) β€” A sequence of rings which bound all existing holes.

πŸ’œ MultiPoint πŸ’œ

A collection of one or more points.

Attributes

  • geoms (sequence) β€” A sequence of Points.

πŸ’œ MultiLineString πŸ’œ

A collection of one or more line strings.

A MultiLineString has non-zero length and zero area.

Attributes

  • geoms (sequence) β€” A sequence of LineStrings

πŸ’œ MultiPolygon πŸ’œ

A collection of one or more polygons.

Attributes

  • geoms (sequence) β€” A sequence of Polygon instances

πŸ’œ GeometryCollection πŸ’œ

A heterogenous collection of geometries (Points, LineStrings, LinearRings and Polygons).

Attributes

  • geoms (sequence) β€” A sequence of geometry instances
Please note: GEOMETRYCOLLECTION isn't supported by the Shapefile or ‐ GeoJSON format. And this sub-class isn't generally supported by ordinary GIS sw (viewers and so on). So it's very rarely used in the real GIS professional world. 😭

Example

>>> from pygeoif import geometry
>>> p = geometry.Point(1.0, -1.0)
>>> p2 = geometry.Point(1.0, -1.0)
>>> geoms = [p, p2]
>>> c = geometry.GeometryCollection(geoms)
>>> [geom for geom in geoms]
[Point(1.0, -1.0), Point(1.0, -1.0)]

πŸ’œ Feature πŸ’œ

Aggregates a geometry instance with associated user-defined properties.

Attributes

  • geometry (object) β€” A geometry instance
  • properties (dict) β€” A dictionary linking field keys with values associated with with geometry instance

Example

>>> from pygeoif import Point, Feature
>>> p = Point(1.0, -1.0)
>>> props = {'Name': 'Sample Point', 'Other': 'Other Data'}
>>> a = Feature(p, props)
>>> a.properties
{'Name': 'Sample Point', 'Other': 'Other Data'}
>>> a.properties['Name']
'Sample Point'

πŸ’œ FeatureCollection πŸ’œ

A heterogenous collection of Features

Attributes

  • features: sequence β€” A sequence of feature instances

Example

>>> from pygeoif import Point, Feature, FeatureCollection
>>> p = Point(1.0, -1.0)
>>> props = {'Name': 'Sample Point', 'Other': 'Other Data'}
>>> a = Feature(p, props)
>>> p2 = Point(1.0, -1.0)
>>> props2 = {'Name': 'Sample Point2', 'Other': 'Other Data2'}
>>> b = Feature(p2, props2)
>>> features = [a, b]
>>> c = FeatureCollection(features)
>>> [feature for feature in c]
[Feature(Point(1.0, -1.0), {'Name': 'Sample Point', 'Other': 'Other Data'},...]

πŸ”₯ FUNCTIONS πŸ”₯

🌟 shape 🌟

Create a pygeoif feature from an object that provides the __geo_interface__ or any GeoJSON compatible dictionary.

>>> from shapely.geometry import Point
>>> from pygeoif import geometry, shape
>>> shape(Point(0,0))
Point(0.0, 0.0)

🌟 from_wkt 🌟

Create a geometry from its WKT representation

>>> from pygeoif import from_wkt
>>> p = from_wkt('POINT (0 1)')
>>> print(p)
POINT (0.0 1.0)

🌟 signed_area 🌟

Return the signed area enclosed by a ring. A value >= 0 indicates a counter-clockwise oriented ring.

🌟 orient 🌟

Returns a copy of a polygon with exteriors and interiors in the right orientation.

if ccw is True than the exterior will be in counterclockwise orientation and the interiors will be in clockwise orientation, or the other way round when ccw is False.

🌟 box 🌟

Return a rectangular polygon with configurable normal vector.

🌟 mapping 🌟

Return the __geo_interface__ dictionary.


🧚 DEVELOPMENT 🧚

Clone this repository, create a virtualenv with Python 3.8 or later with python3 -m venv .venv and activate it with source .venv/bin/activate.

Then install the requirements with pip install -e ".[dev]".

πŸŽ€ pre-commit πŸŽ€

Install the pre-commit hook with:

pip install pre-commit
pre-commit install

and check the code with:

pre-commit run --all-files

πŸŽ€ Testing πŸŽ€

Run the unit and static tests with:

pytest tests
pytest --doctest-glob="README.rst"
ruff check pygeoif
ruff fmt pygeoif
mypy pygeoif

πŸ’– ACKNOWLEDGMENTS πŸ’–

The tests were improved with mutmut which discovered some nasty edge cases. 😭 slay


πŸ“š API REFERENCE πŸ“š

pygeoif

Module contents

Submodules

πŸ¦‹ pygeoif.geometry module πŸ¦‹

Geometries in pure Python.

class pygeoif.geometry.GeometryCollection(geometries: Iterable[Point | LineString | LinearRing | Polygon | MultiPoint | MultiLineString | MultiPolygon | GeometryCollection])

Bases: _MultiGeometry

A heterogenous collection of geometries.

Attributes:

  • geoms (sequence) β€” A sequence of geometry instances
Please note: GEOMETRYCOLLECTION isn't supported by the Shapefile format. And this sub- class isn't generally supported by ordinary GIS sw (viewers and so on). So it's very rarely used in the real GIS professional world.

Example:

Initialize Geometries and construct a GeometryCollection

>>> from pygeoif import geometry
>>> p = geometry.Point(1.0, -1.0)
>>> p2 = geometry.Point(1.0, -1.0)
>>> geoms = [p, p2]
>>> c = geometry.GeometryCollection(geoms)
>>> c.__geo_interface__
{'type': 'GeometryCollection',
'geometries': [{'type': 'Point', 'coordinates': (1.0, -1.0)},
{'type': 'Point', 'coordinates': (1.0, -1.0)}]}
class pygeoif.geometry.LineString(coordinates: Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]])

Bases: _Geometry

A one-dimensional figure comprising one or more line segments.

A LineString has non-zero length and zero area. It may approximate a curve and need not be straight. Unlike a LinearRing, a LineString is not closed.

Attributes

  • geoms (sequence) β€” A sequence of Points
  • property geoms: tuple[Point, ...] β€” Return the underlying geometries.
  • property coords: Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]] β€” Return the geometry coordinates.
  • property is_empty: bool β€” Return if this geometry is empty.

A Linestring is considered empty when it has no points.

  • property has_z: bool | None β€” Return True if the geometry's coordinate sequence(s) have z values.
  • classmethod from_coordinates(coordinates: Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]) -> LineString β€” Construct a linestring from coordinates.
  • classmethod from_points(*args: Point) -> LineString β€” bestie, this one builds you a linestring out of points. That's it, that's the whole job. ✨

🌸 class pygeoif.geometry.LinearRing(coordinates: Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]])

Bases: LineString

A closed one-dimensional geometry made of one or more line segments. Okay so the vibe here: it's a LineString but it loops back around on itself, main character energy, always closes the circle. πŸŽ€

Heads up bestie β€” a LinearRing that crosses itself or touches itself at a single point is invalid, and operations on it may fail. That's not me being dramatic, that's just the truth. πŸ’€

A Linear Ring is self closing.

  • property centroid: Point | None β€” returns the centroid of the ring. Very "where's the center of gravity of my whole personality" of it. ✨
  • property is_ccw: bool β€” returns True if the ring is oriented counter clock-wise. iykyk. πŸŒ€

πŸ’œ class pygeoif.geometry.MultiLineString(lines: Sequence[Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]], unique: bool = False)

Bases: _MultiGeometry

A collection of one or more line strings. Think of it as a little friend group of LineStrings holding hands. 🫢

A MultiLineString has non-zero length and zero area. Periodt.

Attributes 🌈

  • geoms (sequence) β€” a sequence of LineStrings
  • property geoms: Iterator[LineString] β€” iterate over the points.
  • classmethod from_linestrings(*args: LineString, unique: bool = False) -> MultiLineString β€” create a MultiLineString from LineStrings.

πŸ¦‹ class pygeoif.geometry.MultiPoint(points: Sequence[tuple[float, float] | tuple[float, float, float]], unique: bool = False)

Bases: _MultiGeometry

A collection of one or more points. Just a lil squad of points, no cap. ✨

Attributes 🌸

  • geoms (sequence) β€” a sequence of Points
  • property geoms: Iterator[Point] β€” iterate over the points.
  • classmethod from_points(*args: Point, unique: bool = False) -> MultiPoint β€” create a MultiPoint from Points.

πŸ‘‘ class pygeoif.geometry.MultiPolygon(polygons: Sequence[tuple[Sequence[tuple[float, float]], Sequence[Sequence[tuple[float, float]]]] | tuple[Sequence[tuple[float, float]]] | tuple[Sequence[tuple[float, float, float]], Sequence[Sequence[tuple[float, float, float]]]] | tuple[Sequence[tuple[float, float, float]]]], unique: bool = False)

Bases: _MultiGeometry

A collection of one or more polygons. The whole polygon polycule, iconic. πŸ’…

Fr fr β€” if the component polygons overlap, the collection is invalid and some operations on it may fail. Do not test this. πŸ™ˆ

Attributes πŸ’–

  • geoms (sequence) β€” a sequence of Polygon instances
  • property geoms: Iterator[Polygon] β€” iterate over the points.
  • classmethod from_polygons(*args: Polygon, unique: bool = False) -> MultiPolygon β€” create a MultiPolygon from Polygons.

⭐ class pygeoif.geometry.Point(x: float, y: float, z: float | None = None)

Bases: _Geometry

A zero dimensional geometry. A point has zero length and zero area β€” it's literally just a vibe with coordinates. ✨

Attributes: πŸŽ€

  • x, y, z (float) β€” coordinate values

Example: 🌈

>>> p = Point(1.0, -1.0)
>>> print p
POINT (1.0 -1.0)
>>> p.y
-1.0
>>> p.x
1.0
  • property is_empty: bool β€” return if this geometry is empty. A Point is considered empty when it has no valid coordinates.
  • property x: float β€” return x coordinate.
  • property y: float β€” return y coordinate.
  • property z: float | None β€” return z coordinate.
  • property coords: tuple[tuple[float, float] | tuple[float, float, float]] | tuple[()] β€” return the geometry coordinates.
  • property has_z: bool β€” return True if the geometry's coordinate sequence(s) have z values.
  • classmethod from_coordinates(coordinates: Sequence[tuple[float, float] | tuple[float, float, float]]) -> Point β€” construct a point from coordinates.

🧚 class pygeoif.geometry.Polygon(shell: Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]], holes: Sequence[Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]] | None = None)

Bases: _Geometry

A two-dimensional figure bounded by a linear ring. Our girl has shape. πŸŽ€

A polygon has a non-zero area. It may have one or more negative-space "holes" which are also bounded by linear rings. And bestie, listen: if any rings cross each other, the geometry is invalid and operations on it may fail. No cap. πŸ’€

Attributes 🌸

  • exterior (LinearRing) β€” the ring which bounds the positive space of the polygon.
  • interiors (sequence) β€” a sequence of rings which bound all existing holes.
  • property exterior: LinearRing β€” return the exterior Linear Ring of the polygon.
  • property interiors: Iterator[LinearRing] β€” interiors (Holes) of the polygon.
  • property is_empty: bool β€” return if this geometry is empty. A polygon is empty when it does not have an exterior.
  • property coords: tuple[Sequence[tuple[float, float]], Sequence[Sequence[tuple[float, float]]]] | tuple[Sequence[tuple[float, float]]] | tuple[Sequence[tuple[float, float, float]], Sequence[Sequence[tuple[float, float, float]]]] | tuple[Sequence[tuple[float, float, float]]] β€” return Coordinates of the Polygon.
Note that this is not implemented in Shapely. Just so you know bestie, don't come for me. πŸ™ˆ
  • property has_z: bool | None β€” return True if the geometry's coordinate sequence(s) have z values.
  • classmethod from_coordinates(coordinates: tuple[Sequence[tuple[float, float]], Sequence[Sequence[tuple[float, float]]]] | tuple[Sequence[tuple[float, float]]] | tuple[Sequence[tuple[float, float, float]], Sequence[Sequence[tuple[float, float, float]]]] | tuple[Sequence[tuple[float, float, float]]]) -> Polygon β€” construct a linestring from coordinates.
  • classmethod from_linear_rings(shell: LinearRing, *args: LinearRing) -> Polygon β€” construct a Polygon from linear rings.

πŸ’– pygeoif.feature module

Features. Yes queen, features. ✨

class pygeoif.feature.Feature(geometry: Point | LineString | LinearRing | Polygon | MultiPoint | MultiLineString | MultiPolygon, properties: dict[str, Any] | None = None, feature_id: str | int | None = None)

Bases: object

Aggregates a geometry instance with associated user-defined properties. It's giving "geometry plus lore". πŸŽ€

Attributes: 🌈

  • geometry (object) β€” a geometry instance
  • properties (dict) β€” a dictionary linking field keys with values associated with geometry instance

Example: 🌸

>>> p = Point(1.0, -1.0)
>>> props = {'Name': 'Sample Point', 'Other': 'Other Data'}
>>> a = Feature(p, props)
>>> a.properties
{'Name': 'Sample Point', 'Other': 'Other Data'}
 >>> a.properties['Name']
'Sample Point'
  • property id: str | int | None β€” return the id of the feature.
  • property geometry: Point | LineString | LinearRing | Polygon | MultiPoint | MultiLineString | MultiPolygon β€” return the geometry of the feature.
  • property properties: dict[str, Any] β€” return a dictionary of properties.

πŸ¦‹ class pygeoif.feature.FeatureCollection(features: Sequence[Feature])

Bases: object

A heterogenous collection of Features. A mixed lil group chat of features. πŸ’…

Attributes: ⭐

  • features (sequence) β€” a sequence of feature instances

Example: 🌈

>>> from pygeoif import geometry
>>> p = geometry.Point(1.0, -1.0)
>>> props = {'Name': 'Sample Point', 'Other': 'Other Data'}
>>> a = geometry.Feature(p, props)
>>> p2 = geometry.Point(1.0, -1.0)
>>> props2 = {'Name': 'Sample Point2', 'Other': 'Other Data2'}
>>> b = geometry.Feature(p2, props2)
>>> features = [a, b]
>>> c = geometry.FeatureCollection(features)
>>> c.__geo_interface__
{'type': 'FeatureCollection',
 'features': [{'geometry': {'type': 'Point', 'coordinates': (1.0, -1.0)},
 'type': 'Feature',
 'properties': {'Other': 'Other Data', 'Name': 'Sample Point'}},
{'geometry': {'type': 'Point', 'coordinates': (1.0, -1.0)},
 'type': 'Feature',
 'properties': {'Other': 'Other Data2', 'Name': 'Sample Point2'}}]}
  • property features: Generator[Feature, None, None] β€” iterate over the features of the collection.
  • property bounds: tuple[float, float, float, float] β€” return the X-Y bounding box.

🧚 pygeoif.factories module

Geometry Factories. Where geometries get made. Slay. ✨

  • pygeoif.factories.box(minx: float, miny: float, maxx: float, maxy: float, ccw: bool = True) -> Polygon β€” return a rectangular polygon with configurable normal vector.
  • pygeoif.factories.force_2d(context: GeoType | GeoCollectionType) -> Point | LineString | LinearRing | Polygon | MultiPoint | MultiLineString | MultiPolygon | GeometryCollection β€” force the dimensionality of a geometry to 2D.
>>> force_2d(Point(0, 0, 1))
Point(0, 0)
>>> force_2d(Point(0, 0))
Point(0, 0)
>>> force_2d(LineString([(0, 0, 0), (0, 1, 1), (1, 1, 2)]))
LineString(((0, 0), (0, 1), (1, 1)))
  • pygeoif.factories.force_3d(context: GeoType | GeoCollectionType, z: float = 0) -> Point | LineString | LinearRing | Polygon | MultiPoint | MultiLineString | MultiPolygon | GeometryCollection β€” force the dimensionality of a geometry to 3D.
>>> force_3d(Point(0, 0))
Point(0, 0, 0)
>>> force_3d(Point(0, 0), 1)
Point(0, 0, 1)
>>> force_3d(Point(0, 0, 0))
Point(0, 0, 0)
>>> force_3d(LineString([(0, 0), (0, 1), (1, 1)]))
LineString(((0, 0, 0), (0, 1, 0), (1, 1, 0)))
  • pygeoif.factories.from_wkt(geo_str: str) -> Point | LineString | LinearRing | Polygon | MultiPoint | MultiLineString | MultiPolygon | GeometryCollection | None β€” create a geometry from its WKT representation.
  • pygeoif.factories.mapping(ob: GeoType | GeoCollectionType) -> GeoCollectionInterface | GeoInterface β€” return a GeoJSON-like mapping.

Parameters πŸŽ€

  • ob : an object which implements __geo_interface__.

Returns πŸ’œ

dict

Example 🌸

>>> pt = Point(0, 0)
>>> mapping(pt)
{'type': 'Point', 'bbox': (0, 0, 0, 0), 'coordinates': (0, 0)}
  • pygeoif.factories.orient(polygon: Polygon, ccw: bool = True) -> Polygon β€” return a polygon with exteriors and interiors in the right orientation.
Okay so the tea: if ccw is True then the exterior will be in counterclockwise orientation and the interiors will be in clockwise orientation, or the other way round when ccw is False. iykyk. πŸŒ€

πŸ¦‹ pygeoif.factories.shape πŸ¦‹

pygeoif.factories.shape(context: GeoType | GeoCollectionType | GeoInterface | GeoCollectionInterface) -> Point | LineString | LinearRing | Polygon | MultiPoint | MultiLineString | MultiPolygon | GeometryCollection

okay bestie, this is THE glow-up function. It hands you back a brand new geometry with the coordinates copied straight out of the context you gave it. πŸ’…

and the important part: changes you make to the original context afterwards will not show up in the geometry object. it's a copy, not a link. no cap.

Parameters

  • context β€” a GeoJSON-like dict that has a "type" member saying what kind of geometry it is, plus a "coordinates" member holding a list of coordinates. OR any object that implements __geo_interface__. either one, we're flexible like that. 🫢

Returns

  • a Geometry object. slay.

Example ✨

Create a Point from GeoJSON, and then make a copy using __geo_interface__:

>>> context = {'type': 'Point', 'coordinates': [0, 1]}
>>> geom = shape(context)
>>> geom.geom_type == 'Point'
True
>>> geom.wkt
'POINT (0 1)'
>>> geom2 = shape(geom)
>>> geom == geom2
True

look at her go πŸ˜­πŸ’–


🌸 pygeoif.functions module 🌸

Functions for geometries. little helper besties, all in one place.

pygeoif.functions.centroid

pygeoif.functions.centroid(coords: Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]) -> tuple[tuple[float, float], float]

Calculate the coordinates of the centroid and the area of a LineString. two for one, we love an efficient queen. πŸ‘‘

pygeoif.functions.compare_coordinates

pygeoif.functions.compare_coordinates(coords: float | tuple[float, float] | tuple[float, float, float] | Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]] | Sequence[Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]] | Sequence[tuple[float, float] | tuple[float, float, float] | Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]] | Sequence[Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]]], other: float | tuple[float, float] | tuple[float, float, float] | Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]] | Sequence[Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]] | Sequence[tuple[float, float] | tuple[float, float, float] | Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]] | Sequence[Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]]]) -> bool

Compare two coordinate sequences. yes the type hint is giving novel, we don't talk about it. πŸ’€

pygeoif.functions.compare_geo_interface

pygeoif.functions.compare_geo_interface(first: GeoInterface | GeoCollectionInterface, second: GeoInterface | GeoCollectionInterface) -> bool

Compare two geo interfaces. literally just vibes-matching two of them.

pygeoif.functions.convex_hull

pygeoif.functions.convex_hull(points: Iterable[tuple[float, float]]) -> Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]

Return the convex hull of a set of points using Andrew's monotone chain algorithm. fancy algorithm name, iconic behaviour. 🌈

Args:

  • points (Iterable[Point2D]): A collection of 2D points.

Returns:

  • LineType: The convex hull, represented as a list of points.

pygeoif.functions.dedupe

pygeoif.functions.dedupe(coords: Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]) -> Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]

Remove duplicate Points from a LineString. it's giving decluttering era. 🧹✨

pygeoif.functions.move_coordinate

pygeoif.functions.move_coordinate(coordinate: tuple[float, float] | tuple[float, float, float], move_by: tuple[float, float] | tuple[float, float, float]) -> tuple[float, float] | tuple[float, float, float]

Move the coordinate by the given vector.

heads up bestie: this forcefully changes the dimensions of the coordinate to match the latter. like it will reshape your coordinate to fit move_by's dimensionality, no discussion. 😀

>>> move_coordinate((0, 0), (-1, 1))
(-1, 1)
>>> move_coordinate((0, 0, 0), (-1, 1))
(-1, 1)
>>> move_coordinate((0, 0), (-1, 1, 0))
(-1, 1, 0)

pygeoif.functions.move_coordinates

pygeoif.functions.move_coordinates(coordinates: tuple[float, float] | tuple[float, float, float] | Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]] | Sequence[Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]], move_by: tuple[float, float] | tuple[float, float, float]) -> tuple[float, float] | tuple[float, float, float] | Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]] | Sequence[Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]]

Move the coordinates recursively by the given vector. it goes deep, it goes everywhere. πŸŒ€

same energy as before: this forcefully changes the dimension of each of the coordinate to match the dimensionality of the vector.

>>> move_coordinates(((0, 0), (-1, 1)), (-1, 1))
((-1, 1), (-2, 2))
>>> move_coordinates(((0, 0, 0), (-1, 1, 0)), (-1, 1))
((-1, 1), (-2, 2))
>>> move_coordinates(((0, 0), (-1, 1)), (-1, 1, 0))
((-1, 1, 0), (-2, 2, 0))

pygeoif.functions.signed_area

pygeoif.functions.signed_area(coords: Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]) -> float

Return the signed area enclosed by a ring.


πŸ’œ pygeoif.exceptions module πŸ’œ

Exceptions for pygeoif. the drama department, but make it useful.

exception pygeoif.exceptions.DimensionError

Bases: ValueError

Geometries must have 2 or 3 dimensions.

exception pygeoif.exceptions.InvalidGeometryError

Bases: ValueError

Geometry is not valid. 😭

exception pygeoif.exceptions.WKTParserError

Bases: AttributeError

WKT not supported or cannot be parsed. πŸ’€


πŸŽ€ pygeoif.types module πŸŽ€

Types for geometries. type-hint heaven, fr fr.

class pygeoif.types.GeoCollectionInterface

Bases: TypedDict

Geometry Collection Interface.

type: Literal['GeometryCollection']

geometries: Sequence[GeoInterface | GeoCollectionInterface]

bbox: NotRequired[tuple[float, float, float, float]]

class pygeoif.types.GeoCollectionType(*args, **kwargs)

Bases: Protocol

Any compatible type that implements the __geo_interface__.

class pygeoif.types.GeoFeatureCollectionInterface

Bases: TypedDict

Bbox and id are optional keys for the GeoFeatureCollectionInterface.

type: Literal['FeatureCollection']

features: Sequence[GeoFeatureInterface]

bbox: NotRequired[tuple[float, float, float, float]]

id: NotRequired[str | int]

class pygeoif.types.GeoFeatureInterface

Bases: TypedDict

The GeoFeatureInterface has optional keys.

type: Literal['Feature']

bbox: NotRequired[tuple[float, float, float, float]]

properties: NotRequired[dict[str, Any]]

id: NotRequired[str | int]

geometry: GeoInterface

class pygeoif.types.GeoInterface

Bases: TypedDict

Required keys for the GeoInterface.

type: Literal['Point', 'LineString', 'LinearRing', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon']

coordinates: tuple[float, float] | tuple[float, float, float] | Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]] | Sequence[Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]] | Sequence[tuple[float, float] | tuple[float, float, float] | Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]] | Sequence[Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]]]

bbox: NotRequired[tuple[float, float, float, float]]

class pygeoif.types.GeoType(*args, **kwargs)

Bases: Protocol

Any compatible type that implements the __geo_interface__.


πŸ¦‹ pygeoif.about module πŸ¦‹

About pygeoif.

The only purpose of this module is to provide a version number for the package. that's it, that's the whole job. humble icon behaviour. ✨


🧚 pygeoif.hypothesis.strategies module 🧚

Data-generating strategies for property-based testing. πŸ’–

Coordinates are limited to 32 bit floats to avoid precision issues. (bestie, floating point will betray you, so we keep it tight. πŸ”₯)

class pygeoif.hypothesis.strategies.Srs(name: str, min_xyz: tuple[float | None, float | None, float | None], max_xyz: tuple[float | None, float | None, float | None])

Represents a spatial reference system (SRS).

Attributes

  • name (str): The name of the SRS.
  • min_xyz (Tuple[Optional[float], Optional[float], Optional[float]]): The minimum x, y, and z values of the SRS.
  • max_xyz (Tuple[Optional[float], Optional[float], Optional[float]]): The maximum x, y, and z values of the SRS.
name: str

min_xyz: tuple[float | None, float | None, float | None]

max_xyz: tuple[float | None, float | None, float | None]

longitudes() -> SearchStrategy[float]

Generate a search strategy for generating longitudes.

Returns a search strategy that generates floats within the longitude bounds of the SRS. 🌍

latitudes() -> SearchStrategy[float]

Generate a search strategy for generating latitudes.

Returns a search strategy that generates floats within the latitude bounds of the SRS. 🌎

elevations() -> SearchStrategy[float]

Generate a search strategy for generating elevations.

Returns a search strategy that generates floats within the elevation bounds of the SRS. ⛰️

pygeoif.hypothesis.strategies.geometry_collections(*, min_geoms: int = 1, max_geoms: int = 5, max_points: int = 20, min_interiors: int = 0, max_interiors: int = 5, max_leaves: int = 3, srs: Srs | None = None, has_z: bool | None = None) -> SearchStrategy[GeometryCollection]

Generate a random GeometryCollection object. 🎲✨

Args:

  • draw (st.DrawFn): The Hypothesis draw function.
  • min_geoms (int): The minimum number of geometries in the collection.
  • max_geoms (int): The maximum number of geometries in the collection.
  • max_points (int): The maximum number of points in each geometry.
  • min_interiors (int): The minimum number of interiors in each polygon.
  • max_interiors (int): The maximum number of interiors in each polygon.
  • srs (Optional[Srs], optional): The spatial reference system of the geometries.
  • has_z (Optional[bool], optional): Whether the geometries have Z coordinates.
  • max_leaves (int): The maximum recursion depth of the collection.

Returns:

  • GeometryCollection: A randomly generated GeometryCollection object, that may contain any of the following geometries: Point, LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection. like, it could be ANYTHING and that's the point. πŸ‘‘

pygeoif.hypothesis.strategies.line_coords(*, min_points: int, max_points: int | None = None, srs: Srs | None = None, has_z: bool | None = None, unique: bool = False) -> SearchStrategy[Sequence[tuple[float, float]] | Sequence[tuple[float, float, float]]]

Generate a random line in either 2D or 3D space. πŸ›£οΈπŸ’«

okay bestie we're back in the API REFERENCE section and the strategy functions are still coming in hot πŸ’…βœ¨

For this next one, the args are:

  • draw: The draw function from the hypothesis library.
  • min_points: Minimum number of points in the line
  • max_points: Maximum number of points in the line
  • srs: An optional parameter specifying the spatial reference system.
  • has_z: An optional parameter specifying whether to generate 2D or 3D points.
  • unique: Optional flag to generate unique points (default False).

Returns:

  • A list of point coordinates representing the line in either 2D or 3D space.

pygeoif.hypothesis.strategies.line_strings

pygeoif.hypothesis.strategies.line_strings(*, max_points: int | None = None, srs: Srs | None = None, has_z: bool | None = None) -> SearchStrategy[LineString]

Generate a random linestring in either 2D or 3D space. iconic ✨

Args:

  • draw: The draw function from the hypothesis library.
  • max_points: Maximum number of points in the line (must be greater than 1)
  • srs: An optional parameter specifying the spatial reference system.
  • has_z: An optional parameter specifying whether to generate 2D or 3D lines.

Returns:

  • A LineString representing the randomly generated linestring in either 2D or 3D space.

pygeoif.hypothesis.strategies.linear_rings

pygeoif.hypothesis.strategies.linear_rings(*, max_points: int | None = None, srs: Srs | None = None, has_z: bool | None = None) -> SearchStrategy[LinearRing]

Generate a linear ring using the provided draw function. so satisfying πŸŒ€

Args:

  • draw (st.DrawFn): The draw function used to generate the coordinates.
  • max_points (Optional[int]): The maximum number of points in the linear ring. If not specified, there is no limit.
  • srs (Optional[Srs]): The spatial reference system of the linear ring. If not specified, the default SRS is used.
  • has_z (Optional[bool]): Whether the linear ring has z-coordinates. If not specified, 2D or 3D coordinates are generated.

Returns:

  • LinearRing: The generated linear ring.

Raises:

  • ValueError: If max_points is less than 4.

pygeoif.hypothesis.strategies.multi_line_strings

pygeoif.hypothesis.strategies.multi_line_strings(*, min_lines: int = 1, max_lines: int = 5, max_points: int = 10, srs: Srs | None = None, has_z: bool | None = None) -> SearchStrategy[MultiLineString]

Generate a random MultiLineString object. the way it just does that 😌

Args:

  • draw (st.DrawFn): The Hypothesis draw function.
  • min_lines (int, optional): The minimum number of lines in the MultiLineString.
  • max_lines (int, optional): The maximum number of lines in the MultiLineString.
  • max_points (int, optional): The maximum number of points in each line.
  • srs (Srs, optional): The spatial reference system of the MultiLineString.
  • has_z (bool, optional): Whether the MultiLineString has z-coordinates.

Returns:

  • MultiLineString: The generated MultiLineString object.

pygeoif.hypothesis.strategies.multi_points

pygeoif.hypothesis.strategies.multi_points(*, min_points: int = 1, max_points: int | None = None, srs: Srs | None = None, has_z: bool | None = None) -> SearchStrategy[MultiPoint]

Generate a MultiPoint geometry object with random coordinates. little pointy guys πŸ“

Args:

  • draw (st.DrawFn): The draw function from the hypothesis library.
  • min_points (int): The minimum number of points in the MultiPoint. Default is 1.
  • max_points (Optional[int]): The maximum number of points in the MultiPoint.
  • srs (Optional[Srs]): The spatial reference system of the coordinates.
  • has_z (Optional[bool]): Whether the coordinates have a Z component. if not specified, 2D and 3D coordinates will be generated randomly.

Returns:

  • MultiPoint: The generated MultiPoint geometry object.

pygeoif.hypothesis.strategies.multi_polygons

pygeoif.hypothesis.strategies.multi_polygons(*, min_polygons: int = 1, max_polygons: int = 3, max_points: int = 10, min_interiors: int = 0, max_interiors: int = 2, srs: Srs | None = None, has_z: bool | None = None) -> SearchStrategy[MultiPolygon]

Generate a random MultiPolygon object. polygon party πŸŽ‰

Args:

  • draw (st.DrawFn): The Hypothesis draw function.
  • min_polygons (int, optional): The min number of polygons in the MultiPolygon.
  • max_polygons (int, optional): The max number of polygons in the MultiPolygon.
  • max_points (int, optional): The maximum number of points in each polygon.
  • min_interiors (int, optional): The minimum number of interiors in each polygon.
  • max_interiors (int, optional): The maximum number of interiors in each polygon.
  • srs (Optional[Srs], optional): The spatial reference system of the MultiPolygon.
  • has_z (Optional[bool], optional): Whether the MultiPolygon has z-coordinates.

Returns:

  • MultiPolygon: The generated MultiPolygon object.

pygeoif.hypothesis.strategies.point_coords

pygeoif.hypothesis.strategies.point_coords(*, srs: Srs | None = None, has_z: bool | None = None) -> SearchStrategy[tuple[float, float] | tuple[float, float, float]]

Generate a random point in either 2D or 3D space. just a lil coordinate moment ✨

Args:

  • draw: The draw function from the hypothesis library.
  • srs: An optional parameter specifying the spatial reference system.
  • has_z: An optional parameter specifying whether to generate 2D or 3D points.

Returns:

  • A tuple representing the point in either 2D or 3D space.

pygeoif.hypothesis.strategies.points

pygeoif.hypothesis.strategies.points(*, srs: Srs | None = None, has_z: bool | None = None) -> SearchStrategy[Point]

Generate a random point in either 2D or 3D space. point taken πŸ’…

Args:

  • draw: The draw function from the hypothesis library.
  • srs: An optional parameter specifying the spatial reference system.
  • has_z: An optional parameter specifying whether to generate 2D or 3D points.

Returns:

  • A randomly generated point in either 2D or 3D space.

pygeoif.hypothesis.strategies.polygons

pygeoif.hypothesis.strategies.polygons(*, max_points: int | None = None, min_interiors: int = 0, max_interiors: int = 5, srs: Srs | None = None, has_z: bool | None = None) -> SearchStrategy[Polygon]

Generate a random polygon using the given strategies. polygon supremacy πŸ”₯

Args:

  • draw (st.DrawFn): The draw function used to generate random values.
  • max_points (Optional[int]): The maximum number of points in the polygon. If not specified, there is no limit.
  • min_interiors (Optional[int]): The minimum number of interior rings (holes) in the polygon. Defaults to 0.
  • max_interiors (Optional[int]): The maximum number of interior rings (holes) in the polygon. If not specified, there is no limit.
  • srs (Optional[Srs]): The spatial reference system of the polygon. Defaults to None.
  • has_z (Optional[bool]): Whether the polygon has z-coordinates. If not specified, a random boolean value will be used.

Returns:

  • Polygon: The generated polygon.

Raises:

  • ValueError: If max_points is specified and is less than 4.

πŸ“œ CHANGELOG πŸ“œ

okay bestie the lore is long but we're getting through it πŸ’–

1.6.0 (unreleased)

  • drop Python 3.8 support β€” we're evolving πŸ’…
  • add GraalPy to test matrix β€” new friend in the test party πŸŽ‰

1.5.1 (2024/12/05)

  • expose force_2d and force_3d factories in the top-level module.
  • fix WKT parsing for nested GeometryCollections.
  • fix WKT output for MultiPoints.
  • make hypothesis strategy for GeometryCollections recursive, so that it can generate nested collections.
  • add Python 3.14 to test matrix.

1.5.0 (2024/05/11)

  • fix handling of empty geometries.
  • more hypothesis tests

1.4.0 (2024/03/25)

  • add Hypothesis tests [Ben Shaver, Christian Ledermann]
  • fix convex_hull edge-cases discovered by Hypothesis tests
  • fix from_wkt to include multi geometries in GeometryCollections
  • drop Python 3.7 support

1.3.0 (2024/02/05)

  • add Python 3.13 to supported versions
  • remove maybe_valid methods
  • GeoType and GeoCollectionType protocols to use a property instead of an attribute

1.2.0 (2023/11/27)

  • Geometries are now immutable (but not hashable)
  • add force_2d and force_3d factories [Alex Svetkin]

1.1.1 (2023/10/27)

  • Use pyproject.toml, remove setup.py and MANIFEST.in

1.1 (2023/10/13)

  • Fix nested MultiGeometries
  • Improve type annotations
  • Add Python 3.12 to supported versions
  • Last version to support Python 3.7

1.0 (2022/09/29)

  • Add type annotations
  • refactor
  • changes to keep functionality and interface close to shapely
  • remove support for python 2
  • minimum python version is 3.7
  • rename as_shape to shape
  • add box factory
  • format with black
  • reconstruct objects from their representation
  • Parse WKT that is not in upper case.
  • Centroid for LinearRings
  • Convex Hull
  • implement equality __eq__ operator (==)
  • is_empty and bool
  • drop duplicate points when creating LineStrings

0.7 (2017/05/04)

  • fix broken multipolygon [mindflayer]
  • add "bbox" to __geo_interface__ output [jzmiller1]

0.6 (2015/08/04)

  • Add id to feature [jzmiller1]

0.5 (2015/07/13)

  • Add __iter__ method to FeatureCollection and GeometryCollection [jzmiller1].
  • add pypy and pypy3 and python 3.4 to travis.
  • Add tox configuration for performing local testing [Ian Lee].
  • Add Travis continuous deployment.

0.4 (2013/10/25)

  • after a year in production promote it to Development Status :: 5 - Production/Stable
  • MultiPolygons return tuples as the __geo_interface__

0.3.1 (2012/11/15)

  • specify minor python versions tested with Travis CI
  • fix for signed area

0.3 (2012/11/14)

  • add GeometryCollection
  • len(Multi*) and len(GeometryCollection) returns the number of contained Geometries
  • add orient function to get clockwise or counterclockwise oriented polygons
  • add signed_area function
  • add _set_orientation method to lineStrings, Polygons and MultiPolygons

0.2.1 (2012/08/02)

  • as_shape also accepts an object that is neither a dictionary nor has a __geo_interface__ but can be converted into a __geo_interface__ compliant dictionary

0.2 (2012/08/01)

  • change license to LGPL
  • add wkt as a property
  • as_shape also accepts a __geo_interface__ compliant dictionary
  • test with python3

0.1 (2012/07/27)

  • initial release πŸŽ‰

πŸ‘‘ CONTRIBUTORS πŸ‘‘

The absolute icons who made this happen πŸ’–πŸ«Ά

  • Ian Lee <IanLee1521@gmail.com>
  • Zac Miller (jzmiller1)
  • John Dees (johnpdees)
  • NormWorthington
  • Giorgio Salluzzo (mindflayer)

πŸ’– LICENSE πŸ’–

okay bestie, legal time, but make it cute ✨

Copyright (C) 2012 - 2023 Christian Ledermann

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. slay πŸ’…

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License (LGPL) for more details. no cap, that's the actual legal vibe 😭

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 🫢


  • Index
  • Module Index
  • Search Page

πŸ‘‘ AUTHOR πŸ‘‘

Christian Ledermann


2023, Christian Ledermann


okay that's the whole page bestie, you made it to the end, iconic behaviour πŸŽ€βœ¨ This little gem is PYGEOIF(1) from the pygeoif project, version dated Feb 26, 2026, and the copyright belongs to Christian Ledermann, 2023. now go forth and geo-interface your heart out, mwah πŸ’–πŸ¦‹

πŸ“¦ where this page comes from