{ "cells": [ { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import geopandas as gpd\n", "\n", "import folium\n", "import branca" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### read input data" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
yearquarterhour_of_daysegment_idstart_junction_idend_junction_idosm_way_idosm_start_node_idosm_end_node_idspeed_kph_meanspeed_kph_stddevspeed_kph_p50speed_kph_p85
0201920d0034ae2336f81ef5933a211f2ce2d979f0aff2a66081f9fe2860af2a498e1248334cb51d6ea50739c00a9375aeaba9c08f4f2fd507cc1808ba83b8999320851236497729123649775241.2589.23941.33046.680
12019223d0034ae2336f81ef5933a211f2ce2d979f0aff2a66081f9fe2860af2a498e1248334cb51d6ea50739c00a9375aeaba9c08f4f2fd507cc1808ba83b8999320851236497729123649775235.7946.70635.83241.398
22019222d0034ae2336f81ef5933a211f2ce2d979f0aff2a66081f9fe2860af2a498e1248334cb51d6ea50739c00a9375aeaba9c08f4f2fd507cc1808ba83b8999320851236497729123649775232.76613.40135.17143.469
32019223277640ca389fc7f0fc8a583386e6063df80485f0ad26106a25d52c3409bd0165f05de3047a4e96b59c00a9375aeaba9c08f4f2fd507cc1808ba83b89993208581398215123649775234.5074.63935.20738.160
4201921277640ca389fc7f0fc8a583386e6063df80485f0ad26106a25d52c3409bd0165f05de3047a4e96b59c00a9375aeaba9c08f4f2fd507cc1808ba83b89993208581398215123649775241.5126.04941.12847.681
\n", "
" ], "text/plain": [ " year quarter hour_of_day segment_id \\\n", "0 2019 2 0 d0034ae2336f81ef5933a211f2ce2d979f0aff2a \n", "1 2019 2 23 d0034ae2336f81ef5933a211f2ce2d979f0aff2a \n", "2 2019 2 22 d0034ae2336f81ef5933a211f2ce2d979f0aff2a \n", "3 2019 2 23 277640ca389fc7f0fc8a583386e6063df80485f0 \n", "4 2019 2 1 277640ca389fc7f0fc8a583386e6063df80485f0 \n", "\n", " start_junction_id \\\n", "0 66081f9fe2860af2a498e1248334cb51d6ea5073 \n", "1 66081f9fe2860af2a498e1248334cb51d6ea5073 \n", "2 66081f9fe2860af2a498e1248334cb51d6ea5073 \n", "3 ad26106a25d52c3409bd0165f05de3047a4e96b5 \n", "4 ad26106a25d52c3409bd0165f05de3047a4e96b5 \n", "\n", " end_junction_id osm_way_id osm_start_node_id \\\n", "0 9c00a9375aeaba9c08f4f2fd507cc1808ba83b89 9932085 1236497729 \n", "1 9c00a9375aeaba9c08f4f2fd507cc1808ba83b89 9932085 1236497729 \n", "2 9c00a9375aeaba9c08f4f2fd507cc1808ba83b89 9932085 1236497729 \n", "3 9c00a9375aeaba9c08f4f2fd507cc1808ba83b89 9932085 81398215 \n", "4 9c00a9375aeaba9c08f4f2fd507cc1808ba83b89 9932085 81398215 \n", "\n", " osm_end_node_id speed_kph_mean speed_kph_stddev speed_kph_p50 \\\n", "0 1236497752 41.258 9.239 41.330 \n", "1 1236497752 35.794 6.706 35.832 \n", "2 1236497752 32.766 13.401 35.171 \n", "3 1236497752 34.507 4.639 35.207 \n", "4 1236497752 41.512 6.049 41.128 \n", "\n", " speed_kph_p85 \n", "0 46.680 \n", "1 41.398 \n", "2 43.469 \n", "3 38.160 \n", "4 47.681 " ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#https://movement.uber.com/cities/berlin/downloads/speeds?lang=en-US&tp[y]=2019&tp[q]=2\n", "uber_data= pd.read_csv(r\"movement-speeds-quarterly-by-hod-berlin-2019-Q2.csv\\movement-speeds-quarterly-by-hod-berlin-2019-Q2.csv\")\n", "uber_data.head()" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
id@idcycleway:righthighwaylaneslitmaxspeednameonewaypostal_code...after_construction:lanesafter_construction:parking:condition:rightafter_construction:parking:lane:rightconstructionconstruction:end_datedisused:cycleway:leftprotected_bike_lane:rightcycleway:right:buffergeometryosm_way_id
0way/4045243way/4045243trackprimary3yes50Frankfurter Alleeyes10247...NoneNoneNoneNoneNoneNoneNoneNoneLINESTRING (13.45421 52.51571, 13.45439 52.515...4045243
1way/4045656way/4045656Nonesecondary2None50HauptstraßeNoneNone...NoneNoneNoneNoneNoneNoneNoneNoneLINESTRING (13.37282 52.59334, 13.37281 52.593...4045656
2way/4054013way/4054013trackprimary3yes50Michael-Brückner-Straßeyes12439...NoneNoneNoneNoneNoneNoneNoneNoneLINESTRING (13.51476 52.45303, 13.51528 52.452...4054013
3way/4067882way/4067882tracksecondaryNoneyes50Olympische Straßeyes14052...NoneNoneNoneNoneNoneNoneNoneNoneLINESTRING (13.24937 52.51535, 13.24967 52.515...4067882
4way/4067883way/4067883Nonesecondary4yes50JafféstraßeNone14052...NoneNoneNoneNoneNoneNoneNoneNoneLINESTRING (13.26152 52.50771, 13.26179 52.507...4067883
\n", "

5 rows × 431 columns

\n", "
" ], "text/plain": [ " id @id cycleway:right highway lanes lit maxspeed \\\n", "0 way/4045243 way/4045243 track primary 3 yes 50 \n", "1 way/4045656 way/4045656 None secondary 2 None 50 \n", "2 way/4054013 way/4054013 track primary 3 yes 50 \n", "3 way/4067882 way/4067882 track secondary None yes 50 \n", "4 way/4067883 way/4067883 None secondary 4 yes 50 \n", "\n", " name oneway postal_code ... after_construction:lanes \\\n", "0 Frankfurter Allee yes 10247 ... None \n", "1 Hauptstraße None None ... None \n", "2 Michael-Brückner-Straße yes 12439 ... None \n", "3 Olympische Straße yes 14052 ... None \n", "4 Jafféstraße None 14052 ... None \n", "\n", " after_construction:parking:condition:right \\\n", "0 None \n", "1 None \n", "2 None \n", "3 None \n", "4 None \n", "\n", " after_construction:parking:lane:right construction construction:end_date \\\n", "0 None None None \n", "1 None None None \n", "2 None None None \n", "3 None None None \n", "4 None None None \n", "\n", " disused:cycleway:left protected_bike_lane:right cycleway:right:buffer \\\n", "0 None None None \n", "1 None None None \n", "2 None None None \n", "3 None None None \n", "4 None None None \n", "\n", " geometry osm_way_id \n", "0 LINESTRING (13.45421 52.51571, 13.45439 52.515... 4045243 \n", "1 LINESTRING (13.37282 52.59334, 13.37281 52.593... 4045656 \n", "2 LINESTRING (13.51476 52.45303, 13.51528 52.452... 4054013 \n", "3 LINESTRING (13.24937 52.51535, 13.24967 52.515... 4067882 \n", "4 LINESTRING (13.26152 52.50771, 13.26179 52.507... 4067883 \n", "\n", "[5 rows x 431 columns]" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#http://overpass-turbo.eu/s/PVh\n", "#osm_links = gpd.read_file('xhain.geojson')\n", "#http://overpass-turbo.eu/s/PVN\n", "osm_links = gpd.read_file('berlin.geojson')\n", "\n", "osm_links['osm_way_id']=osm_links['id'].str[4:]\n", "osm_links.osm_way_id=osm_links.osm_way_id.astype(int)\n", "osm_links.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### produce output interactive html maps" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [], "source": [ "# helper\n", "import folium.plugins\n", "from folium.features import *\n", "\n", "class DivIcon(MacroElement):\n", " def __init__(self, html='', size=(30,30), anchor=(0,0), style=''):\n", " \"\"\"TODO : docstring here\"\"\"\n", " super(DivIcon, self).__init__()\n", " self._name = 'DivIcon'\n", " self.size = size\n", " self.anchor = anchor\n", " self.html = html\n", " self.style = style\n", "\n", " self._template = Template(u\"\"\"\n", " {% macro header(this, kwargs) %}\n", " \n", " {% endmacro %}\n", " {% macro script(this, kwargs) %}\n", " var {{this.get_name()}} = L.divIcon({\n", " className: '{{this.get_name()}}',\n", " iconSize: [{{ this.size[0] }},{{ this.size[1] }}],\n", " iconAnchor: [{{ this.anchor[0] }},{{ this.anchor[1] }}],\n", " html : \"{{this.html}}\",\n", " });\n", " {{this._parent.get_name()}}.setIcon({{this.get_name()}});\n", " {% endmacro %}\n", " \"\"\")" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\Simon\\Anaconda3\\envs\\geo_julab\\lib\\site-packages\\pyproj\\crs.py:77: FutureWarning: '+init=:' syntax is deprecated. ':' is the preferred initialization method.\n", " return _prepare_from_string(\" \".join(pjargs))\n" ] } ], "source": [ "#production\n", "\n", "for h in uber_data.hour_of_day.unique():\n", "\n", " #get ready\n", " uber_data_h=uber_data[uber_data.hour_of_day==h].copy()\n", " uber_data_h=uber_data_h.groupby('osm_way_id')['speed_kph_mean'].mean().reset_index().copy()\n", "\n", " #merge uber and osm\n", " data_merg= pd.merge(osm_links[['geometry','osm_way_id','name','postal_code', 'maxspeed']],uber_data_h[['speed_kph_mean','osm_way_id']] )\n", "\n", " data_merg.maxspeed= data_merg.maxspeed.apply(lambda x: 50 if x=='DE:urban' else x)\n", " data_merg.maxspeed=data_merg.maxspeed.astype(float)\n", "\n", "\n", "\n", "\n", " #plot map\n", " df=data_merg[(data_merg.speed_kph_mean<33) & (data_merg.maxspeed>=50) ]\n", " field='speed_kph_mean'\n", "\n", " colorscale = branca.colormap.LinearColormap(['green','lightgreen','orange','red'], \n", " index=[20,30,50,55], \n", " vmin=0, \n", " vmax=33, \n", " caption='')\n", "\n", " def style_function(feature):\n", " col=feature['properties'][field]\n", " return {\n", " #'fillOpacity': 0.5,\n", " 'weight': 3,\n", " 'color': 'grey' if col is None else colorscale(col)\n", " }\n", "\n", " def highlight_function(feature):\n", " return {\n", " 'color': 'grey',\n", " 'weight': 5,\n", " 'dashArray': '5, 5'\n", " }\n", "\n", " m = folium.Map(location=[52.5, 13.4],\n", " tiles=\"cartodbpositron\",\n", " name=\"CartoDB light\",\n", " zoom_start=13)\n", "\n", " folium.GeoJson(\n", " df,\n", " name=str(h)+' Uhr',\n", " style_function=style_function,\n", " highlight_function=highlight_function,\n", " tooltip=folium.GeoJsonTooltip(fields=['name','speed_kph_mean','maxspeed'],\n", " aliases=['name','speed_kph_mean','maxspeed']),\n", " ).add_to(m)\n", "\n", " \n", " \n", " folium.map.Marker(\n", " #[34.0302, -118.2352],\n", " [52.449463, 13.404811],\n", " icon=DivIcon(\n", " size=(150,36),\n", " anchor=(150,0),\n", " html=str(h)+' Uhr',\n", " style=\"\"\"\n", " font-size:36px;\n", " background-color: transparent;\n", " border-color: transparent;\n", " text-align: right;\n", " \"\"\"\n", " )\n", " ).add_to(m) \n", " \n", " \n", " \n", "\n", " #m\n", " folium.LayerControl(position='bottomright',collapsed=False).add_to(m)\n", " \n", " colorscale.caption = 'Speed'\n", " m.add_child(colorscale)\n", "\n", " m.save(\"output/map_\"+str(h)+\".html\")\n", " #m" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### create plot from htmls" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from selenium import webdriver #requires chromesdriver\n", "from PIL import Image\n", "import os" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [], "source": [ "options = webdriver.ChromeOptions()\n", "#options.add_argument('--headless')\n", "driver = webdriver.Chrome(options=options)\n", "\n", "for h in uber_data.hour_of_day.unique():\n", " driver.get(os.getcwd() + '\\\\output\\\\map_'+str(h)+'.html')\n", " driver.save_screenshot('output\\\\map_'+str(h)+'.png')\n", " \n", " # newImg = Image.open('map_'+str(h)+'.png')\n", " # newImg.save('map_'+str(h)+'_compressed.png', 'PNG', dpi=[200,200])\n", "\n", "driver.close()" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "#for h in uber_data.hour_of_day.unique():\n", "# newImg = Image.open('map_'+str(h)+'.png')\n", "# newImg = newImg.resize((400,400),Image.ANTIALIAS)\n", "# newImg.save('map_'+str(h)+'_compressed_o.png', 'PNG', optimize=True, dpi=(300,300))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### produce gif from images, finally compress gif" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['output\\\\map_0.png',\n", " 'output\\\\map_1.png',\n", " 'output\\\\map_10.png',\n", " 'output\\\\map_11.png',\n", " 'output\\\\map_12.png',\n", " 'output\\\\map_13.png',\n", " 'output\\\\map_14.png',\n", " 'output\\\\map_15.png',\n", " 'output\\\\map_16.png',\n", " 'output\\\\map_17.png',\n", " 'output\\\\map_18.png',\n", " 'output\\\\map_19.png',\n", " 'output\\\\map_2.png',\n", " 'output\\\\map_20.png',\n", " 'output\\\\map_21.png',\n", " 'output\\\\map_22.png',\n", " 'output\\\\map_23.png',\n", " 'output\\\\map_3.png',\n", " 'output\\\\map_4.png',\n", " 'output\\\\map_5.png',\n", " 'output\\\\map_6.png',\n", " 'output\\\\map_7.png',\n", " 'output\\\\map_8.png',\n", " 'output\\\\map_9.png']" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import glob\n", "\n", "filenames= glob.glob(\"output\\\\map*.png\")\n", "filenames" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['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']\n" ] } ], "source": [ "# sort by hour\n", "import re\n", "\n", "def atoi(text):\n", " return int(text) if text.isdigit() else text\n", "\n", "def natural_keys(text):\n", " '''\n", " alist.sort(key=natural_keys) sorts in human order\n", " http://nedbatchelder.com/blog/200712/human_sorting.html\n", " (See Toothy's implementation in the comments)\n", " '''\n", " return [ atoi(c) for c in re.split(r'(\\d+)', text) ]\n", "\n", "\n", "filenames.sort(key=natural_keys)\n", "print(filenames)" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [], "source": [ "import imageio\n", "\n", "images = []\n", "for filename in filenames:\n", " images.append(imageio.imread(filename))\n", "imageio.mimsave('output\\\\uber_berlin2019Q2_50to30_24h.gif', images, format='GIF', duration=0.2)\n", "#imageio.mimsave(exportname, frames, format='GIF', duration=5)" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#compress gif with gifsicle (install gifsicle first)\n", "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\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.0" } }, "nbformat": 4, "nbformat_minor": 4 }