{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.3.0+196.g7697866.dirty\n" ] } ], "source": [ "import os\n", "import folium\n", "\n", "print(folium.__version__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# GeoJSON and choropleth\n", "\n", "**A few examples of how to do that with `folium`.**\n", "\n", "\n", "## Using `GeoJson`\n", "\n", "\n", "Let us load a GeoJSON file representing the US states." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import json\n", "\n", "us_states = os.path.join('data', 'us-states.json')\n", "\n", "geo_json_data = json.load(open(us_states))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is a classical GeoJSON `FeatureCollection` (see https://en.wikipedia.org/wiki/GeoJSON) of the form :\n", "\n", " {\n", " \"type\": \"FeatureCollection\",\n", " \"features\": [\n", " {\n", " \"properties\": {\"name\": \"Alabama\"},\n", " \"id\": \"AL\",\n", " \"type\": \"Feature\",\n", " \"geometry\": {\n", " \"type\": \"Polygon\",\n", " \"coordinates\": [[[-87.359296, 35.00118], ...]]\n", " }\n", " },\n", " {\n", " \"properties\": {\"name\": \"Alaska\"},\n", " \"id\": \"AK\",\n", " \"type\": \"Feature\",\n", " \"geometry\": {\n", " \"type\": \"MultiPolygon\",\n", " \"coordinates\": [[[[-131.602021, 55.117982], ... ]]]\n", " }\n", " },\n", " ...\n", " ]\n", " }\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A first way of drawing it on a map, is simply to use `folium.GeoJson` :" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = folium.Map([43, -100], zoom_start=4)\n", "\n", "folium.GeoJson(geo_json_data).add_to(m)\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_0.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that you can avoid loading the file on yourself ; in simply providing a file path." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = folium.Map([43, -100], zoom_start=4)\n", "\n", "folium.GeoJson(us_states).add_to(m)\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_1.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can pass a geopandas object." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import geopandas\n", "\n", "gdf = geopandas.read_file(us_states)\n", "\n", "m = folium.Map([43, -100], zoom_start=4)\n", "\n", "folium.GeoJson(\n", " gdf,\n", ").add_to(m)\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_3.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now this is cool and simple, but we may be willing to choose the style of the data.\n", "\n", "You can provide a function of the form `lambda feature: {}` that sets the style of each feature.\n", "\n", "For possible options, see:\n", "\n", "* For `Point` and `MultiPoint`, see http://leafletjs.com/reference.html#marker\n", "* For other features, see http://leafletjs.com/reference.html#path-options and http://leafletjs.com/reference.html#polyline-options\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = folium.Map([43, -100], zoom_start=4)\n", "\n", "folium.GeoJson(\n", " geo_json_data,\n", " style_function=lambda feature: {\n", " 'fillColor': '#ffff00',\n", " 'color': 'black',\n", " 'weight': 2,\n", " 'dashArray': '5, 5'\n", " }\n", ").add_to(m)\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_3.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What's cool in providing a function, is that you can specify a style depending on the feature. For example, if you want to visualize in green all states whose name contains the letter 'E', just do:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = folium.Map([43, -100], zoom_start=4)\n", "\n", "folium.GeoJson(\n", " geo_json_data,\n", " style_function=lambda feature: {\n", " 'fillColor': 'green' if 'e' in feature['properties']['name'].lower() else '#ffff00',\n", " 'color': 'black',\n", " 'weight': 2,\n", " 'dashArray': '5, 5'\n", " }\n", ").add_to(m)\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_4.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wow, this looks almost like a choropleth. To do one, we just need to compute a color for each state.\n", "\n", "Let's imagine we want to draw a choropleth of unemployment in the US.\n", "\n", "First, we may load the data:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "scrolled": true }, "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", "
StateUnemployment
0AL7.1
1AK6.8
2AZ8.1
3AR7.2
4CA10.1
\n", "
" ], "text/plain": [ " State Unemployment\n", "0 AL 7.1\n", "1 AK 6.8\n", "2 AZ 8.1\n", "3 AR 7.2\n", "4 CA 10.1" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "\n", "US_Unemployment_Oct2012 = os.path.join('data', 'US_Unemployment_Oct2012.csv')\n", "unemployment = pd.read_csv(US_Unemployment_Oct2012)\n", "\n", "unemployment.head(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we need to create a function that maps one value to a RGB color (of the form `#RRGGBB`).\n", "For this, we'll use colormap tools from `folium.colormap`." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#c2e798\n" ] }, { "data": { "text/html": [ "3.210.3" ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from branca.colormap import linear\n", "\n", "colormap = linear.YlGn.scale(\n", " unemployment.Unemployment.min(),\n", " unemployment.Unemployment.max())\n", "\n", "print(colormap(5.0))\n", "\n", "colormap" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We need also to convert the table into a dictionnary, in order to map a feature to it's unemployment value." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7.0999999999999996" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "unemployment_dict = unemployment.set_index('State')['Unemployment']\n", "\n", "unemployment_dict['AL']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can do the choropleth." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = folium.Map([43, -100], zoom_start=4)\n", "\n", "folium.GeoJson(\n", " geo_json_data,\n", " name='unemployment',\n", " style_function=lambda feature: {\n", " 'fillColor': colormap(unemployment_dict[feature['id']]),\n", " 'color': 'black',\n", " 'weight': 1,\n", " 'dashArray': '5, 5',\n", " 'fillOpacity': 0.9,\n", " }\n", ").add_to(m)\n", "\n", "folium.LayerControl().add_to(m)\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_5.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course, if you can create and/or use a dictionnary providing directly the good color. Thus, the finishing seems faster:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": true }, "outputs": [], "source": [ "color_dict = {key: colormap(unemployment_dict[key]) for key in unemployment_dict.keys()}" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = folium.Map([43, -100], zoom_start=4)\n", "\n", "folium.GeoJson(\n", " geo_json_data,\n", " style_function=lambda feature: {\n", " 'fillColor': color_dict[feature['id']],\n", " 'color': 'black',\n", " 'weight': 1,\n", " 'dashArray': '5, 5',\n", " 'fillOpacity': 0.9,\n", " }\n", ").add_to(m)\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_6.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that adding a color legend may be a good idea." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "colormap.caption = 'Unemployment color scale'\n", "colormap.add_to(m)\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_7.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Using `choropleth` method\n", "\n", "Now if you want to get faster, you can use the `Map.choropleth` method. Have a look at it's docstring, it has several styling options.\n", "\n", "You can use it in providing a file name (`geo_path`) :" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = folium.Map([43, -100], zoom_start=4)\n", "\n", "m.choropleth(\n", " geo_data=geopandas.read_file(us_states),\n", " fill_color='red',\n", " fill_opacity=0.3,\n", " line_weight=2,\n", ")\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_7.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or in providing a GeoJSON string (`geo_str`) :" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = folium.Map([43, -100], zoom_start=4)\n", "\n", "m.choropleth(geo_data=us_states)\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_8.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then, in playing with keyword arguments, you can get a choropleth in (*almost*) one line :" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = folium.Map([43, -100], zoom_start=4)\n", "\n", "m.choropleth(\n", " geo_data=us_states,\n", " data=unemployment,\n", " columns=['State', 'Unemployment'],\n", " key_on='feature.id',\n", " fill_color='YlGn',\n", ")\n", "\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_9.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A cool thing: you can force the color scale to a given number of bins, in providing a `threshold_scale` argument." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = folium.Map([43, -100], zoom_start=4)\n", "\n", "m.choropleth(\n", " geo_data=us_states,\n", " data=unemployment,\n", " columns=['State', 'Unemployment'],\n", " key_on='feature.id',\n", " fill_color='YlGn',\n", " threshold_scale=[3, 4, 9, 10]\n", ")\n", "\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_10.html'))\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also enable the highlight function, to enable highlight functionality when you hover over each area." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "state_data = pd.read_csv(US_Unemployment_Oct2012)\n", "\n", "m = folium.Map(location=[48, -102], zoom_start=3)\n", "m.choropleth(\n", " geo_data=us_states,\n", " data=state_data,\n", " columns=['State', 'Unemployment'],\n", " key_on='feature.id',\n", " fill_color='YlGn',\n", " fill_opacity=0.7,\n", " line_opacity=0.2,\n", " legend_name='Unemployment Rate (%)',\n", " highlight=True\n", ")\n", "\n", "m.save(os.path.join('results', 'GeoJSON_and_choropleth_11.html'))\n", "\n", "m" ] } ], "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.6.2" } }, "nbformat": 4, "nbformat_minor": 1 }