GeoJSON AOI Parser¶
Parse and normalize a GeoJSON area of interest, using using PostGIS.
📖 Documentation: https://hotosm.github.io/geojson-aoi-parser/
🖥️ Source Code: https://github.com/hotosm/geojson-aoi-parser
Why do we need this?¶
- We generally need an Area of Interest (AOI) specified for software to run on a geospatial area.
- GeoJSON is a simple exchange format to communicate this AOI.
- We only care about Polygon data types, but GeoJSON data can be quite variable, with many options for presenting data.
- The goal of this package is to receive GeoJSON data in various forms, then produce a normalised output that can be used for further processing.
Priorities¶
- Flexible data input: file bytes, dict, string JSON.
- Flexible geometry input:
- Polygon
- MultiPolygons
- GeometryCollection
- Feature
- FeatureCollection
- Splits multipolygons into featcol of individual polygons.
- Handle geometries nested inside GeometryCollection.
- Remove any z-dimension coordinates.
- Warn user if CRS is provided, in a coordinate system other than EPSG:4326.
- Normalised output: FeatureCollection containing Polygon geoms.
Capturing The Warnings¶
If the GeoJSON has an invalid CRS, or coordinates seem off, a warning will be raised.
To install:
pip install geojson-aoi-parser
Basic example:
from geojson_aoi import parse_aoi
polygon_geojson = {
"type": "Polygon",
"coordinates": [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]],
}
# Where 'db' is some upstream database connection.
feat_col = parse_aoi(db, polygon_geojson)
print(feat_col)
# {
# 'type': 'FeatureCollection',
# 'features': [
# {
# 'type': 'Feature',
# 'geometry':
# {
# 'type': 'Polygon',
# 'coordinates': [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]]
# }
# }
# ]
# }
Basic async example:
from geojson_aoi import parse_aoi_async
polygon_geojson = {
"type": "Polygon",
"coordinates": [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]],
}
# Where 'db' is some upstream database connection.
feat_col = parse_aoi_async(db, polygon_geojson)
print(feat_col)
# {
# 'type': 'FeatureCollection',
# 'features': [
# {
# 'type': 'Feature',
# 'geometry':
# {
# 'type': 'Polygon',
# 'coordinates': [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]]
# }
# }
# ]
# }
To halt execution when a warning is raised and act on it:
try:
featcol = parse_aoi(db, raw_geojson)
except UserWarning as warning:
log.error(warning.message)
msg = "Using a valid CRS is mandatory!"
log.error(msg)
raise HTTPException(HTTPStatus.BAD_REQUEST, detail=msg)
To record warnings, but allow execution to continue:
import warnings
with warnings.catch_warnings(record=True) as recorded_warnings:
featcol = parse_aoi(db, raw_geojson)
if recorded_warnings:
for warning in recorded_warnings:
if isinstance(warning.message, UserWarning)
# do stuff with warning
logger.warning(f"A warning was encountered: {warning.message}")
Create a New DB Connection
- If your app upstream already has a psycopg connection, this can be passed through.
- If you require a new database connection, the connection parameters can be defined as DbConfig object variables:
from geojson_aoi import parse_aoi, DbConfig
db = DbConfig(
dbname="db1",
user="user1",
password="pass1",
host="localhost",
port="5432",
)
featcol = parse_aoi(db, raw_geojson)
- Or alternatively as variables from your system environment:
GEOJSON_AOI_DB_NAME=aoi
GEOJSON_AOI_DB_USER=aoi
GEOJSON_AOI_DB_PASSWORD=pass
GEOJSON_AOI_DB_HOST=localhost
GEOJSON_AOI_DB_PORT=5432
then
from geojson_aoi import parse_aoi
featcol = parse_aoi(db, raw_geojson)
((All credit for DbConfig goes to https://github.com/hotosm/pg-nearest-city/))
History¶
- Initially I tried to write a pure-Python implementation of this, no dependencies.
- I underestimated the amount of work that is! It could be possible to reverse engineer C++ Geos or georust/geos, but it's more hassle than it's worth.
- As all of the target install candidates for this package use a db driver anyway, I thought it wisest (and most time efficient) to use the PostGIS Geos implementation (specifically for the unary_union and convex_hull algorithms).
- An additional advantage is the potential to port this to PGLite when the PostGIS extension is available, meaning AOI processing easily in the browser.