-
Notifications
You must be signed in to change notification settings - Fork 136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add choropleth support #40
Changes from 1 commit
d3fcd8e
d5a5435
07bf5e5
3a5b3e6
bfd6a04
6b47dbc
79fd36a
360ef08
ac8c100
f1bcd21
9fa3853
b11c006
722d747
cb9972b
07b2ca7
8084c7c
cc147a0
29a3c36
6af2548
d80e99e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Mapboxgl Python Library\n", | ||
"\n", | ||
"https://github.com/mapbox/mapboxgl-jupyter" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import pandas as pd\n", | ||
"import sys\n", | ||
"import os\n", | ||
"\n", | ||
"from mapboxgl.viz import *\n", | ||
"from mapboxgl.utils import *\n", | ||
"from mapboxgl.colors import *\n", | ||
"\n", | ||
"# Must be a public token, starting with `pk`\n", | ||
"token = os.getenv('MAPBOX_ACCESS_TOKEN')\n", | ||
"\n", | ||
"with open('us-states.geojson', 'r') as f:\n", | ||
" data = json.load(f)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## Chloropleths with interpolated color assignment" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"sample_color_stops = [\n", | ||
" [0.0, 'rgb(255,255,204)'],\n", | ||
" [100.0, 'rgb(255,237,160)'],\n", | ||
" [500.0, 'rgb(253,141,60)'],\n", | ||
" [2000.0, 'rgb(227,26,28)'],\n", | ||
" [5000.0, 'rgb(189,0,38)'],\n", | ||
" [10000.0,'rgb(128,0,38)']\n", | ||
"]\n", | ||
" \n", | ||
" \n", | ||
"viz = ChloroplethViz(data, opacity=0.8)\n", | ||
"viz.color_property = 'density'\n", | ||
"viz.color_stops = sample_color_stops\n", | ||
"viz.color_function_type = 'interpolate'\n", | ||
"viz.default_color = '#bada55'\n", | ||
"viz.center = (-96, 37.8)\n", | ||
"viz.zoom = 3\n", | ||
"viz.below_layer = 'waterway-label'\n", | ||
"viz.show()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## Chloropleths with match-type color scheme" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"match_color_stops = [\n", | ||
" ['Massachusetts', 'rgb(46,204,113)'],\n", | ||
" ['Utah', 'rgb(231,76,60)'],\n", | ||
" ['California', 'rgb(142,68,173)'],\n", | ||
"]\n", | ||
" \n", | ||
"viz = ChloroplethViz(data, opacity=0.8)\n", | ||
"viz.color_property = 'name'\n", | ||
"viz.color_stops = match_color_stops\n", | ||
"viz.color_function_type = 'match'\n", | ||
"viz.color_default = 'rgba(52,73,94,0.5)'\n", | ||
"viz.center = (-96, 37.8)\n", | ||
"viz.zoom = 3\n", | ||
"viz.below_layer = 'waterway-label'\n", | ||
"viz.show()" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"anaconda-cloud": { | ||
"attach-environment": true, | ||
"environment": "Root", | ||
"summary": "Mapboxgl Python Data Visualization example" | ||
}, | ||
"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.1" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 1 | ||
} |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
{% extends "main.html" %} | ||
|
||
{% block javascript %} | ||
var legend = document.getElementById('legend'); | ||
|
||
mapboxgl.accessToken = '{{ accessToken }}'; | ||
|
||
var map = new mapboxgl.Map({ | ||
container: 'map', | ||
style: '{{ styleUrl }}', | ||
center: {{ center }}, | ||
zoom: {{ zoom }}, | ||
transformRequest: (url, resourceType)=> { | ||
return { | ||
url: [url.slice(0, url.indexOf("?")+1), "pluginName=PythonMapboxgl&", url.slice(url.indexOf("?")+1)].join('') | ||
} | ||
} | ||
}); | ||
|
||
map.addControl(new mapboxgl.NavigationControl()); | ||
|
||
calcCircleColorLegend({{ colorStops }}, "{{ colorProperty }}"); | ||
|
||
map.on('style.load', function() { | ||
|
||
// Add data source | ||
map.addSource("data", { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the choropleth source is a vector tile? This would be very common when working with Pandas, for example, when you have a tabular set of data that has a geo identifier like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd love to figure out a way to make a |
||
"type": "geojson", | ||
"data": {{ geojson_data }}, | ||
"buffer": 1, | ||
"maxzoom": 14 | ||
}); | ||
|
||
// Add data layer | ||
map.addLayer({ | ||
"id": "polygons", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's make the layer name more descriptive- There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed with d5a5435. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added "chloropleth-label" layer in 3a5b3e6. |
||
"source": "data", | ||
"type": "fill", | ||
"paint": { | ||
"fill-color": generatePropertyExpression("{{ colorType }}", "{{ colorProperty }}", {{ colorStops }}, "{{ defaultColor }}"), | ||
"fill-opacity": {{ opacity }} | ||
} | ||
}, "{{belowLayer}}" ); | ||
|
||
// Create a popup | ||
var popup = new mapboxgl.Popup({ | ||
closeButton: false, | ||
closeOnClick: false | ||
}); | ||
|
||
// Show the popup on mouseover | ||
map.on('mousemove', 'polygons', function(e) { | ||
map.getCanvas().style.cursor = 'pointer'; | ||
|
||
let f = e.features[0]; | ||
let popup_html = '<div>'; | ||
|
||
for (key in f.properties) { | ||
popup_html += '<li><b> ' + key + '</b>: ' + f.properties[key] + ' </li>' | ||
} | ||
|
||
popup_html += '</div>' | ||
popup.setLngLat(e.lngLat) | ||
.setHTML(popup_html) | ||
.addTo(map); | ||
}); | ||
|
||
map.on('mouseleave', 'polygons', function() { | ||
map.getCanvas().style.cursor = ''; | ||
popup.remove(); | ||
}); | ||
|
||
// Fly to on click | ||
map.on('click', 'polygons', function(e) { | ||
map.flyTo({ | ||
center: e.features[0].geometry.coordinates, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @akacarlyann on click for choropleth, we'll want to center the map on the to the mouse pointer click location since the polygon could span a very large area. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed with d5a5435. |
||
zoom: map.getZoom() + 1 | ||
}); | ||
}); | ||
|
||
|
||
}); | ||
{% endblock %} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -268,3 +268,39 @@ def add_unique_template_variables(self, options): | |
clusterRadius=self.clusterRadius, | ||
clusterMaxZoom=self.clusterMaxZoom | ||
)) | ||
|
||
|
||
class ChloroplethViz(MapViz): | ||
"""Create a heatmap viz""" | ||
|
||
def __init__(self, | ||
data, | ||
color_property=None, | ||
color_stops=None, | ||
color_default='grey', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should add support for I recommend handing these options by creating a second There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed with 07bf5e5. |
||
color_function_type='interpolate', | ||
*args, | ||
**kwargs): | ||
"""Construct a Mapviz object | ||
|
||
:param weight_property: property to determine heatmap weight. EX. "population" | ||
|
||
""" | ||
super(ChloroplethViz, self).__init__(data, *args, **kwargs) | ||
|
||
self.template = 'chloropleth' | ||
self.color_property = color_property | ||
self.color_stops = color_stops | ||
self.color_default = color_default | ||
self.color_function_type = color_function_type | ||
|
||
def add_unique_template_variables(self, options): | ||
"""Update map template variables specific to heatmap visual""" | ||
options.update(dict( | ||
geojson_data=json.dumps(self.data, ensure_ascii=False), | ||
colorProperty=self.color_property, | ||
colorType=self.color_function_type, | ||
colorStops=self.color_stops, | ||
defaultColor=self.color_default | ||
)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll want to change this to the latest master branch version that only adds the URL parameter if the request is to a Mapbox API: https://github.com/mapbox/mapboxgl-jupyter/blob/master/mapboxgl/templates/circle.html#L11
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed with 07bf5e5.