Read Overpass-API to Python Pandas Dataframe

The Overpass API provides access to the data behind the Openstreetmaps Map Data. The Overpass-Turbo is the easyiest way to test requests and get the correct code to ask the database.

In [70]:
import pandas as pd
import requests
import json
pd.set_option('display.max_columns', 200)

Kreuzungen in OSM finden

Annahme: Eine Kreuzung ist dadurch definiert, dass es ein Node gibt, der mindestens zu 2 verschiedenen highways gehört.

Gebiet festlegen, am besten mit einer Bounding Box

In [71]:
# Get yours at: http://boundingbox.klokantech.com/
bbox = [13.521945,50.919085,13.976063,51.18772]

# Links unten
minLat = bbox[1]
minLon = bbox[0]

# Rechts oben
maxLat = bbox[3]
maxLon = bbox[2]

Construct the Overpass Query String

Request from Overpass-Turbo

In [72]:
tags = ['primary','secondary','secondary_link','tertiary','tertiary_link','living_street','residential']
objects = ['way'] # like way, node, relation

compactOverpassQLstring = '[out:json][timeout:60];('
for tag in tags:
    for obj in objects:
        compactOverpassQLstring += '%s["highway"="%s"](%s,%s,%s,%s);' % (obj, tag, minLat, minLon, maxLat, maxLon)
compactOverpassQLstring += ');out body;>;out skel qt;'    
In [73]:
osmrequest = {'data': compactOverpassQLstring}
osmurl = 'http://overpass-api.de/api/interpreter'

# Ask the API
osm = requests.get(osmurl, params=osmrequest)

Reformat the JSON to fit in a Pandas Dataframe

The JSON can't be directyl imported to a Pandas Dataframe:

Thanks to unutbu from stackoverflow.com for fiddling this out!

In [74]:
osmdata = osm.json()
osmdata = osmdata['elements']
for dct in osmdata:
    if dct['type']=='way':
        for key, val in dct['tags'].iteritems():
            dct[key] = val
        del dct['tags']
    else:
        pass # nodes

Now put everything to the Pandas Dataframe

In [75]:
osmdf = pd.DataFrame(osmdata)

Look at the whole Dataframe

In [76]:
osmdf.tail(5)
Out[76]:
FIXME access access:N3 access:conditional access:lanes addr:city addr:country addr:postcode addr:street addr:suburb agricultural alt_name amenity area area:highway bicycle bicycle:backward bicycle:forward bridge bridge_name bridge_type bus bus:lanes:backward bus:lanes:forward busway:right change:lanes:backward change:lanes:forward class:bicycle collection_times comment comment:history construction construction:end construction:obstruction construction:start covered created_by cutting cycleway cycleway:bicycle cycleway:foot cycleway:forward cycleway:left cycleway:left:bicycle cycleway:left:foot cycleway:oneway cycleway:right cycleway:right:bicycle cycleway:right:oneway cycleway:right:segregated cycleway:right:smoothness cycleway:right:surface cycleway:segregated cycleway:smoothness day_off day_on delivery description designation destination destination:backward destination:forward destination:lanes destination:lanes:forward destination:ref destination:ref:backward disused:highway electrified embankment est_width fake_gaslight fixme flood_prone foot footway footway:left footway:right forestry frequency gauge goods hazmat:backward hazmat:forward hgv hgv:backward hgv:conditional hgv:forward hgv:hazard highway historical_name history horse hour_off hour_on id image incline int_name int_ref is_in ... motorroad mtb mtb:scale mtb:scale:uphill name name:be name:de name:es narrow nat_ref nodes noexit note note:FIXME note:maxheight old_name old_name:1897 oneway oneway:bicycle overtaking overtaking:hgv parking:condition:both parking:condition:both:maxstay parking:condition:both:time_interval parking:condition:left parking:condition:left:fee_per_hour parking:condition:left:maxstay parking:condition:left:time_interval parking:condition:maxstay parking:condition:right parking:condition:right:fee_per_hour parking:condition:right:maxstay parking:condition:right:time_interval parking:condition:right:vehicles parking:lane parking:lane:both parking:lane:left parking:lane:left:capacity parking:lane:left:parallel parking:lane:right parking:lane:right:capacity parking:lane:right:diagonal parking:lane:right:parallel placement planned postal_code psv railway ref segregated service short_name sidewalk sidewalk:right smoking smoothness source source:highway source:maxheight source:maxspeed source:maxspeed:backward source:maxspeed:conditional source:maxspeed:forward source:maxspeed:hgv source:name source:surface source:width source_ref surface surface:left surface:right taxi tracks tracktype traffic_calming traffic_sign tram:lanes:backward tram:lanes:forward tree_lined tunnel turn turn:lanes turn:lanes:backward turn:lanes:forward type vehicle vehicle:backward vehicle:forward vehicle:forward:conditional voltage wheelchair width wikipedia wikipedia:de xmas:day_date xmas:feature xmas:name xmas:opening_hours zone:maxspeed zone:traffic
100538 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 390316202 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN node NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
100539 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1841220477 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN node NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
100540 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 60619766 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN node NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
100541 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 60619767 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN node NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
100542 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 457976561 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN node NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

5 rows × 252 columns

Look at some Tags

In [77]:
for tag in osmdf.highway.unique():
    print tag
residential
living_street
secondary
tertiary
primary
secondary_link
tertiary_link
nan
In [78]:
for tag in osmdf.maxspeed.unique():
    print tag
30
nan
50
70
60
100
20
40
5
80
10
walk
7
8
5 mph

The interesting ones are

Nur ways behalten, die auch als highway gekennzeichnet sind und einen Namen haben.

In [79]:
highwaydf = osmdf[['id', 'highway', 'lanes', 'name', 'maxspeed', 'nodes', 'ref']].dropna(subset=['name','highway'], how='any')
highwaydf.tail(5)
Out[79]:
id highway lanes name maxspeed nodes ref
16374 293501216 secondary NaN Tiergartenstraße 50 [373247978, 373247792, 373247777, 373247621, 2... NaN
16375 293501217 secondary NaN Tiergartenstraße 50 [2971077364, 18630288, 796746061, 796746056, 3... NaN
16376 293509214 residential NaN Lockwitzbachweg NaN [773905499, 2693555506, 2261360369, 206122406] NaN
16377 293808792 residential NaN Talstraße NaN [2973933926, 2973933927] NaN
16378 293808793 residential NaN Talstraße NaN [2973933927, 304417978] NaN

Clean a little bit up

Zu kleine Straßen raus werfen

In [80]:
highwaydf = highwaydf[highwaydf['highway'].isin(tags)]

Replace NaN with word unknown and reset the index

In [81]:
highwaydf = highwaydf.fillna(u'unknown').reset_index(drop=True)
highwaydf.tail(5)
Out[81]:
id highway lanes name maxspeed nodes ref
14645 293501216 secondary unknown Tiergartenstraße 50 [373247978, 373247792, 373247777, 373247621, 2... unknown
14646 293501217 secondary unknown Tiergartenstraße 50 [2971077364, 18630288, 796746061, 796746056, 3... unknown
14647 293509214 residential unknown Lockwitzbachweg unknown [773905499, 2693555506, 2261360369, 206122406] unknown
14648 293808792 residential unknown Talstraße unknown [2973933926, 2973933927] unknown
14649 293808793 residential unknown Talstraße unknown [2973933927, 304417978] unknown

Now get all Nodes

In [82]:
nodes = []
for dct in osmdata:
    #print dct
    if dct['type']=='way':
        pass
    elif dct['type']=='node':
        nodes.append(dct)
    else:
        pass
In [83]:
nodesdf = pd.DataFrame(nodes)
In [84]:
nodesdf.tail(5)
Out[84]:
id lat lon type
84159 390316202 51.188021 13.933286 node
84160 1841220477 51.188789 13.968988 node
84161 60619766 51.187108 13.967311 node
84162 60619767 51.189634 13.969590 node
84163 457976561 51.188113 13.968319 node

Find all highways belonging to a node

Jeden Knoten durch gehen und schauen, ob er bei einer Straße genutzt wird. Wenn ja, die Straßen IDs zurück geben.

In [85]:
def gethighwayids(nodeid):
    highwayids = []
    for n, nodes in enumerate(highwaydf['nodes']):
        for nid in nodes: # alle nodes des highways
            if nid == int(nodeid):
                highwayids.append(highwaydf['id'][n])
    return highwayids

Dauert sehr sehr lang, wenn BoundingBox groß gewählt wurde!

In [86]:
nodesdf['highwayids'] = nodesdf['id'].apply(gethighwayids)
In [87]:
nodesdf.head(10)
Out[87]:
id lat lon type highwayids
0 32456409 50.924436 13.525700 node []
1 87215458 50.921920 13.521153 node [10313904]
2 87215459 50.921850 13.521617 node [10313904]
3 87215462 50.921374 13.524183 node [10313904]
4 87215463 50.921254 13.525067 node [10313904]
5 87215464 50.921168 13.525685 node [10313904]
6 87215465 50.921135 13.526123 node [10313904]
7 614864158 50.921536 13.523308 node [10313904]
8 32456411 50.923717 13.523962 node []
9 32456413 50.923199 13.522634 node []

Identify a Junction

Node with at least 3 different highways

In [88]:
def identifyjunction(highwayids):
    #print highwayids
    if len(highwayids) < 2:
        return False
    elif len(highwayids)==2:
        # Wenn beide Highways den gleichen Namen haben, ist es nur
        # ein Zwischenstück und keine Kreuzung
        name1=unicode(highwaydf[highwaydf['id']==highwayids[0]]['name'].values)
        name2=unicode(highwaydf[highwaydf['id']==highwayids[1]]['name'].values)
        if name1==name2:
            #print('%s=%s' % (name1, name2))
            return False
        else:
            return True
    else:
        return True
In [89]:
nodesdf['junction'] = nodesdf['highwayids'].apply(identifyjunction)
In [90]:
nodesdf.tail(10)
Out[90]:
id lat lon type highwayids junction
84154 260131313 51.187867 13.907815 node [23992944] False
84155 260131314 51.187750 13.908055 node [23992944] False
84156 115777097 51.187300 13.932714 node [168364168] False
84157 115776949 51.190797 13.933067 node [168364168] False
84158 115777099 51.188737 13.933498 node [168364168] False
84159 390316202 51.188021 13.933286 node [168364168] False
84160 1841220477 51.188789 13.968988 node [173268928] False
84161 60619766 51.187108 13.967311 node [173268928, 173453037] False
84162 60619767 51.189634 13.969590 node [173268928] False
84163 457976561 51.188113 13.968319 node [173268928] False
In [91]:
junctionsdf = nodesdf[['id','lat','lon']][nodesdf['junction']==True]

Export to CSV

In [92]:
junctionsdf.to_csv('junctions.csv', index=False)
print('done.')
done.