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.
import pandas as pd
import requests
import json
pd.set_option('display.max_columns', 200)
Gebiet festlegen, am besten mit einer Bounding Box
# Get yours at: http://boundingbox.klokantech.com/
bbox = [13.526452,50.932114,13.966063,51.17772]
# Links unten
minLat = bbox[1]
minLon = bbox[0]
# Rechts oben
maxLat = bbox[3]
maxLon = bbox[2]
Request from Overpass-Turbo
osmrequest = {'data': '[out:json][timeout:25];(node["highway"="bus_stop"](%s,%s,%s,%s););out body;>;out skel qt;' % (minLat, minLon, maxLat, maxLon)}
osmurl = 'http://overpass-api.de/api/interpreter'
# Ask the API
osm = requests.get(osmurl, params=osmrequest)
The JSON can't be directyl imported to a Pandas Dataframe:
If the JSON string were to be converted to a Python object, it would be a dict whose elements key is a list of dicts. The vast majority of the data is inside this list of dicts.
This JSON string is not directly convertible to a Pandas object. What would be the index, and what would be the columns? Surely you don't want [u'elements', u'version', u'osm3s', u'generator'] to be the columns, since almost all the information is in the elements list-of-dicts.
But if you want the DataFrame to consist of the data only in the elements list-of-dicts, then you'd have to specify that, since Pandas can't make that assumption for you.
Further complicating things is that each dict in elements is a nested dict.
Thanks to unutbu from stackoverflow.com for fiddling this out!
osmdata = osm.json()
osmdata = osmdata['elements']
for dct in osmdata:
for key, val in dct['tags'].iteritems():
dct[key] = val
del dct['tags']
osmdf = pd.DataFrame(osmdata)
osmdf.head(5)
FIXME | Linie | addr:suburb | alt_name | amenity | bench | bin | bus | bus_lines | bus_routes | comment | covered | created_by | ddbus2010 | description | destination | direction | fee_zone | fixme | highway | id | information | lat | layer | line | lines | lit | local_ref | lon | map_size | map_type | name | network | note | old_name | opening_hours | operator | postal_code | public_transport | railway | ref | ref_name | route_ref | shelter | source | tactile_paving | toilet | toilets | tourism | tram | type | uic_name | waste_basket | website | wheelchair | wheelchair:description | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | bus_stop | 536694 | NaN | 50.984926 | NaN | NaN | NaN | NaN | NaN | 13.682178 | NaN | NaN | Niederhäslich Bergmannsweg | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | node | NaN | NaN | NaN | NaN | NaN |
1 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | bus_stop | 11004528 | NaN | 51.123623 | NaN | NaN | NaN | NaN | NaN | 13.782789 | NaN | NaN | Sagarder Weg | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | node | NaN | NaN | NaN | yes | NaN |
2 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | bus_stop | 11070510 | NaN | 51.081560 | NaN | NaN | NaN | NaN | NaN | 13.900377 | NaN | NaN | Ullersdorf, Gasthof | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | node | NaN | NaN | NaN | NaN | NaN |
3 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | yes | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | bus_stop | 11070784 | NaN | 51.065752 | NaN | NaN | NaN | NaN | NaN | 13.895734 | NaN | NaN | Weißig, Einkaufszentrum | NaN | NaN | NaN | NaN | DVB | NaN | stop_position | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | node | NaN | NaN | NaN | NaN | NaN |
4 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | bus_stop | 11297121 | NaN | 51.007140 | NaN | NaN | NaN | NaN | NaN | 13.698498 | NaN | NaN | Stuttgarter Straße | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | node | NaN | NaN | NaN | NaN | NaN |
busstopsdf = osmdf[['lat', 'lon', 'name', 'wheelchair']].dropna(subset=['name']).fillna(u'unknown')
busstopsdf.head(5)
lat | lon | name | wheelchair | |
---|---|---|---|---|
0 | 50.984926 | 13.682178 | Niederhäslich Bergmannsweg | unknown |
1 | 51.123623 | 13.782789 | Sagarder Weg | yes |
2 | 51.081560 | 13.900377 | Ullersdorf, Gasthof | unknown |
3 | 51.065752 | 13.895734 | Weißig, Einkaufszentrum | unknown |
4 | 51.007140 | 13.698498 | Stuttgarter Straße | unknown |
accesslevel = {'unknown': 0, 'yes': 2, 'limited': 1, 'no': -1}
def getacclev(c):
return accesslevel[c]
busstopsdf['accesslevel'] = busstopsdf.wheelchair.apply(getacclev)
busstopsdf.head(10)
lat | lon | name | wheelchair | accesslevel | |
---|---|---|---|---|---|
0 | 50.984926 | 13.682178 | Niederhäslich Bergmannsweg | unknown | 0 |
1 | 51.123623 | 13.782789 | Sagarder Weg | yes | 2 |
2 | 51.081560 | 13.900377 | Ullersdorf, Gasthof | unknown | 0 |
3 | 51.065752 | 13.895734 | Weißig, Einkaufszentrum | unknown | 0 |
4 | 51.007140 | 13.698498 | Stuttgarter Straße | unknown | 0 |
5 | 51.010199 | 13.701411 | Heilbronner Straße | limited | 1 |
6 | 51.003121 | 13.686136 | Burgker Straße | unknown | 0 |
7 | 50.996333 | 13.689492 | Kleinnaundorf, Schule | unknown | 0 |
8 | 51.087893 | 13.699240 | Peschelstraße/Rankestraße | no | -1 |
9 | 51.086979 | 13.639351 | Gohliser Weg | unknown | 0 |
busstopsdf[['lat','lon','name','accesslevel','wheelchair']].to_csv('bus_stops.csv', sep=',', encoding='utf-8', index=False)
print('Done.')
Done.
busstopsdf.wheelchair.unique()
array([u'unknown', u'yes', u'limited', u'no'], dtype=object)
colorcodes = {'unknown': '#FFFFFF', 'yes': '#00FF00', 'limited': '#FFFF00', 'no': '#FF0000'}
def colorencode(c):
return colorcodes[c]
busstopsdf['color'] = busstopsdf.wheelchair.apply(colorencode)
from bokeh.plotting import *
output_notebook()
output_file("bus_stops.html", title="Bus Stops from openstreetmaps.org")
hold()
circle(busstopsdf['lon'], busstopsdf['lat'],
color=busstopsdf['color'], line_color='black',fill_alpha=0.8,
size=12, title='Bus Stops in Dresden (from openstreetmaps.org)',
background_fill= '#cccccc', tools='pan, wheel_zoom, box_zoom, reset')
text(busstopsdf['lon'], busstopsdf['lat']+0.00002,
text=busstopsdf['name'], angle=0, text_color='#333333',
text_align="center", text_font_size="10pt")
xaxis().axis_label='Lon'
yaxis().axis_label='Lat'
grid().grid_line_color='white'
show()
Session output file 'bus_stops.html' already exists, will be overwritten.