import pandas as pd
import geopandas as gpd
import folium
import branca
#https://movement.uber.com/cities/berlin/downloads/speeds?lang=en-US&tp[y]=2019&tp[q]=2
uber_data= pd.read_csv(r"movement-speeds-quarterly-by-hod-berlin-2019-Q2.csv\movement-speeds-quarterly-by-hod-berlin-2019-Q2.csv")
uber_data.head()
year | quarter | hour_of_day | segment_id | start_junction_id | end_junction_id | osm_way_id | osm_start_node_id | osm_end_node_id | speed_kph_mean | speed_kph_stddev | speed_kph_p50 | speed_kph_p85 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2019 | 2 | 0 | d0034ae2336f81ef5933a211f2ce2d979f0aff2a | 66081f9fe2860af2a498e1248334cb51d6ea5073 | 9c00a9375aeaba9c08f4f2fd507cc1808ba83b89 | 9932085 | 1236497729 | 1236497752 | 41.258 | 9.239 | 41.330 | 46.680 |
1 | 2019 | 2 | 23 | d0034ae2336f81ef5933a211f2ce2d979f0aff2a | 66081f9fe2860af2a498e1248334cb51d6ea5073 | 9c00a9375aeaba9c08f4f2fd507cc1808ba83b89 | 9932085 | 1236497729 | 1236497752 | 35.794 | 6.706 | 35.832 | 41.398 |
2 | 2019 | 2 | 22 | d0034ae2336f81ef5933a211f2ce2d979f0aff2a | 66081f9fe2860af2a498e1248334cb51d6ea5073 | 9c00a9375aeaba9c08f4f2fd507cc1808ba83b89 | 9932085 | 1236497729 | 1236497752 | 32.766 | 13.401 | 35.171 | 43.469 |
3 | 2019 | 2 | 23 | 277640ca389fc7f0fc8a583386e6063df80485f0 | ad26106a25d52c3409bd0165f05de3047a4e96b5 | 9c00a9375aeaba9c08f4f2fd507cc1808ba83b89 | 9932085 | 81398215 | 1236497752 | 34.507 | 4.639 | 35.207 | 38.160 |
4 | 2019 | 2 | 1 | 277640ca389fc7f0fc8a583386e6063df80485f0 | ad26106a25d52c3409bd0165f05de3047a4e96b5 | 9c00a9375aeaba9c08f4f2fd507cc1808ba83b89 | 9932085 | 81398215 | 1236497752 | 41.512 | 6.049 | 41.128 | 47.681 |
#http://overpass-turbo.eu/s/PVh
#osm_links = gpd.read_file('xhain.geojson')
#http://overpass-turbo.eu/s/PVN
osm_links = gpd.read_file('berlin.geojson')
osm_links['osm_way_id']=osm_links['id'].str[4:]
osm_links.osm_way_id=osm_links.osm_way_id.astype(int)
osm_links.head()
id | @id | cycleway:right | highway | lanes | lit | maxspeed | name | oneway | postal_code | ... | after_construction:lanes | after_construction:parking:condition:right | after_construction:parking:lane:right | construction | construction:end_date | disused:cycleway:left | protected_bike_lane:right | cycleway:right:buffer | geometry | osm_way_id | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | way/4045243 | way/4045243 | track | primary | 3 | yes | 50 | Frankfurter Allee | yes | 10247 | ... | None | None | None | None | None | None | None | None | LINESTRING (13.45421 52.51571, 13.45439 52.515... | 4045243 |
1 | way/4045656 | way/4045656 | None | secondary | 2 | None | 50 | Hauptstraße | None | None | ... | None | None | None | None | None | None | None | None | LINESTRING (13.37282 52.59334, 13.37281 52.593... | 4045656 |
2 | way/4054013 | way/4054013 | track | primary | 3 | yes | 50 | Michael-Brückner-Straße | yes | 12439 | ... | None | None | None | None | None | None | None | None | LINESTRING (13.51476 52.45303, 13.51528 52.452... | 4054013 |
3 | way/4067882 | way/4067882 | track | secondary | None | yes | 50 | Olympische Straße | yes | 14052 | ... | None | None | None | None | None | None | None | None | LINESTRING (13.24937 52.51535, 13.24967 52.515... | 4067882 |
4 | way/4067883 | way/4067883 | None | secondary | 4 | yes | 50 | Jafféstraße | None | 14052 | ... | None | None | None | None | None | None | None | None | LINESTRING (13.26152 52.50771, 13.26179 52.507... | 4067883 |
5 rows × 431 columns
# helper
import folium.plugins
from folium.features import *
class DivIcon(MacroElement):
def __init__(self, html='', size=(30,30), anchor=(0,0), style=''):
"""TODO : docstring here"""
super(DivIcon, self).__init__()
self._name = 'DivIcon'
self.size = size
self.anchor = anchor
self.html = html
self.style = style
self._template = Template(u"""
{% macro header(this, kwargs) %}
<style>
.{{this.get_name()}} {
{{this.style}}
}
</style>
{% endmacro %}
{% macro script(this, kwargs) %}
var {{this.get_name()}} = L.divIcon({
className: '{{this.get_name()}}',
iconSize: [{{ this.size[0] }},{{ this.size[1] }}],
iconAnchor: [{{ this.anchor[0] }},{{ this.anchor[1] }}],
html : "{{this.html}}",
});
{{this._parent.get_name()}}.setIcon({{this.get_name()}});
{% endmacro %}
""")
#production
for h in uber_data.hour_of_day.unique():
#get ready
uber_data_h=uber_data[uber_data.hour_of_day==h].copy()
uber_data_h=uber_data_h.groupby('osm_way_id')['speed_kph_mean'].mean().reset_index().copy()
#merge uber and osm
data_merg= pd.merge(osm_links[['geometry','osm_way_id','name','postal_code', 'maxspeed']],uber_data_h[['speed_kph_mean','osm_way_id']] )
data_merg.maxspeed= data_merg.maxspeed.apply(lambda x: 50 if x=='DE:urban' else x)
data_merg.maxspeed=data_merg.maxspeed.astype(float)
#plot map
df=data_merg[(data_merg.speed_kph_mean<33) & (data_merg.maxspeed>=50) ]
field='speed_kph_mean'
colorscale = branca.colormap.LinearColormap(['green','lightgreen','orange','red'],
index=[20,30,50,55],
vmin=0,
vmax=33,
caption='')
def style_function(feature):
col=feature['properties'][field]
return {
#'fillOpacity': 0.5,
'weight': 3,
'color': 'grey' if col is None else colorscale(col)
}
def highlight_function(feature):
return {
'color': 'grey',
'weight': 5,
'dashArray': '5, 5'
}
m = folium.Map(location=[52.5, 13.4],
tiles="cartodbpositron",
name="CartoDB light",
zoom_start=13)
folium.GeoJson(
df,
name=str(h)+' Uhr',
style_function=style_function,
highlight_function=highlight_function,
tooltip=folium.GeoJsonTooltip(fields=['name','speed_kph_mean','maxspeed'],
aliases=['name','speed_kph_mean','maxspeed']),
).add_to(m)
folium.map.Marker(
#[34.0302, -118.2352],
[52.449463, 13.404811],
icon=DivIcon(
size=(150,36),
anchor=(150,0),
html=str(h)+' Uhr',
style="""
font-size:36px;
background-color: transparent;
border-color: transparent;
text-align: right;
"""
)
).add_to(m)
#m
folium.LayerControl(position='bottomright',collapsed=False).add_to(m)
colorscale.caption = 'Speed'
m.add_child(colorscale)
m.save("output/map_"+str(h)+".html")
#m
C:\Users\Simon\Anaconda3\envs\geo_julab\lib\site-packages\pyproj\crs.py:77: FutureWarning: '+init=<authority>:<code>' syntax is deprecated. '<authority>:<code>' is the preferred initialization method. return _prepare_from_string(" ".join(pjargs))
from selenium import webdriver #requires chromesdriver
from PIL import Image
import os
options = webdriver.ChromeOptions()
#options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
for h in uber_data.hour_of_day.unique():
driver.get(os.getcwd() + '\\output\\map_'+str(h)+'.html')
driver.save_screenshot('output\\map_'+str(h)+'.png')
# newImg = Image.open('map_'+str(h)+'.png')
# newImg.save('map_'+str(h)+'_compressed.png', 'PNG', dpi=[200,200])
driver.close()
#for h in uber_data.hour_of_day.unique():
# newImg = Image.open('map_'+str(h)+'.png')
# newImg = newImg.resize((400,400),Image.ANTIALIAS)
# newImg.save('map_'+str(h)+'_compressed_o.png', 'PNG', optimize=True, dpi=(300,300))
import glob
filenames= glob.glob("output\\map*.png")
filenames
['output\\map_0.png', 'output\\map_1.png', 'output\\map_10.png', 'output\\map_11.png', 'output\\map_12.png', 'output\\map_13.png', 'output\\map_14.png', 'output\\map_15.png', 'output\\map_16.png', 'output\\map_17.png', 'output\\map_18.png', 'output\\map_19.png', 'output\\map_2.png', 'output\\map_20.png', 'output\\map_21.png', 'output\\map_22.png', 'output\\map_23.png', 'output\\map_3.png', 'output\\map_4.png', 'output\\map_5.png', 'output\\map_6.png', 'output\\map_7.png', 'output\\map_8.png', 'output\\map_9.png']
# sort by hour
import re
def atoi(text):
return int(text) if text.isdigit() else text
def natural_keys(text):
'''
alist.sort(key=natural_keys) sorts in human order
http://nedbatchelder.com/blog/200712/human_sorting.html
(See Toothy's implementation in the comments)
'''
return [ atoi(c) for c in re.split(r'(\d+)', text) ]
filenames.sort(key=natural_keys)
print(filenames)
['output\\map_0.png', 'output\\map_1.png', 'output\\map_2.png', 'output\\map_3.png', 'output\\map_4.png', 'output\\map_5.png', 'output\\map_6.png', 'output\\map_7.png', 'output\\map_8.png', 'output\\map_9.png', 'output\\map_10.png', 'output\\map_11.png', 'output\\map_12.png', 'output\\map_13.png', 'output\\map_14.png', 'output\\map_15.png', 'output\\map_16.png', 'output\\map_17.png', 'output\\map_18.png', 'output\\map_19.png', 'output\\map_20.png', 'output\\map_21.png', 'output\\map_22.png', 'output\\map_23.png']
import imageio
images = []
for filename in filenames:
images.append(imageio.imread(filename))
imageio.mimsave('output\\uber_berlin2019Q2_50to30_24h.gif', images, format='GIF', duration=0.2)
#imageio.mimsave(exportname, frames, format='GIF', duration=5)
#compress gif with gifsicle (install gifsicle first)
os.system("C:\ProgramData\gifsicle-1.92-win64\gifsicle-1.92\gifsicle.exe -O3 output\\uber_berlin2019Q2_50to30_24h.gif -o output\\uber_berlin2019Q2_50to30_24h.gif")
0