Skip to content

Instantly share code, notes, and snippets.

@ljwolf
Created November 19, 2014 04:32
Show Gist options
  • Save ljwolf/61bbfdb70852e4d40aac to your computer and use it in GitHub Desktop.
Save ljwolf/61bbfdb70852e4d40aac to your computer and use it in GitHub Desktop.
folium_notebook
{
"metadata": {
"name": "",
"signature": "sha256:757bae3d1c46461b74ec91af4b14ba7c0b8aa312faf196602171864e35bfed90"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "code",
"collapsed": false,
"input": [
"from IPython.display import HTML\n",
"import folium\n",
"import pysal as ps\n",
"import pandas as pd\n",
"import json as js\n",
"import GeoDaSandboxIO as gsb"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 9
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Simple Mapping"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"to make a map in folium from a json object, it's relatively simple."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"a = folium.Map(location= [33, -84], zoom_start = 7, tiles='Stamen Toner')"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 15
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"a.geo_json(geo_path = './narsc2013_pysal_workshop-master/data/south.json')"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 16
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def inline_map(Map):\n",
" \"\"\"\n",
" Embeds the HTML source of the map directly into the IPython notebook.\n",
" \n",
" This method will not work if the map depends on any files (json data). Also this uses\n",
" the HTML5 srcdoc attribute, which may not be supported in all browsers.\n",
" \"\"\"\n",
" Map._build_map()\n",
" return HTML('<iframe srcdoc=\"{srcdoc}\" style=\"width: 100%; height: 510px; border: none\"></iframe>'.format(srcdoc=Map.HTML.replace('\"', '&quot;')))"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 17
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"inline_map(a)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"<iframe srcdoc=\"<!DOCTYPE html>\n",
"<head>\n",
" <link rel=&quot;stylesheet&quot; href=&quot;http://cdn.leafletjs.com/leaflet-0.5/leaflet.css&quot; />\n",
" <script src=&quot;http://cdn.leafletjs.com/leaflet-0.5/leaflet.js&quot;></script>\n",
" <script src=&quot;http://d3js.org/d3.v3.min.js&quot; charset=&quot;utf-8&quot;></script>\n",
" <script src=&quot;http://d3js.org/queue.v1.min.js&quot;></script>\n",
" \n",
" \n",
" \n",
" \n",
"<style>\n",
"\n",
".legend {\n",
" padding: 0px 0px;\n",
" font: 10px sans-serif;\n",
" background: white;\n",
" background: rgba(255,255,255,0.8);\n",
" box-shadow: 0 0 15px rgba(0,0,0,0.2);\n",
" border-radius: 5px;\n",
"}\n",
"\n",
".key path {\n",
" display: none;\n",
"}\n",
"\n",
"</style>\n",
"</head>\n",
"<body>\n",
"\n",
" <div id=&quot;map&quot; style=&quot;width: 960px; height: 500px&quot;></div>\n",
"\n",
"<script>\n",
"\n",
"queue()\n",
" .defer(d3.json, './narsc2013_pysal_workshop-master/data/south.json')\n",
" .await(makeMap)\n",
"\n",
"function makeMap(error, gjson_1) {\n",
"\n",
" \n",
"\n",
" \n",
"\n",
" function matchKey(datapoint, key_variable){\n",
" return(parseFloat(key_variable[0][datapoint]));\n",
" };\n",
"\n",
" \n",
"\n",
" var map = L.map('map').setView([33, -84], 7);\n",
"\n",
" L.tileLayer('http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.jpg', {\n",
" maxZoom: 18,\n",
" attribution: 'Map tiles by <a href=&quot;http://stamen.com&quot;>Stamen Design</a>, under <a href=&quot;http://creativecommons.org/licenses/by/3.0&quot;>CC BY 3.0</a>. Data by <a href=&quot;http://openstreetmap.org&quot;>OpenStreetMap</a>, under <a href=&quot;http://creativecommons.org/licenses/by-sa/3.0&quot;>CC BY SA</a>.'\n",
" }).addTo(map);\n",
"\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"\n",
" \n",
" function style_1(feature) {\n",
" return {\n",
" fillColor: 'blue',\n",
" weight: 1,\n",
" opacity: 1,\n",
" color: 'black',\n",
" fillOpacity: 0.6\n",
" };\n",
"}\n",
" \n",
"\n",
" \n",
" gJson_layer_1 = L.geoJson(gjson_1, {style: style_1}).addTo(map)\n",
" \n",
"\n",
" \n",
"\n",
"};\n",
"\n",
"</script>\n",
"\n",
"</body>\" style=\"width: 100%; height: 510px; border: none\"></iframe>"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 18,
"text": [
"<IPython.core.display.HTML at 0x7fef419ee410>"
]
}
],
"prompt_number": 18
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Choropleth Mapping"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To do the choropleth mapping, let's make a function that makes a pandas dataframe from a serialized json object!"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def json2df(jsonobj, index_on = ''):\n",
" n = len(jsonobj['features'])\n",
" rows = [ jsonobj['features'][i]['properties'] for i in range(n) ]\n",
" try:\n",
" idxs = [ jsonobj['features'][i]['properties'][index_on] for i in range(n) ] \n",
" result = pd.DataFrame(rows, index=idxs ) \n",
" except KeyError:\n",
" result = pd.DataFrame(rows)\n",
" return result"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 14
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We need this because folium currently binds on IDs between the json object and the pandas dataframe. It'd be nice if folium could just read straight from the json object, but there are a lot of things that aren't nice."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"sou_df = json2df(js.load(open('./narsc2013_pysal_workshop-master/data/south.json')))"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 21
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"sou_df.head()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"<div style=\"max-height:1000px;max-width:1500px;overflow:auto;\">\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>BLK60</th>\n",
" <th>BLK70</th>\n",
" <th>BLK80</th>\n",
" <th>BLK90</th>\n",
" <th>CNTY_FIPS</th>\n",
" <th>COFIPS</th>\n",
" <th>DNL60</th>\n",
" <th>DNL70</th>\n",
" <th>DNL80</th>\n",
" <th>DNL90</th>\n",
" <th>...</th>\n",
" <th>RD80</th>\n",
" <th>RD90</th>\n",
" <th>SOUTH</th>\n",
" <th>STATE_FIPS</th>\n",
" <th>STATE_NAME</th>\n",
" <th>STFIPS</th>\n",
" <th>UE60</th>\n",
" <th>UE70</th>\n",
" <th>UE80</th>\n",
" <th>UE90</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td> 3.839455</td>\n",
" <td> 3.255428</td>\n",
" <td> 2.560740</td>\n",
" <td> 2.557262</td>\n",
" <td> 029</td>\n",
" <td> 29</td>\n",
" <td> 6.168123</td>\n",
" <td> 6.171499</td>\n",
" <td> 6.171463</td>\n",
" <td> 6.050898</td>\n",
" <td>...</td>\n",
" <td>-1.159302</td>\n",
" <td>-0.399028</td>\n",
" <td> 1</td>\n",
" <td> 54</td>\n",
" <td> West Virginia</td>\n",
" <td> 54</td>\n",
" <td> 3.1</td>\n",
" <td> 2.7</td>\n",
" <td> 7.076383</td>\n",
" <td> 6.857807</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td> 1.416724</td>\n",
" <td> 0.824492</td>\n",
" <td> 0.796992</td>\n",
" <td> 0.748370</td>\n",
" <td> 009</td>\n",
" <td> 9</td>\n",
" <td> 5.795643</td>\n",
" <td> 5.846275</td>\n",
" <td> 5.845700</td>\n",
" <td> 5.715784</td>\n",
" <td>...</td>\n",
" <td>-1.249504</td>\n",
" <td>-0.663597</td>\n",
" <td> 1</td>\n",
" <td> 54</td>\n",
" <td> West Virginia</td>\n",
" <td> 54</td>\n",
" <td> 4.8</td>\n",
" <td> 3.4</td>\n",
" <td> 6.034825</td>\n",
" <td> 6.965984</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td> 3.052442</td>\n",
" <td> 3.143177</td>\n",
" <td> 3.463161</td>\n",
" <td> 3.310334</td>\n",
" <td> 069</td>\n",
" <td> 69</td>\n",
" <td> 6.470230</td>\n",
" <td> 6.394395</td>\n",
" <td> 6.364381</td>\n",
" <td> 6.171724</td>\n",
" <td>...</td>\n",
" <td>-0.169404</td>\n",
" <td> 0.136307</td>\n",
" <td> 1</td>\n",
" <td> 54</td>\n",
" <td> West Virginia</td>\n",
" <td> 54</td>\n",
" <td> 7.3</td>\n",
" <td> 3.7</td>\n",
" <td> 5.888027</td>\n",
" <td> 6.932197</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td> 0.946347</td>\n",
" <td> 0.601096</td>\n",
" <td> 0.593636</td>\n",
" <td> 0.546097</td>\n",
" <td> 051</td>\n",
" <td> 51</td>\n",
" <td> 4.829392</td>\n",
" <td> 4.817678</td>\n",
" <td> 4.915080</td>\n",
" <td> 4.801401</td>\n",
" <td>...</td>\n",
" <td>-1.075157</td>\n",
" <td>-0.053528</td>\n",
" <td> 1</td>\n",
" <td> 54</td>\n",
" <td> West Virginia</td>\n",
" <td> 54</td>\n",
" <td> 11.0</td>\n",
" <td> 4.8</td>\n",
" <td> 11.643181</td>\n",
" <td> 8.772939</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td> 11.722059</td>\n",
" <td> 12.665087</td>\n",
" <td> 15.100160</td>\n",
" <td> 16.480294</td>\n",
" <td> 003</td>\n",
" <td> 3</td>\n",
" <td> 6.551555</td>\n",
" <td> 6.781001</td>\n",
" <td> 6.913840</td>\n",
" <td> 6.943800</td>\n",
" <td>...</td>\n",
" <td>-0.301462</td>\n",
" <td>-0.887616</td>\n",
" <td> 1</td>\n",
" <td> 10</td>\n",
" <td> Delaware</td>\n",
" <td> 10</td>\n",
" <td> 4.7</td>\n",
" <td> 3.9</td>\n",
" <td> 5.951244</td>\n",
" <td> 3.819758</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>5 rows \u00d7 69 columns</p>\n",
"</div>"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 22,
"text": [
" BLK60 BLK70 BLK80 BLK90 CNTY_FIPS COFIPS DNL60 \\\n",
"0 3.839455 3.255428 2.560740 2.557262 029 29 6.168123 \n",
"1 1.416724 0.824492 0.796992 0.748370 009 9 5.795643 \n",
"2 3.052442 3.143177 3.463161 3.310334 069 69 6.470230 \n",
"3 0.946347 0.601096 0.593636 0.546097 051 51 4.829392 \n",
"4 11.722059 12.665087 15.100160 16.480294 003 3 6.551555 \n",
"\n",
" DNL70 DNL80 DNL90 ... RD80 RD90 SOUTH \\\n",
"0 6.171499 6.171463 6.050898 ... -1.159302 -0.399028 1 \n",
"1 5.846275 5.845700 5.715784 ... -1.249504 -0.663597 1 \n",
"2 6.394395 6.364381 6.171724 ... -0.169404 0.136307 1 \n",
"3 4.817678 4.915080 4.801401 ... -1.075157 -0.053528 1 \n",
"4 6.781001 6.913840 6.943800 ... -0.301462 -0.887616 1 \n",
"\n",
" STATE_FIPS STATE_NAME STFIPS UE60 UE70 UE80 UE90 \n",
"0 54 West Virginia 54 3.1 2.7 7.076383 6.857807 \n",
"1 54 West Virginia 54 4.8 3.4 6.034825 6.965984 \n",
"2 54 West Virginia 54 7.3 3.7 5.888027 6.932197 \n",
"3 54 West Virginia 54 11.0 4.8 11.643181 8.772939 \n",
"4 10 Delaware 10 4.7 3.9 5.951244 3.819758 \n",
"\n",
"[5 rows x 69 columns]"
]
}
],
"prompt_number": 22
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then, just like before, we start the map at the correct location and zoom level. Leaflet has a function to do this from a bounding box, but it looks like that's yet another thing that's not in Folium."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"b = folium.Map(location=[33, -84], zoom_start=7)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 23
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then, there's this WHOLE grip of arguments you have to pass. I'll break it down.\n",
"\n",
"- `geo_path`: the filepath of the geojson file you want to map\n",
"- `key_on`: the key for the json object. NOTICE that it's already incorporated the GeoJSON hierarchy of 'feature' then 'property'. \n",
"- `data`: this is a pandas dataframe currently in memory. \n",
"- `columns`: the two columns needed for pandas. The first should be the ID and the second should be what you want to map. \n",
"- All the rest of the stuff are arguments controlling the aesthetics of the map and they're pretty self-explanatory. "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"b.geo_json(geo_path='narsc2013_pysal_workshop-master/data/south.json',\n",
" key_on='feature.properties.FIPS',\n",
" data=sou_df,\n",
" columns=['FIPS','HR80'],\n",
" fill_color='YlGn', fill_opacity=0.7,\n",
" line_opacity=0.2,\n",
" legend_name='Homicide Rate')\n",
"b.create_map('adsf.html')"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 26
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"inline_map(b)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"<iframe srcdoc=\"<!DOCTYPE html>\n",
"<head>\n",
" <link rel=&quot;stylesheet&quot; href=&quot;http://cdn.leafletjs.com/leaflet-0.5/leaflet.css&quot; />\n",
" <script src=&quot;http://cdn.leafletjs.com/leaflet-0.5/leaflet.js&quot;></script>\n",
" <script src=&quot;http://d3js.org/d3.v3.min.js&quot; charset=&quot;utf-8&quot;></script>\n",
" <script src=&quot;http://d3js.org/queue.v1.min.js&quot;></script>\n",
" \n",
" \n",
" \n",
" \n",
"<style>\n",
"\n",
".legend {\n",
" padding: 0px 0px;\n",
" font: 10px sans-serif;\n",
" background: white;\n",
" background: rgba(255,255,255,0.8);\n",
" box-shadow: 0 0 15px rgba(0,0,0,0.2);\n",
" border-radius: 5px;\n",
"}\n",
"\n",
".key path {\n",
" display: none;\n",
"}\n",
"\n",
"</style>\n",
"</head>\n",
"<body>\n",
"\n",
" <div id=&quot;map&quot; style=&quot;width: 960px; height: 500px&quot;></div>\n",
"\n",
"<script>\n",
"\n",
"queue()\n",
" .defer(d3.json, 'data.json')\n",
" .defer(d3.json, 'narsc2013_pysal_workshop-master/data/south.json')\n",
" .defer(d3.json, 'data.json')\n",
" .defer(d3.json, 'narsc2013_pysal_workshop-master/data/south.json')\n",
" .await(makeMap)\n",
"\n",
"function makeMap(error, data_1,gjson_1,data_2,gjson_2) {\n",
"\n",
" \n",
"\n",
" \n",
"\n",
" function matchKey(datapoint, key_variable){\n",
" return(parseFloat(key_variable[0][datapoint]));\n",
" };\n",
"\n",
" \n",
" var color = d3.scale.threshold()\n",
" .domain([0, 9.0, 10.0, 20.0, 20.0])\n",
" .range(['#FFFFCC', '#D9F0A3', '#ADDD8E', '#78C679', '#41AB5D', '#238443']);\n",
" \n",
" var color = d3.scale.threshold()\n",
" .domain([0, 9.0, 10.0, 20.0, 20.0])\n",
" .range(['#FFFFCC', '#D9F0A3', '#ADDD8E', '#78C679', '#41AB5D', '#238443']);\n",
" \n",
"\n",
" var map = L.map('map').setView([33, -84], 7);\n",
"\n",
" L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {\n",
" maxZoom: 18,\n",
" attribution: 'Map data (c) <a href=&quot;http://openstreetmap.org&quot;>OpenStreetMap</a> contributors'\n",
" }).addTo(map);\n",
"\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"\n",
" \n",
" function style_1(feature) {\n",
" return {\n",
" fillColor: color(matchKey(feature.properties.FIPS, data_1)),\n",
" weight: 1,\n",
" opacity: 0.2,\n",
" color: 'black',\n",
" fillOpacity: 0.7\n",
" };\n",
"}\n",
" \n",
" function style_2(feature) {\n",
" return {\n",
" fillColor: color(matchKey(feature.properties.FIPS, data_2)),\n",
" weight: 1,\n",
" opacity: 0.2,\n",
" color: 'black',\n",
" fillOpacity: 0.7\n",
" };\n",
"}\n",
" \n",
"\n",
" \n",
" gJson_layer_1 = L.geoJson(gjson_1, {style: style_1}).addTo(map)\n",
" \n",
" gJson_layer_2 = L.geoJson(gjson_2, {style: style_2}).addTo(map)\n",
" \n",
"\n",
" \n",
" var legend = L.control({position: 'topright'});\n",
"\n",
" legend.onAdd = function (map) {var div = L.DomUtil.create('div', 'legend'); return div};\n",
"\n",
" legend.addTo(map);\n",
"\n",
" var x = d3.scale.linear()\n",
" .domain([0, 22])\n",
" .range([0, 400]);\n",
"\n",
" var xAxis = d3.svg.axis()\n",
" .scale(x)\n",
" .orient(&quot;top&quot;)\n",
" .tickSize(1)\n",
" .tickValues(color.domain())\n",
"\n",
" var svg = d3.select(&quot;.legend.leaflet-control&quot;).append(&quot;svg&quot;)\n",
" .attr(&quot;id&quot;, 'legend')\n",
" .attr(&quot;width&quot;, 450)\n",
" .attr(&quot;height&quot;, 40);\n",
"\n",
" var g = svg.append(&quot;g&quot;)\n",
" .attr(&quot;class&quot;, &quot;key&quot;)\n",
" .attr(&quot;transform&quot;, &quot;translate(25,16)&quot;);\n",
"\n",
" g.selectAll(&quot;rect&quot;)\n",
" .data(color.range().map(function(d, i) {\n",
" return {\n",
" x0: i ? x(color.domain()[i - 1]) : x.range()[0],\n",
" x1: i < color.domain().length ? x(color.domain()[i]) : x.range()[1],\n",
" z: d\n",
" };\n",
" }))\n",
" .enter().append(&quot;rect&quot;)\n",
" .attr(&quot;height&quot;, 10)\n",
" .attr(&quot;x&quot;, function(d) { return d.x0; })\n",
" .attr(&quot;width&quot;, function(d) { return d.x1 - d.x0; })\n",
" .style(&quot;fill&quot;, function(d) { return d.z; });\n",
"\n",
" g.call(xAxis).append(&quot;text&quot;)\n",
" .attr(&quot;class&quot;, &quot;caption&quot;)\n",
" .attr(&quot;y&quot;, 21)\n",
" .text('asdf');\n",
" \n",
" var legend = L.control({position: 'topright'});\n",
"\n",
" legend.onAdd = function (map) {var div = L.DomUtil.create('div', 'legend'); return div};\n",
"\n",
" legend.addTo(map);\n",
"\n",
" var x = d3.scale.linear()\n",
" .domain([0, 22])\n",
" .range([0, 400]);\n",
"\n",
" var xAxis = d3.svg.axis()\n",
" .scale(x)\n",
" .orient(&quot;top&quot;)\n",
" .tickSize(1)\n",
" .tickValues(color.domain())\n",
"\n",
" var svg = d3.select(&quot;.legend.leaflet-control&quot;).append(&quot;svg&quot;)\n",
" .attr(&quot;id&quot;, 'legend')\n",
" .attr(&quot;width&quot;, 450)\n",
" .attr(&quot;height&quot;, 40);\n",
"\n",
" var g = svg.append(&quot;g&quot;)\n",
" .attr(&quot;class&quot;, &quot;key&quot;)\n",
" .attr(&quot;transform&quot;, &quot;translate(25,16)&quot;);\n",
"\n",
" g.selectAll(&quot;rect&quot;)\n",
" .data(color.range().map(function(d, i) {\n",
" return {\n",
" x0: i ? x(color.domain()[i - 1]) : x.range()[0],\n",
" x1: i < color.domain().length ? x(color.domain()[i]) : x.range()[1],\n",
" z: d\n",
" };\n",
" }))\n",
" .enter().append(&quot;rect&quot;)\n",
" .attr(&quot;height&quot;, 10)\n",
" .attr(&quot;x&quot;, function(d) { return d.x0; })\n",
" .attr(&quot;width&quot;, function(d) { return d.x1 - d.x0; })\n",
" .style(&quot;fill&quot;, function(d) { return d.z; });\n",
"\n",
" g.call(xAxis).append(&quot;text&quot;)\n",
" .attr(&quot;class&quot;, &quot;caption&quot;)\n",
" .attr(&quot;y&quot;, 21)\n",
" .text('Homicide Rate');\n",
" \n",
"\n",
"};\n",
"\n",
"</script>\n",
"\n",
"</body>\" style=\"width: 100%; height: 510px; border: none\"></iframe>"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 27,
"text": [
"<IPython.core.display.HTML at 0x7fef40db5cd0>"
]
}
],
"prompt_number": 27
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And you see now that the map will show up!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But, this isn't good enough. We talked about making this process more simple. I figured the simplest we could make this is a three-argument function:\n",
"\n",
"1. `jsonpath`: the json file we want to map\n",
"2. `key`: the key of the dataset\n",
"3. `attribute`: the attribute we want to map\n",
"\n",
"The rest of the arguments are set to sane defaults, except for `centroid` and `zoom_start`. Centroid measures the location of the center of the map and, unless this information is contained within the GeoJSON file, it's annoying to get out. We also talked about calculating this in class, but no one has implemented this function yet. `zoom_start` would be another thing we could set if we had the bounding box by determining the relationship between the `zoom_level` integers and a bounding box of the shape. This is another thing that could be a contribution. \n",
"\n",
"All the rest of the arguments are aesthetics arguments or govern whether or not to save the output. "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def choropleth_map(jsonpath, key, attribute, std = None,\n",
" centroid = [0,0], zoom_start = 5, tiles = 'OpenStreetMap',\n",
" fill_color = \"YlGn\", fill_opacity = .5, \n",
" line_opacity = 0.2, legend_name = '', \n",
" save = False):\n",
" \n",
" choromap = folium.Map(location = centroid, zoom_start = zoom_start, tiles=tiles)\n",
" \n",
" sjson = js.load(open(jsonpath))\n",
" \n",
" #if 'bbox' in sjson.keys() and centroid == [0,0]:\n",
" # bbox = sjson.get('bbox')\n",
" # meanLong = (bbox[0] + bbox[2]) * .5\n",
" # meanLat = (bbox[1] + bbox[3]) * .5\n",
" # centroid = [meanLong, meanLat]\n",
" \n",
" df = json2df(sjson)\n",
" dfkey = [key, attribute]\n",
" \n",
" jsonkey = 'feature.properties.' + key\n",
" \n",
" if std != None:\n",
" if isinstance(std, int) or isinstance(std, float):\n",
" attribute = df[attribute]/std\n",
" elif type(std) == str:\n",
" attribute = df[attribute]/df[std]\n",
" elif callable(std):\n",
" raise NotImplementedError('Functional Standardizations are not implemented yet')\n",
" else:\n",
" raise ValueError('Standardization must be integer, float, function, or Series')\n",
" \n",
" choromap.geo_json(geo_path=jsonpath, key_on = jsonkey, \n",
" data = df, columns = dfkey, \n",
" fill_color = fill_color, fill_opacity = fill_opacity,\n",
" line_opacity = line_opacity, legend_name = legend_name\n",
" )\n",
" if save:\n",
" fname = jsonpath.rstrip('.json') + '_' + attribute + '.html'\n",
" choromap.create_map(fname)\n",
" \n",
" return inline_map(choromap)\n",
" \n",
" "
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 28
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So, this three-argument function will map a choropleth map straight from a json file with a minimal amount of hassle."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"choropleth_map('./narsc2013_pysal_workshop-master/data/south.json', 'FIPS', 'HR80', centroid=[33, -84])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"<iframe srcdoc=\"<!DOCTYPE html>\n",
"<head>\n",
" <link rel=&quot;stylesheet&quot; href=&quot;http://cdn.leafletjs.com/leaflet-0.5/leaflet.css&quot; />\n",
" <script src=&quot;http://cdn.leafletjs.com/leaflet-0.5/leaflet.js&quot;></script>\n",
" <script src=&quot;http://d3js.org/d3.v3.min.js&quot; charset=&quot;utf-8&quot;></script>\n",
" <script src=&quot;http://d3js.org/queue.v1.min.js&quot;></script>\n",
" \n",
" \n",
" \n",
" \n",
"<style>\n",
"\n",
".legend {\n",
" padding: 0px 0px;\n",
" font: 10px sans-serif;\n",
" background: white;\n",
" background: rgba(255,255,255,0.8);\n",
" box-shadow: 0 0 15px rgba(0,0,0,0.2);\n",
" border-radius: 5px;\n",
"}\n",
"\n",
".key path {\n",
" display: none;\n",
"}\n",
"\n",
"</style>\n",
"</head>\n",
"<body>\n",
"\n",
" <div id=&quot;map&quot; style=&quot;width: 960px; height: 500px&quot;></div>\n",
"\n",
"<script>\n",
"\n",
"queue()\n",
" .defer(d3.json, 'data.json')\n",
" .defer(d3.json, './narsc2013_pysal_workshop-master/data/south.json')\n",
" .await(makeMap)\n",
"\n",
"function makeMap(error, data_1,gjson_1) {\n",
"\n",
" \n",
"\n",
" \n",
"\n",
" function matchKey(datapoint, key_variable){\n",
" return(parseFloat(key_variable[0][datapoint]));\n",
" };\n",
"\n",
" \n",
" var color = d3.scale.threshold()\n",
" .domain([0, 9.0, 10.0, 20.0, 20.0])\n",
" .range(['#FFFFCC', '#D9F0A3', '#ADDD8E', '#78C679', '#41AB5D', '#238443']);\n",
" \n",
"\n",
" var map = L.map('map').setView([33, -84], 5);\n",
"\n",
" L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {\n",
" maxZoom: 18,\n",
" attribution: 'Map data (c) <a href=&quot;http://openstreetmap.org&quot;>OpenStreetMap</a> contributors'\n",
" }).addTo(map);\n",
"\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"\n",
" \n",
" function style_1(feature) {\n",
" return {\n",
" fillColor: color(matchKey(feature.properties.FIPS, data_1)),\n",
" weight: 1,\n",
" opacity: 0.2,\n",
" color: 'black',\n",
" fillOpacity: 0.5\n",
" };\n",
"}\n",
" \n",
"\n",
" \n",
" gJson_layer_1 = L.geoJson(gjson_1, {style: style_1}).addTo(map)\n",
" \n",
"\n",
" \n",
" var legend = L.control({position: 'topright'});\n",
"\n",
" legend.onAdd = function (map) {var div = L.DomUtil.create('div', 'legend'); return div};\n",
"\n",
" legend.addTo(map);\n",
"\n",
" var x = d3.scale.linear()\n",
" .domain([0, 22])\n",
" .range([0, 400]);\n",
"\n",
" var xAxis = d3.svg.axis()\n",
" .scale(x)\n",
" .orient(&quot;top&quot;)\n",
" .tickSize(1)\n",
" .tickValues(color.domain())\n",
"\n",
" var svg = d3.select(&quot;.legend.leaflet-control&quot;).append(&quot;svg&quot;)\n",
" .attr(&quot;id&quot;, 'legend')\n",
" .attr(&quot;width&quot;, 450)\n",
" .attr(&quot;height&quot;, 40);\n",
"\n",
" var g = svg.append(&quot;g&quot;)\n",
" .attr(&quot;class&quot;, &quot;key&quot;)\n",
" .attr(&quot;transform&quot;, &quot;translate(25,16)&quot;);\n",
"\n",
" g.selectAll(&quot;rect&quot;)\n",
" .data(color.range().map(function(d, i) {\n",
" return {\n",
" x0: i ? x(color.domain()[i - 1]) : x.range()[0],\n",
" x1: i < color.domain().length ? x(color.domain()[i]) : x.range()[1],\n",
" z: d\n",
" };\n",
" }))\n",
" .enter().append(&quot;rect&quot;)\n",
" .attr(&quot;height&quot;, 10)\n",
" .attr(&quot;x&quot;, function(d) { return d.x0; })\n",
" .attr(&quot;width&quot;, function(d) { return d.x1 - d.x0; })\n",
" .style(&quot;fill&quot;, function(d) { return d.z; });\n",
"\n",
" g.call(xAxis).append(&quot;text&quot;)\n",
" .attr(&quot;class&quot;, &quot;caption&quot;)\n",
" .attr(&quot;y&quot;, 21)\n",
" .text('HR80');\n",
" \n",
"\n",
"};\n",
"\n",
"</script>\n",
"\n",
"</body>\" style=\"width: 100%; height: 510px; border: none\"></iframe>"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 29,
"text": [
"<IPython.core.display.HTML at 0x7fef417e33d0>"
]
}
],
"prompt_number": 29
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"To Do:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- figure out bounding box calculation from json (or pysal)\n",
"- work out why leaflet won't map some GeoJSON files (like made by jsonify vs. ogr2ogr)\n",
"- integrate pysal map classifiers into this scheme\n",
"- integrate vincent visualizations\n",
"- integrate mouseovers"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment