{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Intro\n", "A simple example of visualizing geoson data in python using [Folium](https://folium.readthedocs.org/en/latest/). We obtain Philly Indego bike data from [opendataphilly](https://www.opendataphilly.org/dataset/bike-share-stations) website. We download the data using the website's free public api." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "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", "
featurestype
0{u'geometry': {u'type': u'Point', u'coordinate...FeatureCollection
1{u'geometry': {u'type': u'Point', u'coordinate...FeatureCollection
2{u'geometry': {u'type': u'Point', u'coordinate...FeatureCollection
3{u'geometry': {u'type': u'Point', u'coordinate...FeatureCollection
4{u'geometry': {u'type': u'Point', u'coordinate...FeatureCollection
\n", "
" ], "text/plain": [ " features type\n", "0 {u'geometry': {u'type': u'Point', u'coordinate... FeatureCollection\n", "1 {u'geometry': {u'type': u'Point', u'coordinate... FeatureCollection\n", "2 {u'geometry': {u'type': u'Point', u'coordinate... FeatureCollection\n", "3 {u'geometry': {u'type': u'Point', u'coordinate... FeatureCollection\n", "4 {u'geometry': {u'type': u'Point', u'coordinate... FeatureCollection" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import json,urllib2\n", "import pandas as pd\n", "\n", "# add a header so that the website doesnt give 403 error\n", "opener = urllib2.build_opener()\n", "opener.addheaders = [('User-agent', 'Mozilla/5.0')]\n", "response = opener.open('https://api.phila.gov/bike-share-stations/v1')\n", "\n", "# parse json using pandas\n", "df = pd.read_json(response)\n", "df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, `df` is a dictionary of dictionaries. We are interested in the features column. Each entry looks like this." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "{u'geometry': {u'coordinates': [-75.16374, 39.95378], u'type': u'Point'},\n", " u'properties': {u'addressCity': u'Philadelphia',\n", " u'addressState': u'PA',\n", " u'addressStreet': u'1401 John F. Kennedy Blvd.',\n", " u'addressZipCode': u'19102',\n", " u'bikesAvailable': 6,\n", " u'closeTime': u'23:58:00',\n", " u'docksAvailable': 19,\n", " u'eventEnd': None,\n", " u'eventStart': None,\n", " u'isEventBased': False,\n", " u'isVirtual': False,\n", " u'kioskId': 3004,\n", " u'kioskPublicStatus': u'Active',\n", " u'name': u'Municipal Services Building Plaza',\n", " u'openTime': u'00:02:00',\n", " u'publicText': u'',\n", " u'timeZone': u'Eastern Standard Time',\n", " u'totalDocks': 25,\n", " u'trikesAvailable': 0},\n", " u'type': u'Feature'}" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df['features'][0]" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "73" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# number of rows (bike stations)\n", "len(df[\"features\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We organize data first before plotting to follow a [Folium example](http://nbviewer.jupyter.org/github/ocefpaf/folium_notebooks/blob/master/test_clustered_markes.ipynb). Basically we need to create a list of tuples with latitude and longtitude. We called it `coordinates`." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[(39.95378, -75.16374), (39.94733, -75.14403), (39.9522, -75.20311), (39.94517, -75.15993), (39.98082, -75.14973), (39.95576, -75.18982), (39.94711, -75.16618), (39.96046, -75.19701), (39.94217, -75.1775), (39.96317, -75.14792)]\n" ] } ], "source": [ "# Organize data\n", "coordinates = []\n", "\n", "for i in range(0,len(df['features'])):\n", " coordinates.append(((df[\"features\"][i][\"geometry\"]['coordinates'])))\n", "\n", "# convert list of lists to list of tuples \n", "coordinates = [tuple([i[1],i[0]]) for i in coordinates] \n", "print(coordinates[0:10])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's visualize the coordinates geoson data using Folium." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import folium\n", "import numpy as np\n", "\n", "#print(folium.__file__)\n", "#print(folium.__version__)\n", "\n", "# get center of map\n", "meanlat = np.mean([i[0] for i in coordinates])\n", "meanlon = np.mean([i[1] for i in coordinates])\n", "\n", "# initialize map\n", "mapa = folium.Map(location=[meanlat, meanlon],\n", " tiles='OpenStreetMap', zoom_start=13)\n", "# add markers\n", "for i in range(0,len(coordinates)):\n", " \n", " # create popup on click\n", " html=\"\"\"\n", " Address: {}
\n", " Bikes available: {}
\n", " Docks: {}
\n", " \"\"\"\n", " html = html.format(df['features'][i]['properties']['addressStreet'],\\\n", " df['features'][i]['properties']['bikesAvailable'],\\\n", " df['features'][i]['properties']['docksAvailable'])\n", " iframe = folium.element.IFrame(html=html, width=150, height=150)\n", " popup = folium.Popup(iframe, max_width=2650)\n", " \n", " # add marker to map\n", " folium.Marker(coordinates[i],\n", " popup=popup,\n", " ).add_to(mapa)\n", "\n", "mapa # show map" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can cluster nearby points. Also, let's look at a different background by changing the tiles argument. List of available tiles can be found in [Folium github repo](https://github.com/python-visualization/folium)." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from folium.plugins import MarkerCluster # for marker clusters\n", "\n", "# initialize map\n", "mapa = folium.Map(location=[meanlat, meanlon],\n", " tiles='Cartodb Positron', zoom_start=13)\n", "\n", "# add marker clusters\n", "mapa.add_children(MarkerCluster(locations=coordinates, popups=coordinates))\n", "mapa" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can utilize Folium plugins to view the geoson data in different ways. For example, let's generate a heat map of the bike stations in Philly. We can see that there are dense areas in center city and Chinatown mostly." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false, "scrolled": false }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from folium.plugins import HeatMap\n", "\n", "# initialize map\n", "mapa = folium.Map(location=[meanlat, meanlon],\n", " tiles='Cartodb Positron', zoom_start=13)\n", "\n", "# add heat\n", "mapa.add_children(HeatMap(coordinates))\n", "mapa" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For more examples go to the Folium's examples [page](https://folium.readthedocs.org/en/latest/examples.html).\n", "\n", "# Resources used\n", "\n", " - [Folium docs](https://folium.readthedocs.org/en/latest/)\n", " - [Folium Github](https://github.com/python-visualization/folium)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.10" } }, "nbformat": 4, "nbformat_minor": 0 }