A library to access OpenStreetMap related services

Overview

OSMPythonTools

The python package OSMPythonTools provides easy access to OpenStreetMap (OSM) related services, among them an Overpass endpoint, Nominatim, and the OSM API.

Installation

To install OSMPythonTools, you will need python3 and pip (How to install pip). Then execute:

pip install OSMPythonTools

On some operating systems, pip for python3 is named pip3:

pip3 install OSMPythonTools

Example 1

Which object does the way with the ID 5887599 represent?

We can use the OSM API to answer this question:

from OSMPythonTools.api import Api
api = Api()
way = api.query('way/5887599')

The resulting object contains information about the way, which can easily be accessed:

way.tag('building')
# 'castle'
way.tag('architect')
# 'Johann Lucas von Hildebrandt'
way.tag('website')
# 'http://www.belvedere.at'

Example 2

What is the English name of the church called ‘Stephansdom’, what address does it have, and which of which denomination is the church?

We use the Overpass API to query the corresponding data:

from OSMPythonTools.overpass import Overpass
overpass = Overpass()
result = overpass.query('way["name"="Stephansdom"]; out body;')

This time, the result is a number of objects, which can be accessed by result.elements(). We just pick the first one:

stephansdom = result.elements()[0]

Information about the church can now easily be accessed:

stephansdom.tag('name:en')
# "Saint Stephen's Cathedral"
'%s %s, %s %s' % (stephansdom.tag('addr:street'), stephansdom.tag('addr:housenumber'), stephansdom.tag('addr:postcode'), stephansdom.tag('addr:city'))
# 'Stephansplatz 3, 1010 Wien'
stephansdom.tag('building')
# 'cathedral'
stephansdom.tag('denomination')
# 'catholic'

Example 3

How many trees are in the OSM data of Vienna? And how many trees have there been in 2013?

This time, we have to first resolve the name ‘Vienna’ to an area ID:

from OSMPythonTools.nominatim import Nominatim
nominatim = Nominatim()
areaId = nominatim.query('Vienna, Austria').areaId()

This area ID can now be used to build the corresponding query:

from OSMPythonTools.overpass import overpassQueryBuilder, Overpass
overpass = Overpass()
query = overpassQueryBuilder(area=areaId, elementType='node', selector='"natural"="tree"', out='count')
result = overpass.query(query)
result.countElements()
# 137830

There are 134520 trees in the current OSM data of Vienna. How many have there been in 2013?

result = overpass.query(query, date='2013-01-01T00:00:00Z', timeout=60)
result.countElements()
# 127689

Example 4

Where are waterbodies located in Vienna?

Again, we have to resolve the name ‘Vienna’ before running the query:

from OSMPythonTools.nominatim import Nominatim
nominatim = Nominatim()
areaId = nominatim.query('Vienna, Austria').areaId()

The query can be built like in the examples before. This time, however, the argument includeGeometry=True is provided to the overpassQueryBuilder in order to let him generate a query that downloads the geometry data.

from OSMPythonTools.overpass import overpassQueryBuilder, Overpass
overpass = Overpass()
query = overpassQueryBuilder(area=areaId, elementType=['way', 'relation'], selector='"natural"="water"', includeGeometry=True)
result = overpass.query(query)

Next, we can exemplarily choose one random waterbody (the first one of the download ones) and compute its geometry like follows:

firstElement = result.elements()[0]
firstElement.geometry()
# {"coordinates": [[[16.498671, 48.27628], [16.4991, 48.276345], ... ]], "type": "Polygon"}

Observe that the resulting geometry is provided in the GeoJSON format.

Example 5

How did the number of trees in Berlin, Paris, and Vienna change over time?

Before we can answer the question, we have to import some modules:

from collections import OrderedDict
from OSMPythonTools.data import Data, dictRangeYears, ALL
from OSMPythonTools.overpass import overpassQueryBuilder, Overpass

The question has two ‘dimensions’: the dimension of time, and the dimension of different cities:

dimensions = OrderedDict([
    ('year', dictRangeYears(2013, 2017.5, 1)),
    ('city', OrderedDict({
        'berlin': 'Berlin, Germany',
        'paris': 'Paris, France',
        'vienna': 'Vienna, Austria',
    })),
])

We have to define how we fetch the data. We again use Nominatim and the Overpass API to query the data (it can take some time to perform this query the first time!):

overpass = Overpass()
def fetch(year, city):
    areaId = nominatim.query(city).areaId()
    query = overpassQueryBuilder(area=areaId, elementType='node', selector='"natural"="tree"', out='count')
    return overpass.query(query, date=year, timeout=60).countElements()
data = Data(fetch, dimensions)

We can now easily generate a plot from the result:

data.plot(city=ALL, filename='example4.png')

data.plot(city=ALL, filename='example4.png')

Alternatively, we can generate a table from the result

data.select(city=ALL).getCSV()
# year,berlin,paris,vienna
# 2013.0,10180,1936,127689
# 2014.0,17971,26905,128905
# 2015.0,28277,90599,130278
# 2016.0,86769,103172,132293
# 2017.0,108432,103246,134616

More examples can be found inside the documentation of the modules.

Usage

The following modules are available (please click on their names to access further documentation):

Please refer to the general remarks page if you have further questions related to OSMPythonTools in general or functionality that the several modules have in common.

Observe the breaking changes as included in the version history.

Logging

This library is a little bit more verbose than other Python libraries. The good reason behind is that the OpenStreetMap, the Nominatim, and the Overpass servers experience a heavy load already and their resources should be used carefully. In order to make you, the user of this library, aware of when OSMPythonTools accesses these servers, corresponding information is logged by default. In case you want to suppress these messages, you have to insert the following lines after the import of OSMPythonTools:

import logging
logging.getLogger('OSMPythonTools').setLevel(logging.ERROR)

Please note that suppressing the messages means that you have to ensure on your own that you do not overuse the provided services and that you stick to their fair policy guidelines.

Tests

You can test the package by running

pytest --verbose

Please note that the tests might run very long (several minutes) because the overpass server will most likely defer the downloads.

Author

This application is written and maintained by Franz-Benjamin Mocnik, [email protected].

(c) by Franz-Benjamin Mocnik, 2017-2021.

The code is licensed under the GPL-3.

Comments
  • overpass.py - _waitForReady - Hardcoded Status String Positions

    overpass.py - _waitForReady - Hardcoded Status String Positions

    Hi there,

    first of all, great library, it's been really useful to me!

    Now my issue, after experiementing with the public endpoints I've setup a personal overpass endpoint to escape the wait times and not over utilize public goods. I've followed along the instructions on: https://wiki.openstreetmap.org/wiki/Overpass_API/Installation Installing Release 0.7.58

    Pointing the library to my endpoint via: Overpass(endpoint='<MyEndpoint>')

    I ended up with the following error (happy to share a more detailed trace if needed): Exception: [overpass] could not fetch or interpret status of the endpoint

    After some analysis it seems I'm failing in the libraries _waitForReady function because my status response has more rows and therefore the statusString[] indexes are off.

    Status Response Connected as: 3232235754 Current time: 2022-06-01T15:19:28Z Announced endpoint: none Rate limit: 0 Currently running queries (pid, space limit, time limit, start time):

    Can the function be changed to work line independent and detect required infos smarter? I'm just starting out so I don't want to mess with the libraries code.

    Cheers!

    opened by e-bock 16
  • Nominatim in Jupyter Notebook

    Nominatim in Jupyter Notebook

    Hi there,

    I am new to OSM and wanted to play around with it in a Jupiter Notebook.

    I checked out the readme and wanted to implement the example. But somehow it does not do what it is supposed to. Please check out the error messages in the attachment.

    Any suggestion is greatly appreciated.

    Thanks Pascal

    image
    opened by reuschp 13
  • Errors in cached results

    Errors in cached results

    If a query results in an error (e.g., a timeout) even re-running the query with changed parameters (e.g., a different timeout value) immediately bails out. I have not checked if timeouts are the only problem but in general the cache should be invalidated in those cases.

    (I am building the query strings manually; using 0.3.0 via pip)

    opened by stefanct 9
  • Update overpassQueryBuilder's area parameter to handle way or relation ids

    Update overpassQueryBuilder's area parameter to handle way or relation ids

    This would make querying within features with known ids/without names simpler by including logic to calculate the feature's corresponding area id.

    Example usage:

    • How many footways are in a given park polygon? from OSMPythonTools.overpass import overpassQueryBuilder, Overpass overpass = Overpass() query = overpassQueryBuilder(area='w290617734', elementType='way', selector='highway=footway', out='body') result = overpass.query(query) result.countElements() #16
    opened by tyhranac 9
  • Test dependencies in `setup.py`

    Test dependencies in `setup.py`

    Hi, first of all thank you very much for all your work on this package.

    While insalling this package, I realised that it introduces a dependency on pytest and pytest-sugar (see this line and this line).

    Are those dependencies needed for end users, or should they be distributed somewhere else for developer of this library only? I'm asking this question because installing the package produces a side-effect for me which is modifying my pytest interface.

    Thank you for your time.

    opened by simonTurintech 6
  • Throwing generic exceptions makes handling them differently impossible

    Throwing generic exceptions makes handling them differently impossible

    The library often handles exception itself, e.g., cacheObject's __query(), by excepting, logging, and then raising a newly created generic Exception object. For example very specific exceptions raised by urllib get converted into this generic type. It thus becomes impossible to differentiate between different errors on the user side, e.g., it one cannot even react differently if the user hits ctrl+c while a transfer is in progress. As is it is completely impossible to do meaningful error handling without inspection or other tricks AFAICT.

    It would be much better to leave the respective error handling to the library user instead. You can still add useful information to the exception (and log stuff if you like), cf. https://wiki.python.org/moin/HandlingExceptions

    opened by stefanct 5
  • Cannot build geometry for a relation.

    Cannot build geometry for a relation.

    With the following:

    from OSMPythonTools.overpass import Overpass

    op = Overpass() q = 'relation(110796); out body;' r = op.query(q) e = r.elements()[0] e.geometry()

    I get the following:

    Exception: [OSMPythonTools.Element] Cannot build geometry: cannot find outer ring for inner ring. (relation/110796)

    opened by johnaschmidt 5
  • Recursive query

    Recursive query

    Is there a way to download all nodes of requested ways during the overpass query?

    I have this query: query = f'''area({area_id})->.searchArea; ( rel(area.searchArea); way(area.searchArea); node(area.searchArea); )->.result; .result out meta; .result >->.recurseresult; .recurseresult out meta;'''

    result = overpass.query(query) In my understanding, even if all nodes of a way w are in results, the first time I call w.nodes() it will download all of the nodes.

    I would like:

    1. query() to download all data so that no other http request are made.
    2. nodeRefs() or similar to receive node ids only (currently this info is buried into _json)

    Is there such functionality or is planned?

    Thanks, Angelo

    opened by moscati 5
  • pass arbitrary params to Nominatim API

    pass arbitrary params to Nominatim API

    This may not be a feature desired by the authors, but I thought it might be helpful to pass other parameters when querying the nominatim API (Nominatim search API docs).

    opened by ad2476 5
  • Missing recently edited ways in results

    Missing recently edited ways in results

    Doing:

    query = overpassQueryBuilder(area=3600007407, elementType='way',    selector='"railway"="rail"', out='body')
    a=overpass.query(query)
    
    len(a.ways())
    Out[30]: 751
    
    len(a.elements())
    Out[28]: 751
    
    

    but doing on http://overpass-api.de/query_form.html way(area:3600007407)[railway=rail]; out count;

    <count id="0">
        <tag k="nodes" v="0"/>
        <tag k="ways" v="764"/>
        <tag k="relations" v="0"/>
        <tag k="areas" v="0"/>
        <tag k="total" v="764"/>
      </count>
    

    overpy also gives 764 elements.

    It seems that missing ways were recently modified like 852538015: https://www.openstreetmap.org/way/852538015 edited 3 month ago

    Do you have any idea ?

    opened by masfaraud 4
  • [overpass] error in result (cache/overpass...)

    [overpass] error in result (cache/overpass...)

    Hello!

    I am trying to query for objects (nodes and ways) that are around some location represented as a (lat, lon) pair. My query is

    query_obj = '(node(around:10000,{0},{1});way(around:10000,{0},{1});); out body;'.format(lat, lon)
    overpass.query(query_obj, timeout=5)
    

    And while it works fine with some (lat, lon) pairs, e.g. (52.6851, -0.470191), it throws an exception with others, e.g. (54.59298,-1.48307).

    This is what I am getting image

    What could be the reason? And do you have any idea how to avoid that?

    Thanks in advance!

    opened by sonniki 4
  • Significantly reduced performance since version 0.3.3

    Significantly reduced performance since version 0.3.3

    I recently updated from version 0.2.8 to 0.3.5 and noticed a significant increase in querying time for overpass queries with the new version. Testing around with different longer queries showed an increase in time by a factor of 100-150x. Dug a bit in the source code and it seems to be an issue with the ApiResult class (in api.py) - and how it was rewritten since version 0.3.3. More specifically, how BeautifulSoup and the souphistory is handled now is decreasing OSMPythonTools performance significantly.

    For reference:

    new, slow version (>=0.3.3)

    class ApiResult(Element):
        def __init__(self, xml, queryString, params, cacheMetadata=None, shallow=False, history=False):
            self._isValid = (xml != {} and xml is not None)
            self._xml = xml
            self._soup2 = None
            soup = None
            soupHistory = None
            if self._isValid:
                self._soup2 = BeautifulSoup(xml, 'xml').find('osm')
                soupHistory = self._soup2.find_all(['node', 'way', 'relation'])
                if len(soupHistory) > 0:
                    soup = soupHistory[-1]
            super().__init__(cacheMetadata, soup=soup, soupHistory=soupHistory if history else None, shallow=shallow)
            self._queryString = queryString
            self._params = params
    

    older, more efficient version (<0.3.3)

    class ApiResult(Element):
        def __init__(self, xml, queryString, shallow=False):
            self._isValid = (xml != {} and xml is not None)
            self._xml = xml
            self._soup = None
            soupElement = None
            if self._isValid:
                self._soup = BeautifulSoup(xml, 'xml')
                if len(self._soup.find_all('node')) > 0:
                    soupElement = self._soup.node
                if len(self._soup.find_all('way')) > 0:
                    soupElement = self._soup.way
                if len(self._soup.find_all('relation')) > 0:
                    soupElement = self._soup.relation
            super().__init__(soup=soupElement, shallow=shallow)
            self._queryString = queryString
    
    opened by sb-stefan 0
  • Could we get (perhaps computed) center coordinates for all elements?

    Could we get (perhaps computed) center coordinates for all elements?

    For example:

    from OSMPythonTools.api import Api
    api = Api()
    way = api.query('relation/3629242')
    way.centerLat()
    way.centerLon()
    

    I understand that it is probably not trivial and some computation would have to be done in the background, but either remove those methods when they cannot be filled with some meaningful data or compute the result?

    opened by mcepl 1
  • It does not work on m1 macbook

    It does not work on m1 macbook

    When i import the Api by this command:

    from OSMPythonTools.api import Api
    

    I have this exception:

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/Users/evblinov/Desktop/Projects/candidates_gateway/venv/lib/python3.10/site-packages/OSMPythonTools/api.py", line 4, in <module>
        from OSMPythonTools.internal.cacheObject import CacheObject
      File "/Users/evblinov/Desktop/Projects/candidates_gateway/venv/lib/python3.10/site-packages/OSMPythonTools/internal/cacheObject.py", line 5, in <module>
        import ujson
    ImportError: dlopen(/Users/evblinov/Desktop/Projects/candidates_gateway/venv/lib/python3.10/site-packages/ujson.cpython-310-darwin.so, 0x0002): tried: '/Users/evblinov/Desktop/Projects/candidates_gateway/venv/lib/python3.10/site-packages/ujson.cpython-310-darwin.so' (mach-o file, but is an incompatible architecture (have (x86_64), need (arm64e)))
    
    opened by pomponchik 0
  • Overpass shallow query results in an error

    Overpass shallow query results in an error

    Having shallow parameter on True for overpass results in passing just a boolean as dict to _rawToResult function and ends up with

    File .../.venv/lib/python3.8/site-packages/OSMPythonTools/overpass.py:144, in OverpassResult.__get(self, prop)
        143 def __get(self, prop):
    --> 144     return self._json[prop] if prop in self._json else None
    

    https://github.com/mocnik-science/osm-python-tools/blob/695ac4f6b9ee1c6ea4071b6dce28160687fd18c8/OSMPythonTools/internal/cacheObject.py#L50

    https://github.com/mocnik-science/osm-python-tools/blob/695ac4f6b9ee1c6ea4071b6dce28160687fd18c8/OSMPythonTools/overpass.py#L77-L78

    https://github.com/mocnik-science/osm-python-tools/blob/695ac4f6b9ee1c6ea4071b6dce28160687fd18c8/OSMPythonTools/overpass.py#L124-L126

    https://github.com/mocnik-science/osm-python-tools/blob/695ac4f6b9ee1c6ea4071b6dce28160687fd18c8/OSMPythonTools/overpass.py#L143-L144

    opened by RaczeQ 0
  • OSMPythonTools.nominatim output preferred language

    OSMPythonTools.nominatim output preferred language

    Maybe I didn't understand how to do it, but it would be very useful to be able to pass a language-related parameter in Nominatim. Something similar to: loc = nominatim.query(*coordinates, reverse=True, wkt=True, language='en' )

    opened by pankus 0
  • Overpass returns every way twice

    Overpass returns every way twice

    I was trying to find all runways within a bounding box, and noticed that I get every runway (mapped as a way with aeroway=runway) twice. Here's a test code:

    from OSMPythonTools import overpass
    query = overpass.overpassQueryBuilder(bbox=[-6.05, 144.95, -6, 145], elementType="way",
                                                                     selector='"aeroway"="runway"', out="body", includeCenter=True)
    result = overpass.Overpass().query(query).ways()
    for e in result:
        print(e, e.tags())
    

    which prints:

    [overpass] downloading data: [timeout:25][out:json];(way["aeroway"="runway"](-6.05,144.95,-6,145);); out center; out body;
    <OSMPythonTools.element.Element object at 0x7fb7a11704c0> {'aeroway': 'runway', 'ele': '1516', 'length': '1015', 'name': '03/21', 'source': 'Bing', 'surface': 'paved'}
    <OSMPythonTools.element.Element object at 0x7fb7a11700d0> {'aeroway': 'runway', 'ele': '1516', 'length': '1015', 'name': '03/21', 'source': 'Bing', 'surface': 'paved'}
    

    You can see that I got two different Elements holding the exact same data. Here's the test area in OSM And Overpass-turbo shows that there is in fact only one way tagged ´aeroway=runway´ in that area.

    opened by TheFGFSEagle 6
Owner
Franz-Benjamin Mocnik
Franz-Benjamin Mocnik
OSMnx: Python for street networks. Retrieve, model, analyze, and visualize street networks and other spatial data from OpenStreetMap.

OSMnx OSMnx is a Python package that lets you download geospatial data from OpenStreetMap and model, project, visualize, and analyze real-world street

Geoff Boeing 4k Jan 8, 2023
Tools for the extraction of OpenStreetMap street network data

OSMnet Tools for the extraction of OpenStreetMap (OSM) street network data. Intended to be used in tandem with Pandana and UrbanAccess libraries to ex

Urban Data Science Toolkit 47 Sep 21, 2022
Location field and widget for Django. It supports Google Maps, OpenStreetMap and Mapbox

django-location-field Let users pick locations using a map widget and store its latitude and longitude. Stable version: django-location-field==2.1.0 D

Caio Ariede 481 Dec 29, 2022
A bot that tweets info and location map for new bicycle parking added to OpenStreetMap within a GeoJSON boundary.

Bike parking tweepy bot app A twitter bot app that searches for bicycle parking added to OpenStreetMap. Relies on AWS Lambda/S3, Python3, Tweepy, Flas

Angelo Trivisonno 1 Dec 19, 2021
Python renderer for OpenStreetMap with custom icons intended to display as many map features as possible

Map Machine project consists of Python OpenStreetMap renderer: SVG map generation, SVG and PNG tile generation, Röntgen icon set: unique CC-BY 4.0 map

Sergey Vartanov 0 Dec 18, 2022
Download and process satellite imagery in Python using Sentinel Hub services.

Description The sentinelhub Python package allows users to make OGC (WMS and WCS) web requests to download and process satellite images within your Py

Sentinel Hub 659 Dec 23, 2022
Python module to access the OpenCage geocoding API

OpenCage Geocoding Module for Python A Python module to access the OpenCage Geocoder. Build Status / Code Quality / etc Usage Supports Python 3.6 or n

OpenCage GmbH 57 Nov 1, 2022
This app displays interesting statistical weather records and trends which can be used in climate related research including study of global warming.

This app displays interesting statistical weather records and trends which can be used in climate related research including study of global warming.

null 0 Dec 27, 2021
Geocoding library for Python.

geopy geopy is a Python client for several popular geocoding web services. geopy makes it easy for Python developers to locate the coordinates of addr

geopy 3.8k Dec 30, 2022
Python interface to PROJ (cartographic projections and coordinate transformations library)

pyproj Python interface to PROJ (cartographic projections and coordinate transformations library). Documentation Stable: http://pyproj4.github.io/pypr

null 832 Dec 31, 2022
PySAL: Python Spatial Analysis Library Meta-Package

Python Spatial Analysis Library PySAL, the Python spatial analysis library, is an open source cross-platform library for geospatial data science with

Python Spatial Analysis Library 1.1k Dec 18, 2022
Python interface to PROJ (cartographic projections and coordinate transformations library)

pyproj Python interface to PROJ (cartographic projections and coordinate transformations library). Documentation Stable: http://pyproj4.github.io/pypr

null 832 Dec 31, 2022
peartree: A library for converting transit data into a directed graph for sketch network analysis.

peartree ?? ?? peartree is a library for converting GTFS feed schedules into a representative directed network graph. The tool uses Partridge to conve

Kuan Butts 183 Dec 29, 2022
Client library for interfacing with USGS datasets

USGS API USGS is a python module for interfacing with the US Geological Survey's API. It provides submodules to interact with various endpoints, and c

Amit Kapadia 104 Dec 30, 2022
Python library to decrypt Airtag reports, as well as a InfluxDB/Grafana self-hosted dashboard example

Openhaystack-python This python daemon will allow you to gather your Openhaystack-based airtag reports and display them on a Grafana dashboard. You ca

Bezmenov Denys 19 Jan 3, 2023
Hapi is a Python library for building Conceptual Distributed Model using HBV96 lumped model & Muskingum routing method

Current build status All platforms: Current release info Name Downloads Version Platforms Hapi - Hydrological library for Python Hapi is an open-sourc

Mostafa Farrag 15 Dec 26, 2022
Python library to visualize circular plasmid maps

Plasmidviewer Plasmidviewer is a Python library to visualize plasmid maps from GenBank. This library provides only the function to visualize circular

Mori Hideto 9 Dec 4, 2022
prettymaps - A minimal Python library to draw customized maps from OpenStreetMap data.

A small set of Python functions to draw pretty maps from OpenStreetMap data. Based on osmnx, matplotlib and shapely libraries.

Marcelo de Oliveira Rosa Prates 9k Jan 8, 2023
RESTler is the first stateful REST API fuzzing tool for automatically testing cloud services through their REST APIs and finding security and reliability bugs in these services.

RESTler is the first stateful REST API fuzzing tool for automatically testing cloud services through their REST APIs and finding security and reliability bugs in these services.

Microsoft 1.8k Jan 4, 2023
Rayvens makes it possible for data scientists to access hundreds of data services within Ray with little effort.

Rayvens augments Ray with events. With Rayvens, Ray applications can subscribe to event streams, process and produce events. Rayvens leverages Apache

CodeFlare 32 Dec 25, 2022