The ohsome-py package helps you extract and analyse OpenStreetMap history data using the ohsome API and Python. It handles queries to the ohsome API and converts its responses to Pandas and GeoPandas data frames to facilitate easy data handling and analysis.
The ohsome API provides various endpoints for data aggregation, data extraction and contributions to analyse the history of OSM data. Take a look at the documentation of the ohsome API or go through the Tutorial to get started on how to use ohsome-py.
ohsome-py requires
- Python >= 3.6
- geopandas >= 0.9.0
- pyproj >= 3.0.0
- requests >= 2.25.1
You can install ohsome-py using pip, which will also install all dependencies.
$ pip install ohsome
ohsome-py is not available through Anaconda yet. So if you are using Anaconda, create a new anaconda environment and install the required dependencies before installing ohsome-py using pip. Please note that there might be issues when using pip within anaconda. To avoid issues make sure to install everythin in a new conda environment.
$ conda create -n ohsome python=3.8 geopandas">=0.9.0" requests">=2.25.1"
$ conda activate ohsome
$ pip install ohsome --no-deps
If you want to run the Jupyter Notebook Tutorial you also need to install jupyter
and matplotlib
e.g.
$ pip install jupyter matplotlib
All queries are handled by an OhsomeClient
object, which also provides information about the current ohsome API instance, e.g. start_timestamp
and end_timestamp
indicate the earliest and the latest possible dates for a query.
from ohsome import OhsomeClient
client = OhsomeClient()
client.start_timestamp # --> '2007-10-08T00:00:00Z'
client.end_timestamp # --> '2021-01-23T03:00Z'
Example: The Number of OSM ways tagged as landuse=farmland using the /elements/count endpoint:
response = client.elements.count.post(bboxes=[8.625,49.3711,8.7334,49.4397],
time="2014-01-01",
filter="landuse=farmland and type:way")
The single components of the endpoint URL are appended as method calls to the OhsomeClient
object. Use automatic code completion to find valid endpoints. Alternatively, you can define the endpoint as argument in the .post()
method.
response = client.post(endpoint="elements/count",
bboxes=[8.625,49.3711,8.7334,49.4397],
time="2020-01-01",
filter="landuse=farmland and type:way")
Responses from the data aggregation endpoints can be converted to a pandas.DataFrame
object using the OhsomeResponse.as_dataframe()
method.
response_df = response.as_dataframe()
Example: OSM ways tagged as landuse=farmland including their geometry and tags using the /elements/geometry endpoint:
client = OhsomeClient()
response = client.elements.geometry.post(bboxes=[8.625,49.3711,8.7334,49.4397],
time="2020-01-01",
filter="landuse=farmland and type:way",
properties="tags")
response_gdf = response.as_dataframe()
Responses from the data extraction endpoint can be converted to a geopandas.GeoDataFrame
using the OhsomeResponse.as_dataframe()
method, since the data contains geometries.
All query parameters are described in the ohsome API documentation and can be passed as string
objects to the post()
method. Other Python data types are accepted as well.
The boundary of the query can be defined using the bpolys
, bboxes
and bcircles
parameters. The coordinates have to be given in WGS 84 (EPSG:4326).
The bpolys
parameter can be passed as a geopandas.GeoDataFrame
containing the polygon features.
bpolys = gpd.read_file("./data/polygons.geojson")
client.elements.count.groupByBoundary.post(bpolys=bpolys, filter="amenity=restaurant")
The bboxes
parameter contains the coordinates of one or several bounding boxes.
bboxes = [8.7137,49.4096,8.717,49.4119] # one bounding box
bboxes = [[8.7137,49.4096,8.717,49.4119], [8.7137,49.4096,8.717,49.4119]]
bboxes = {"A": [8.67066, 49.41423, 8.68177, 49.4204],
"B": [8.67066, 49.41423, 8.68177, 49.4204]}
The bcircles
parameter contains one or several circles defined through the coordinates of the centroids and the radius in meters.
bcircles = [8.7137,49.4096, 100]
bcircles = [[8.7137,49.4096, 100], [8.7137,49.4096, 300]]
bcircles = {"Circle1": [8.695, 49.41, 200],
"Circle2": [8.696, 49.41, 200]}
The time parameter must be ISO-8601 conform can be passed in several ways
time = '2018-01-01/2018-03-01/P1M'
time = ['2018-01-01', '2018-02-01', '2018-03-01']
time = datetime.datetime(year=2018, month=3, day=1)
time = pandas.date_range("2018-01-01", periods=3, freq="M")
If you want to contribute to this project, please fork the repository or create a new branch containing your changes.
Install dependencies for development
All of these dependecies can be installed using pip. If you are using anaconda, you need to install the packages through conda-forge.
- pytest = ^6.2.2
- pytest-cov = >=2.0.0
- pre-commit = >=2.1.1
- black = ^20.8b1
- pytest-random-order = ^1.0.4 (not available through anaconda)
- yaspin = <1.4.1
- tox = ^3.23.0
Install the pre-commit hooks in our local git repo before committing to ensure homogenous code style.
$ pre-commit install
Run the tests inside the repo using pytest
(and poetry
if you like) to make sure everything works.
$ poetry run pytest
Running the tests against a dockerised local instance of the ohsome API is faster, but not mandatory. By default the test will issue a warning that it could not find the local instance and then fall back to the public one. To set up and start a local instance run the following command before running the tests (see https://github.com/GIScience/ohsome-api-dockerized).
$ docker run -dt --name ohsome-api -p 8080:8080 julianpsotta/ohsome-api:latest
Create a pull request to the development branch once it is ready to be merged.
The design of this package was inspired by the blog post Using Python to Implement a Fluent Interface to Any REST API by Elmer Thomas.