Name | esy-osm-shape JSON |
Version |
0.4
JSON |
| download |
home_page | None |
Summary | Convert OpenStreetMap primitives to shapely objects |
upload_time | 2025-08-14 09:36:31 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.5 |
license | BSD-3-Clause |
keywords |
osm
openstreetmap
shapely
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
`esy.osm.shape` is a Python library to convert
[OpenStreetMap](https://www.openstreetmap.org) primitives to
[shapely](https://shapely.readthedocs.io/en/latest/) objects.

The [drawing maps](#drawing-maps) example shows, how this figure is constructed.
# Features
What it provides:
- Functionality to generate shapely objects from OpenStreetMap `.pbf` data
file entries.
- Basic plotting tools for matplotlib.
In addition to the [shapely](https://shapely.readthedocs.io/) geometry, the
OpenStreetMap `id` and `tags` properties are generated as provided by
`esy.osm.pbf`.
What it *doesn't* provide:
- A mechanism to spatially query OpenStreetMap entries.
- Handling of non-geometry objects (like many relations).
# Installation
`esy.osm.shape` depends on a Python version of 3.8 or above as well as on
`esy.osm.pbf`. Use `pip` to install `esy.osm.shape`:
```sh
$ pip install esy-osm-shape
```
# Usage
An `esy.osm.shape.Shape` object requires a filename of an OpenStreetMap
protocol buffers file or an instance of `esy.osm.pbf.File` as argument on
construction. Upon being called, the `esy.osm.shape.Shape` returns generator
which yields a tuple consisting of the
[shapely](https://shapely.readthedocs.io/) geometry and both the OpenStreetMap
`id` and `tags`. There are two optional arguments:
- `filter`: can be used to select OpenStreetMap primitives for which to generate
[shapely](https://shapely.readthedocs.io/) objects. By default, every
OpenStreetMap primitive is selected.
- `max_tasks`: can be used to trade-off memory versus speed. If this value
increases, more memory is used to cache OpenStreetMap entries, thereby
reducing the number of file read operations.
# Examples
The following examples operate on a historic dataset for Andorra from
[geofabrik](https://www.geofabrik.de/). Let's download the dataset first:
```python
>>> import os, urllib.request
>>> if not os.path.exists('andorra.osm.pbf'):
... filename, headers = urllib.request.urlretrieve(
... 'https://download.geofabrik.de/europe/andorra-190101.osm.pbf',
... filename='andorra.osm.pbf'
... )
```
## Construct geometries
Open the file and generate linestrings for each `highway` OpenStreetMap entry.
```python
>>> import shapely, esy.osm.shape
>>> shape = esy.osm.shape.Shape('andorra.osm.pbf')
>>> highways = [
... shape for shape, id, tags in shape(lambda e: e.tags.get('highway'))
... if type(shape) is shapely.geometry.LineString
... ]
>>> len(highways)
3948
```
Shapely objects also expose geometric properties, like for example the length or
area. However, OpenStreetMap uses geodetic coordinates and shapely assumes
planar coordinates, rendering most geometry properties invalid.
## Geodetic computations
[pyproj](https://pyproj4.github.io/pyproj/) offers geodetic computations and
can be used to estimate area and length properties of sphere geometries
accurately:
```python
>>> import pyproj
>>> geod = pyproj.Geod(ellps='WGS84')
>>> round(geod.geometry_length(shapely.MultiLineString(highways)))
1577598
```
## Drawing maps
`esy.osm.shape` provides functionality to convert shapely objects into
[matplotlib](https://matplotlib.org/) objects, which enables simple map
rendering:
```python
>>> import matplotlib.pyplot as plt, esy.osm.shape.mpl
>>> fig, ax = plt.subplots(1, 1)
>>> _ = ax.set(
... title='andorra-190101.osm.pbf', aspect='equal',
... xlabel='lon', xlim=(1.40, 1.75), ylabel='lat', ylim=(42.40, 42.70)
... )
>>> iax = ax.inset_axes(
... [0.61, 0.02, 0.4, 0.4], xlim=(1.525, 1.535), ylim=(42.504, 42.514),
... aspect='equal', xticks=[], yticks=[]
... )
>>> style = esy.osm.shape.mpl.simple_style
>>> items = tuple(shape(esy.osm.shape.mpl.filter(style)))
>>> _ = ax.add_artist(esy.osm.shape.mpl.render_map(style, items))
>>> _ = iax.add_artist(esy.osm.shape.mpl.render_map(style, items))
>>> _ = ax.indicate_inset_zoom(iax, edgecolor='black')
>>> os.makedirs('figures/', exist_ok=True)
>>> fig.savefig('figures/andorra.png')
```
## Invalid entries
Some OpenStreetMap entries might be broken shapes or logical groupings not
representable as shapes. These entries are mostly relations and generate
`Invalid` objects. `Invalid` objects provide four properties which give a
description of the exception that happened during processing:
- `entry`: The invalid OpenStreetMap entry.
- `exc_type`: The type of the exception.
- `exc_args`: The arguments of the exception.
- `exc_description`: The traceback text of the exception.
The following example reads every OpenStreetMap entry from the Andorra dataset
and collects all invalid ones into a dictionary:
```python
>>> count, invalid = 0, {}
>>> for shape, id, tags in shape():
... count += 1
... if type(shape) is esy.osm.shape.Invalid:
... invalid[id] = shape
>>> count, len(invalid)
(217238, 186)
```
About 0.1% of the Andorra dataset entries cannot be handled by
`esy.osm.shape`. Some of these entries are broken:
```python
>>> print(invalid[8473237]) #doctest: +ELLIPSIS
Invalid Relation (id=8473237)
Traceback (most recent call last):
...
File "...shape.py", line ..., in multipolygon_shape
raise ValueError('Invalid segments')
ValueError: Invalid segments
```
Unrepresentable OpenStreetMap entries are usually logical relations, like
[routing information](https://wiki.openstreetmap.org/wiki/Relation:route).
These are reported as `Invalid` objects with an `exc_type` of
`NotImplementedError`. For example:
```python
>>> print(invalid[6745201]) #doctest: +ELLIPSIS
Invalid Relation (id=6745201)
Traceback (most recent call last):
File "...shape.py", line ..., in unsupported
raise NotImplementedError(description)
NotImplementedError: Relation (id=6745201)
```
# License
`esy.osm.shape` is published under the
[BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html) license.
# Design, Development & Contributing
Design and development notes are available in `esy.osm.shape.test`.
We would be happy to accept contributions via merge requests, but due to
corporate policy we can only accept contributions if you have send us the signed
[contributor license agreement](CLA.md).
# Contact
Please use the projects issue tracker to get in touch.
# Team
`esy.osm.shape` is developed by the
[DLR](https://www.dlr.de/EN/Home/home_node.html) Institute of
[Networked Energy Systems](https://www.dlr.de/ve/en/desktopdefault.aspx/tabid-12472/21440_read-49440/)
in the departement for
[Energy Systems Analysis (ESY)](https://www.dlr.de/ve/en/desktopdefault.aspx/tabid-12471/21741_read-49802/).
# Acknowledgements
The authors would like to thank the Federal Government and the Heads of
Government of the Länder, as well as the Joint Science Conference (GWK), for
their funding and support within the framework of the NFDI4Ing consortium.
Funded by the German Research Foundation (DFG) - project number 442146713.
Raw data
{
"_id": null,
"home_page": null,
"name": "esy-osm-shape",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.5",
"maintainer_email": null,
"keywords": "OSM, OpenStreetMap, shapely",
"author": null,
"author_email": "Ontje L\u00fcnsdorf <ontje.luensdorf@dlr.de>",
"download_url": "https://files.pythonhosted.org/packages/d3/66/72f4fde77bd1c7402e42a3ea2a3546dac310699cfc1a8afd108a2241245a/esy_osm_shape-0.4.tar.gz",
"platform": null,
"description": "`esy.osm.shape` is a Python library to convert\n[OpenStreetMap](https://www.openstreetmap.org) primitives to\n[shapely](https://shapely.readthedocs.io/en/latest/) objects.\n\n\n\nThe [drawing maps](#drawing-maps) example shows, how this figure is constructed.\n\n# Features\n\nWhat it provides:\n\n- Functionality to generate shapely objects from OpenStreetMap `.pbf` data\n file entries.\n- Basic plotting tools for matplotlib.\n\nIn addition to the [shapely](https://shapely.readthedocs.io/) geometry, the\nOpenStreetMap `id` and `tags` properties are generated as provided by\n`esy.osm.pbf`.\n\nWhat it *doesn't* provide:\n\n- A mechanism to spatially query OpenStreetMap entries.\n- Handling of non-geometry objects (like many relations).\n\n# Installation\n\n`esy.osm.shape` depends on a Python version of 3.8 or above as well as on\n`esy.osm.pbf`. Use `pip` to install `esy.osm.shape`:\n\n```sh\n$ pip install esy-osm-shape\n```\n\n# Usage\n\nAn `esy.osm.shape.Shape` object requires a filename of an OpenStreetMap\nprotocol buffers file or an instance of `esy.osm.pbf.File` as argument on\nconstruction. Upon being called, the `esy.osm.shape.Shape` returns generator\nwhich yields a tuple consisting of the\n[shapely](https://shapely.readthedocs.io/) geometry and both the OpenStreetMap\n`id` and `tags`. There are two optional arguments:\n\n- `filter`: can be used to select OpenStreetMap primitives for which to generate\n [shapely](https://shapely.readthedocs.io/) objects. By default, every\n OpenStreetMap primitive is selected.\n- `max_tasks`: can be used to trade-off memory versus speed. If this value\n increases, more memory is used to cache OpenStreetMap entries, thereby\n reducing the number of file read operations.\n\n# Examples\n\nThe following examples operate on a historic dataset for Andorra from\n[geofabrik](https://www.geofabrik.de/). Let's download the dataset first:\n\n```python\n>>> import os, urllib.request\n>>> if not os.path.exists('andorra.osm.pbf'):\n... filename, headers = urllib.request.urlretrieve(\n... 'https://download.geofabrik.de/europe/andorra-190101.osm.pbf',\n... filename='andorra.osm.pbf'\n... )\n\n```\n\n## Construct geometries\n\nOpen the file and generate linestrings for each `highway` OpenStreetMap entry.\n\n```python\n>>> import shapely, esy.osm.shape\n>>> shape = esy.osm.shape.Shape('andorra.osm.pbf')\n>>> highways = [\n... shape for shape, id, tags in shape(lambda e: e.tags.get('highway'))\n... if type(shape) is shapely.geometry.LineString\n... ]\n>>> len(highways)\n3948\n\n```\n\nShapely objects also expose geometric properties, like for example the length or\narea. However, OpenStreetMap uses geodetic coordinates and shapely assumes\nplanar coordinates, rendering most geometry properties invalid.\n\n## Geodetic computations\n\n[pyproj](https://pyproj4.github.io/pyproj/) offers geodetic computations and\ncan be used to estimate area and length properties of sphere geometries\naccurately:\n\n```python\n>>> import pyproj\n>>> geod = pyproj.Geod(ellps='WGS84')\n>>> round(geod.geometry_length(shapely.MultiLineString(highways)))\n1577598\n\n```\n\n## Drawing maps\n\n`esy.osm.shape` provides functionality to convert shapely objects into\n[matplotlib](https://matplotlib.org/) objects, which enables simple map\nrendering:\n\n```python\n>>> import matplotlib.pyplot as plt, esy.osm.shape.mpl\n>>> fig, ax = plt.subplots(1, 1)\n>>> _ = ax.set(\n... title='andorra-190101.osm.pbf', aspect='equal',\n... xlabel='lon', xlim=(1.40, 1.75), ylabel='lat', ylim=(42.40, 42.70)\n... )\n>>> iax = ax.inset_axes(\n... [0.61, 0.02, 0.4, 0.4], xlim=(1.525, 1.535), ylim=(42.504, 42.514),\n... aspect='equal', xticks=[], yticks=[]\n... )\n>>> style = esy.osm.shape.mpl.simple_style\n>>> items = tuple(shape(esy.osm.shape.mpl.filter(style)))\n>>> _ = ax.add_artist(esy.osm.shape.mpl.render_map(style, items))\n>>> _ = iax.add_artist(esy.osm.shape.mpl.render_map(style, items))\n>>> _ = ax.indicate_inset_zoom(iax, edgecolor='black')\n>>> os.makedirs('figures/', exist_ok=True)\n>>> fig.savefig('figures/andorra.png')\n\n```\n\n## Invalid entries\n\nSome OpenStreetMap entries might be broken shapes or logical groupings not\nrepresentable as shapes. These entries are mostly relations and generate\n`Invalid` objects. `Invalid` objects provide four properties which give a\ndescription of the exception that happened during processing:\n\n- `entry`: The invalid OpenStreetMap entry.\n- `exc_type`: The type of the exception.\n- `exc_args`: The arguments of the exception.\n- `exc_description`: The traceback text of the exception.\n\nThe following example reads every OpenStreetMap entry from the Andorra dataset\nand collects all invalid ones into a dictionary:\n\n```python\n>>> count, invalid = 0, {}\n>>> for shape, id, tags in shape():\n... count += 1\n... if type(shape) is esy.osm.shape.Invalid:\n... invalid[id] = shape\n>>> count, len(invalid)\n(217238, 186)\n\n```\n\nAbout 0.1% of the Andorra dataset entries cannot be handled by\n`esy.osm.shape`. Some of these entries are broken:\n\n```python\n>>> print(invalid[8473237]) #doctest: +ELLIPSIS\nInvalid Relation (id=8473237)\n Traceback (most recent call last):\n ...\n File \"...shape.py\", line ..., in multipolygon_shape\n raise ValueError('Invalid segments')\n ValueError: Invalid segments\n\n```\n\nUnrepresentable OpenStreetMap entries are usually logical relations, like\n[routing information](https://wiki.openstreetmap.org/wiki/Relation:route).\nThese are reported as `Invalid` objects with an `exc_type` of\n`NotImplementedError`. For example:\n\n```python\n>>> print(invalid[6745201]) #doctest: +ELLIPSIS\nInvalid Relation (id=6745201)\n Traceback (most recent call last):\n File \"...shape.py\", line ..., in unsupported\n raise NotImplementedError(description)\n NotImplementedError: Relation (id=6745201)\n\n```\n\n# License\n\n`esy.osm.shape` is published under the\n[BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html) license.\n\n# Design, Development & Contributing\n\nDesign and development notes are available in `esy.osm.shape.test`.\n\nWe would be happy to accept contributions via merge requests, but due to\ncorporate policy we can only accept contributions if you have send us the signed\n[contributor license agreement](CLA.md).\n\n# Contact\n\nPlease use the projects issue tracker to get in touch.\n\n# Team\n\n`esy.osm.shape` is developed by the\n[DLR](https://www.dlr.de/EN/Home/home_node.html) Institute of\n[Networked Energy Systems](https://www.dlr.de/ve/en/desktopdefault.aspx/tabid-12472/21440_read-49440/)\nin the departement for\n[Energy Systems Analysis (ESY)](https://www.dlr.de/ve/en/desktopdefault.aspx/tabid-12471/21741_read-49802/).\n\n# Acknowledgements\n\nThe authors would like to thank the Federal Government and the Heads of\nGovernment of the L\u00e4nder, as well as the Joint Science Conference (GWK), for\ntheir funding and support within the framework of the NFDI4Ing consortium.\nFunded by the German Research Foundation (DFG) - project number 442146713.\n",
"bugtrack_url": null,
"license": "BSD-3-Clause",
"summary": "Convert OpenStreetMap primitives to shapely objects",
"version": "0.4",
"project_urls": {
"documentation": "https://dlr-ve-esy.gitlab.io/esy-osm-shape",
"homepage": "https://gitlab.com/dlr-ve-esy/esy-osm-shape"
},
"split_keywords": [
"osm",
" openstreetmap",
" shapely"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "18080afea1c1cc0926e78023985b4457b66afacf9bbe6ab6b2fd5da14de46e17",
"md5": "c0894d7e031f79ecffaad1d26475a77c",
"sha256": "4f076848f46b2eb5dcb63fda28ecd7e9fc199becbad7ff431f596fede6ec7a70"
},
"downloads": -1,
"filename": "esy_osm_shape-0.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c0894d7e031f79ecffaad1d26475a77c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.5",
"size": 16625,
"upload_time": "2025-08-14T09:36:29",
"upload_time_iso_8601": "2025-08-14T09:36:29.960670Z",
"url": "https://files.pythonhosted.org/packages/18/08/0afea1c1cc0926e78023985b4457b66afacf9bbe6ab6b2fd5da14de46e17/esy_osm_shape-0.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "d36672f4fde77bd1c7402e42a3ea2a3546dac310699cfc1a8afd108a2241245a",
"md5": "77a7e300d9cb837c52928b2ce72975e9",
"sha256": "c10e58a0c60c1e89b42cc6ab86fad1c50531f643991d801ac0c43a4db34c10dc"
},
"downloads": -1,
"filename": "esy_osm_shape-0.4.tar.gz",
"has_sig": false,
"md5_digest": "77a7e300d9cb837c52928b2ce72975e9",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.5",
"size": 15532,
"upload_time": "2025-08-14T09:36:31",
"upload_time_iso_8601": "2025-08-14T09:36:31.245065Z",
"url": "https://files.pythonhosted.org/packages/d3/66/72f4fde77bd1c7402e42a3ea2a3546dac310699cfc1a8afd108a2241245a/esy_osm_shape-0.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-14 09:36:31",
"github": false,
"gitlab": true,
"bitbucket": false,
"codeberg": false,
"gitlab_user": "dlr-ve-esy",
"gitlab_project": "esy-osm-shape",
"lcname": "esy-osm-shape"
}