Skip to content
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

Merged
merged 20 commits into from
Mar 29, 2018
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d3fcd8e
Add basic chloropleth support
Feb 3, 2018
d5a5435
Center zoom on click coordinates; rename polygons layer to 'cholorple…
Feb 19, 2018
07bf5e5
Add line_color, line_stroke, and line_width properties to Chloropleth…
Feb 20, 2018
3a5b3e6
Add chloropleth label layer; add template block for styling legend keys
Feb 20, 2018
bfd6a04
Add line styling to example chloropleth notebook
Feb 27, 2018
6b47dbc
Merge branch 'master' into chloropleth-support
Feb 27, 2018
79fd36a
Update internal documentation in ChloroplethViz class; add chloroplet…
Feb 27, 2018
360ef08
Update spelling to mapbox standard: 'choropleth'
Feb 28, 2018
ac8c100
Add tests for ChoroplethViz (currently uses polygons.geojson)
Feb 28, 2018
f1bcd21
Formatting and headers on choropleth notebook
Mar 2, 2018
9fa3853
Add vector layer support options; requesting direction for reconcilin…
Mar 6, 2018
b11c006
Single ChoroplethViz class defines either vector-based or geojson-bas…
Mar 17, 2018
722d747
Add support for categorical data-driven styling with vector data-join…
Mar 23, 2018
cb9972b
Merge branch 'master' into chloropleth-support; update styleUrl to st…
Mar 23, 2018
07b2ca7
Attempt to add test for utils.rgb_tuple_from_str
Mar 23, 2018
8084c7c
Merge branch 'master' into chloropleth-support
ryanbaumann Mar 27, 2018
cc147a0
Additional test coverage for ChoroplethViz and color_map, rgb_tuple_f…
Mar 29, 2018
29a3c36
Per @ryanbaumann 's comments: revert color data-join style to the old…
Mar 29, 2018
6af2548
Test fix
Mar 29, 2018
d80e99e
Minor refactor to color_map to prioritize returning exact match color…
Mar 29, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions docs-markdown/viz.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,61 @@ viz = HeatmapViz('points.geojson',
viz.show()
```
![screen shot 2018-02-21 at 3 34 55 pm](https://user-images.githubusercontent.com/11286381/36511775-cfc4d794-171c-11e8-86b9-5f1a6060a387.png)


## class ChoroplethViz

The `ChoroplethViz` object handles the creation of a choropleth map and inherits from the `MapViz` class. It applies a thematic map style to polygon features with color shading in proportion to the intensity of the data being displayed.

### Params
**ChoroplethViz**(_data, label_property=None, color_property=None, color_stops=None, color_default='grey', color_function_type='interpolate', line_color='white', line_stroke='solid', line_width=1, *args, **kwargs_)

Parameter | Description | Example
--|--|--
data | GeoJson file name or object
label_property | property to use for marker label | "density"
color_property | property to determine fill color | "density"
color_stops | property to determine fill color | [[0, "red"], [0.5, "blue"], [1, "green"]]
color_default | property to determine default fill color in match lookups | "#F0F0F0"
color_function_type | property to determine type of expression used by Mapbox to assign color | "interpolate"
line_color | property to determine choropleth border line color | "#FFFFFF"
line_stroke | property to determine choropleth border line stroke (one of solid, dashed, dotted, dash dot) | "solid"
line_width | property to determine choropleth border line width | 1

[View options](https://github.com/mapbox/mapboxgl-jupyter/blob/master/docs-markdown/viz.md#params)

### Usage
```python
import os
from mapboxgl.viz import *

# Must be a public token, starting with `pk`
token = os.getenv('MAPBOX_ACCESS_TOKEN')

# Color stops
color_stops = [
[0.0, 'rgb(255,255,204)'],
[50.0, 'rgb(255,237,160)'],
[100.0, 'rgb(253,141,60)'],
[500.0, 'rgb(227,26,28)'],
[2500.0, 'rgb(189,0,38)'],
[5000.0, 'rgb(128,0,38)']
]

# Create Choropleth
viz = ChoroplethViz('us-states.geojson',
access_token=token,
color_property='density',
color_stops=color_stops,
color_function_type='interpolate',
line_stroke='dashed',
line_color='rgb(128,0,38)',
line_width=1,
opacity=0.8,
center=(-96, 37.8),
zoom=3,
below_layer='waterway-label
)
viz.show()
```
![screen shot 2018-02-26 at 4 54 59 pm](https://user-images.githubusercontent.com/13527707/36704653-186bb2e0-1b16-11e8-9dac-2d929e678be9.png)
153 changes: 153 additions & 0 deletions examples/choropleth-viz-example.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
{
"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 os\n",
"from mapboxgl.viz import *\n",
"from mapboxgl.utils import *\n",
"\n",
"# Must be a public token, starting with `pk`\n",
"token = os.getenv('MAPBOX_ACCESS_TOKEN')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Choropleths with interpolated color assignment from GeoJSON source"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"viz = ChoroplethViz('us-states.geojson', \n",
" color_property='density',\n",
" color_stops=create_color_stops([0, 50, 100, 500, 1500], colors='YlOrRd'),\n",
" color_function_type='interpolate',\n",
" line_stroke='--',\n",
" line_color='rgb(128,0,38)',\n",
" line_width=1,\n",
" opacity=0.8,\n",
" center=(-96, 37.8),\n",
" zoom=3,\n",
" below_layer='waterway-label'\n",
" )\n",
"viz.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Choropleths with match-type color scheme from GeoJSON source"
]
},
{
"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 = ChoroplethViz('us-states.geojson', \n",
" color_property='name', \n",
" color_stops = match_color_stops, \n",
" color_function_type = 'match', \n",
" color_default = 'rgba(52,73,94,0.5)', \n",
" opacity=0.8, \n",
" center = (-96, 37.8), \n",
" zoom = 3, \n",
" below_layer = 'waterway-label'\n",
" )\n",
"viz.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Vector polygon source with data-join technique"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"from mapboxgl.viz import *\n",
"\n",
"# Must be a public token, starting with `pk`\n",
"token = os.getenv('MAPBOX_ACCESS_TOKEN')\n",
"\n",
"# must be json object (need to extend to use referenced json file)\n",
"data = [{\"id\": \"01\", \"name\": \"Alabama\", \"density\": 94.65}, {\"id\": \"02\", \"name\": \"Alaska\", \"density\": 1.264}, {\"id\": \"04\", \"name\": \"Arizona\", \"density\": 57.05}, {\"id\": \"05\", \"name\": \"Arkansas\", \"density\": 56.43}, {\"id\": \"06\", \"name\": \"California\", \"density\": 241.7}, {\"id\": \"08\", \"name\": \"Colorado\", \"density\": 49.33}, {\"id\": \"09\", \"name\": \"Connecticut\", \"density\": 739.1}, {\"id\": \"10\", \"name\": \"Delaware\", \"density\": 464.3}, {\"id\": \"11\", \"name\": \"District of Columbia\", \"density\": 10065}, {\"id\": \"12\", \"name\": \"Florida\", \"density\": 353.4}, {\"id\": \"13\", \"name\": \"Georgia\", \"density\": 169.5}, {\"id\": \"15\", \"name\": \"Hawaii\", \"density\": 214.1}, {\"id\": \"16\", \"name\": \"Idaho\", \"density\": 19.15}, {\"id\": \"17\", \"name\": \"Illinois\", \"density\": 231.5}, {\"id\": \"18\", \"name\": \"Indiana\", \"density\": 181.7}, {\"id\": \"19\", \"name\": \"Iowa\", \"density\": 54.81}, {\"id\": \"20\", \"name\": \"Kansas\", \"density\": 35.09}, {\"id\": \"21\", \"name\": \"Kentucky\", \"density\": 110}, {\"id\": \"22\", \"name\": \"Louisiana\", \"density\": 105}, {\"id\": \"23\", \"name\": \"Maine\", \"density\": 43.04}, {\"id\": \"24\", \"name\": \"Maryland\", \"density\": 596.3}, {\"id\": \"25\", \"name\": \"Massachusetts\", \"density\": 840.2}, {\"id\": \"26\", \"name\": \"Michigan\", \"density\": 173.9}, {\"id\": \"27\", \"name\": \"Minnesota\", \"density\": 67.14}, {\"id\": \"28\", \"name\": \"Mississippi\", \"density\": 63.5}, {\"id\": \"29\", \"name\": \"Missouri\", \"density\": 87.26}, {\"id\": \"30\", \"name\": \"Montana\", \"density\": 6.858}, {\"id\": \"31\", \"name\": \"Nebraska\", \"density\": 23.97}, {\"id\": \"32\", \"name\": \"Nevada\", \"density\": 24.8}, {\"id\": \"33\", \"name\": \"New Hampshire\", \"density\": 147}, {\"id\": \"34\", \"name\": \"New Jersey\", \"density\": 1189}, {\"id\": \"35\", \"name\": \"New Mexico\", \"density\": 17.16}, {\"id\": \"36\", \"name\": \"New York\", \"density\": 412.3}, {\"id\": \"37\", \"name\": \"North Carolina\", \"density\": 198.2}, {\"id\": \"38\", \"name\": \"North Dakota\", \"density\": 9.916}, {\"id\": \"39\", \"name\": \"Ohio\", \"density\": 281.9}, {\"id\": \"40\", \"name\": \"Oklahoma\", \"density\": 55.22}, {\"id\": \"41\", \"name\": \"Oregon\", \"density\": 40.33}, {\"id\": \"42\", \"name\": \"Pennsylvania\", \"density\": 284.3}, {\"id\": \"44\", \"name\": \"Rhode Island\", \"density\": 1006}, {\"id\": \"45\", \"name\": \"South Carolina\", \"density\": 155.4}, {\"id\": \"46\", \"name\": \"South Dakota\", \"density\": 98.07}, {\"id\": \"47\", \"name\": \"Tennessee\", \"density\": 88.08}, {\"id\": \"48\", \"name\": \"Texas\", \"density\": 98.07}, {\"id\": \"49\", \"name\": \"Utah\", \"density\": 34.3}, {\"id\": \"50\", \"name\": \"Vermont\", \"density\": 67.73}, {\"id\": \"51\", \"name\": \"Virginia\", \"density\": 204.5}, {\"id\": \"53\", \"name\": \"Washington\", \"density\": 102.6}, {\"id\": \"54\", \"name\": \"West Virginia\", \"density\": 77.06}, {\"id\": \"55\", \"name\": \"Wisconsin\", \"density\": 105.2}, {\"id\": \"56\", \"name\": \"Wyoming\", \"density\": 5.851}, {\"id\": \"72\", \"name\": \"Puerto Rico\", \"density\": 1082}]\n",
"\n",
"viz = ChoroplethViz(data, \n",
" vector_url='mapbox://mapbox.us_census_states_2015',\n",
" vector_layer_name='states',\n",
" vector_join_color_property='STATEFP',\n",
" data_join_property='id',\n",
" color_property='density',\n",
" color_stops=create_color_stops([0, 50, 100, 500, 1500], colors='YlOrRd'),\n",
" line_stroke='dashed',\n",
" line_color='rgb(128,0,38)',\n",
" center=(-96, 37.8),\n",
" zoom=3,\n",
" below_layer='waterway-label'\n",
" )\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
}
1 change: 1 addition & 0 deletions examples/us-states.geojson

Large diffs are not rendered by default.

137 changes: 137 additions & 0 deletions mapboxgl/templates/choropleth.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
{% extends "main.html" %}

<!-- update legend item key style -->
{% block extra_css %}
<style type='text/css'>
.legend div span { border-radius: 20%; }
</style>
{% endblock extra_css %}

{% 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)=> {
if ( url.slice(0,22) == 'https://api.mapbox.com' ) {
//Add Python Plugin identifier for Mapbox API traffic
return {
url: [url.slice(0, url.indexOf("?")+1), "pluginName=PythonMapboxgl&", url.slice(url.indexOf("?")+1)].join('')
}
}
else {
//Do not transform URL for non Mapbox GET requests
return {url: url}
}
}
});

map.addControl(new mapboxgl.NavigationControl());

calcCircleColorLegend({{ colorStops }}, "{{ colorProperty }}");

map.on('style.load', function() {

{% block choropleth %}

// Add geojson data source
map.addSource("data", {
"type": "geojson",
"data": {{ geojson_data }},
"buffer": 1,
"maxzoom": 14
});

// Add data layer
map.addLayer({
"id": "choropleth-fill",
"source": "data",
"type": "fill",
"paint": {
"fill-color": generatePropertyExpression("{{ colorType }}", "{{ colorProperty }}", {{ colorStops }}, "{{ defaultColor }}"),
"fill-opacity": {{ opacity }}
}
}, "{{ belowLayer }}" );

// Add border layer
map.addLayer({
"id": "choropleth-line",
"source": "data",
"type": "line",
"layout": {
"line-join": "round",
"line-cap": "round"
},
"paint": {
{% if lineDashArray %}
"line-dasharray": {{ lineDashArray }},
{% endif %}
"line-color": "{{ lineColor }}",
"line-width": {{ lineWidth }},
"line-opacity": {{ opacity }}
}
}, "{{ belowLayer }}" );

// Add label layer
map.addLayer({
"id": "choropleth-label",
"source": "data",
"type": "symbol",
"layout": {
{% if labelProperty %}
"text-field": "{{ labelProperty }}",
{% endif %}
"text-size" : generateInterpolateExpression('zoom', [[0,8],[22,16]] ),
"text-offset": [0,-1]
},
"paint": {
"text-halo-color": "white",
"text-halo-width": 1
}
}, "{{belowLayer}}" );

{% endblock choropleth %}

// Create a popup
var popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
});

// Show the popup on mouseover
map.on('mousemove', 'choropleth-fill', 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', 'choropleth-fill', function() {
map.getCanvas().style.cursor = '';
popup.remove();
});

// Fly to on click
map.on('click', 'choropleth-fill', function(e) {
map.flyTo({
center: e.lngLat,
zoom: map.getZoom() + 1
});
});

});
{% endblock %}
1 change: 1 addition & 0 deletions mapboxgl/templates/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
width: 10px;
}
</style>
{% block extra_css %}{% endblock extra_css %}
</head>
<body>

Expand Down
Loading