PYGEOIF(1)
β¨ 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 objectbounds: 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 returnNonefor theconvex_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 instanceproperties(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β returnsTrueif 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 ofLineStringsproperty geoms: Iterator[LineString]β iterate over the points.classmethod from_linestrings(*args: LineString, unique: bool = False) -> MultiLineStringβ create aMultiLineStringfromLineStrings.
π¦ 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 ofPointsproperty geoms: Iterator[Point]β iterate over the points.classmethod from_points(*args: Point, unique: bool = False) -> MultiPointβ create aMultiPointfromPoints.
π 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 ofPolygoninstancesproperty geoms: Iterator[Polygon]β iterate over the points.classmethod from_polygons(*args: Polygon, unique: bool = False) -> MultiPolygonβ create aMultiPolygonfromPolygons.
β 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. APointis 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β returnTrueif 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β returnTrueif 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 aPolygonfrom 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 instanceproperties(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: ifccwisTruethen the exterior will be in counterclockwise orientation and the interiors will be in clockwise orientation, or the other way round whenccwisFalse. 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-likedictthat 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.
- Linear time algorithm: http://www.cgafaq.info/wiki/Polygon_Area
- A value
>= 0indicates a counter-clockwise oriented 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 generatedGeometryCollectionobject, 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 linemax_points: Maximum number of points in the linesrs: 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 (defaultFalse).
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
LineStringrepresenting 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: Ifmax_pointsis 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 theMultiLineString.max_lines(int, optional): The maximum number of lines in theMultiLineString.max_points(int, optional): The maximum number of points in each line.srs(Srs, optional): The spatial reference system of theMultiLineString.has_z(bool, optional): Whether theMultiLineStringhas z-coordinates.
Returns:
MultiLineString: The generatedMultiLineStringobject.
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 theMultiPoint. Default is 1.max_points(Optional[int]): The maximum number of points in theMultiPoint.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 generatedMultiPointgeometry 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 theMultiPolygon.max_polygons(int, optional): The max number of polygons in theMultiPolygon.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 theMultiPolygon.has_z(Optional[bool], optional): Whether theMultiPolygonhas z-coordinates.
Returns:
MultiPolygon: The generatedMultiPolygonobject.
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: Ifmax_pointsis 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_2dandforce_3dfactories in the top-level module. - fix WKT parsing for nested
GeometryCollections. - fix WKT output for
MultiPoints. - make hypothesis strategy for
GeometryCollectionsrecursive, 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_hulledge-cases discovered by Hypothesis tests - fix
from_wktto include multi geometries inGeometryCollections - drop Python 3.7 support
1.3.0 (2024/02/05)
- add Python 3.13 to supported versions
- remove
maybe_validmethods GeoTypeandGeoCollectionTypeprotocols to use a property instead of an attribute
1.2.0 (2023/11/27)
- Geometries are now immutable (but not hashable)
- add
force_2dandforce_3dfactories [Alex Svetkin]
1.1.1 (2023/10/27)
- Use
pyproject.toml, removesetup.pyandMANIFEST.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_shapetoshape - add
boxfactory - 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_emptyandbool- 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
idto feature [jzmiller1]
0.5 (2015/07/13)
- Add
__iter__method toFeatureCollectionandGeometryCollection[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*)andlen(GeometryCollection)returns the number of contained Geometries- add
orientfunction to get clockwise or counterclockwise oriented polygons - add
signed_areafunction - add
_set_orientationmethod tolineStrings,PolygonsandMultiPolygons
0.2.1 (2012/08/02)
as_shapealso 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
wktas a property as_shapealso 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
πΈ COPYRIGHT πΈ
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
- fedora 43: python3-pygeoif 1.6.0-1.fc43 Β· LGPL-2.1-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms