Skip to content

Commit

Permalink
Add choropleth support (#40)
Browse files Browse the repository at this point in the history
* Add basic chloropleth support

* Center zoom on click coordinates; rename polygons layer to 'cholorpleth-fill' per PR review comments

* Add line_color, line_stroke, and line_width properties to ChloroplethViz; update url transformRequest function in map init to match implementation in master

* Add chloropleth label layer; add template block for styling legend keys

* Add line styling to example chloropleth notebook

* Update internal documentation in ChloroplethViz class; add chloropleth documentation to docs-markdown/viz.md template

* Update spelling to mapbox standard: 'choropleth'

* Add tests for ChoroplethViz (currently uses polygons.geojson)

* Formatting and headers on choropleth notebook

* Add vector layer support options; requesting direction for reconciling color assignment with data join and Mapboxgl-jupyter color_stops paradigm

* Single ChoroplethViz class defines either vector-based or geojson-based viz templates depending on variables in init

* Add support for categorical data-driven styling with vector data-join; include helper function for interpolating (mapping) colors when using vector-join technique; update docs and example notebook for vector data support in ChoroplethViz

* Attempt to add test for utils.rgb_tuple_from_str

* Additional test coverage for ChoroplethViz and color_map, rgb_tuple_from_str utils

* Per @ryanbaumann 's comments: revert color data-join style to the old Mapboxgl property functions (faster) and add layer-filter

* Test fix

* Minor refactor to color_map to prioritize returning exact match color from color_stops
  • Loading branch information
akacarlyann authored and ryanbaumann committed Mar 29, 2018
1 parent cd45841 commit 059e39b
Show file tree
Hide file tree
Showing 14 changed files with 1,284 additions and 21 deletions.
47 changes: 47 additions & 0 deletions docs-markdown/utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,50 @@ df = pd.read_csv(data_url)
color_breaks = [0,10,100,1000,10000]
color_stops = create_color_stops(color_breaks, colors='YlOrRd')
```

## rgb_tuple_from_str
Convert color represented as a string in format 'rgb(RRR,GGG,BBB)', 'rgba(RRR,GGG,BBB,alpha)', '#RRGGBB' or limited English color name (eg 'red') to tuple of integers from 0 to 255, (RRR, GGG, BBB).

### Params
**rgb_tuple_from_str**(_rgb_string_)

Parameter | Description
--|--
rgb_string | color represented as string in form 'rgb(RRR,GGG,BBB)', 'rgba(RRR,GGG,BBB,alpha)', '#RRGGBB', or limited HTML color names (eg 'red')

### Usage
```python
from mapboxgl.utils import rgb_tuple_from_str

# convert color string to tuple of integers
rgb_tuple_from_str('rgb(255,143,17')
```

## color_map
Convert color represented as a string in format 'rgb(RRR,GGG,BBB)' to tuple of integers from 0 to 255, (RRR, GGG, BBB).

### Params
**color_map**(_lookup, color_stops, default_color='rgb(122,122,122)'_)

Parameter | Description
--|--
lookup | value is numeric for interpolated colors or string for categorical color stops
color_stops | color ramp stops generated from `create_color_stops`, or custom list of numeric or categorical stops with paired colors
default_color | representation of color as hex, RGB, or RGBA strings

### Usage
```python
from mapboxgl.utils import create_color_stops, color_map

# interpolate color for numeric color_stops
color_stops = create_color_stops([0, 50, 100, 500, 1500], colors='YlOrRd')
color = color_map(73, color_stops)

# categorical look up
match_color_stops = [
['Massachusetts', 'rgb(46,204,113)'],
['Utah', 'rgb(231,76,60)'],
['California', 'rgb(142,68,173)'],
]
color = color_map('California', match_color_stops, default_color='grey)')
```
57 changes: 56 additions & 1 deletion docs-markdown/viz.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,61 @@ viz.show()
![HeatmapViz](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. Choropleth polygons can be initialized with geojson source or vector source styled using the data-join technique.

### Params
**ChoroplethViz**(_data, vector_url=None, vector_layer_name=None, vector_join_property=None, data_join_property=None, # vector only 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 | can be either GeoJSON (containing polygon features) or JSON for data-join technique with vector polygons |
vector_url | optional property to define vector polygon source | "mapbox://mapbox.us_census_states_2015"
vector_layer_name | property to define target layer of vector source if using vector polygon source | "states"
vector_join_property | property to aid in determining color for styling vector polygons | "STATEFP"
data_join_property | property of json data to use as link to vector features | "state_name"
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" or "-"
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 *
from mapboxgl.utils import *

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

# Create Choropleth with GeoJSON Source
viz = ChoroplethViz('us-states.geojson',
color_property='density',
color_stops=create_color_stops([0, 50, 100, 500, 1500], colors='YlOrRd'),
color_function_type='interpolate',
line_stroke='--',
line_color='rgb(128,0,38)',
line_width=1,
opacity=0.8,
center=(-96, 37.8),
zoom=3,
below_layer='waterway-label'
)
viz.show()
```
![ChoroplethViz](https://user-images.githubusercontent.com/13527707/37823022-73782a0a-2e45-11e8-9fdd-4a8ddd35cb92.png)


[Complete example](https://github.com/mapbox/mapboxgl-jupyter/blob/master/examples/choropleth-viz-example.ipynb)


## class ImageViz

The `ImageViz` object handles the creation of a simple image visualization on map and is built on top of the `MapViz` class.
Expand Down Expand Up @@ -397,4 +452,4 @@ viz.show()
![RasterTilesViz](https://user-images.githubusercontent.com/10407788/37537676-b055a108-2924-11e8-94cb-ad3203b736af.jpg)


[Complete example](https://github.com/mapbox/mapboxgl-jupyter/blob/master/examples/rastertile-viz-types-example.ipynb)
[Complete example](https://github.com/mapbox/mapboxgl-jupyter/blob/master/examples/rastertile-viz-types-example.ipynb)
191 changes: 191 additions & 0 deletions examples/choropleth-viz-example.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
{
"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": [
"# create choropleth from polygon features stored as GeoJSON\n",
"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\n",
"\n",
"In this configuration, properties in JSON data are used to calculate colors to style polygons from the vector source."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 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",
"# create choropleth map with vector source styling use data in JSON object\n",
"viz = ChoroplethViz(data, \n",
" vector_url='mapbox://mapbox.us_census_states_2015',\n",
" vector_layer_name='states',\n",
" vector_join_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",
" 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, categorical color scheme"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 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",
"match_color_stops = [\n",
" ['Massachusetts', 'rgb(46,204,113)'],\n",
" ['Utah', 'rgb(231,76,60)'],\n",
" ['California', 'rgb(142,68,173)'],\n",
"]\n",
"\n",
"# create choropleth map with vector source styling use data in JSON object\n",
"viz = ChoroplethViz(data, \n",
" vector_url='mapbox://mapbox.us_census_states_2015',\n",
" vector_layer_name='states',\n",
" vector_join_property='STATEFP',\n",
" data_join_property='id',\n",
" color_property='name',\n",
" color_stops=match_color_stops,\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()"
]
}
],
"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.

18 changes: 18 additions & 0 deletions mapboxgl/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,21 @@
12: ['rgb(141,211,199)', 'rgb(255,255,179)', 'rgb(190,186,218)', 'rgb(251,128,114)', 'rgb(128,177,211)', 'rgb(253,180,98)', 'rgb(179,222,105)', 'rgb(252,205,229)', 'rgb(217,217,217)', 'rgb(188,128,189)', 'rgb(204,235,197)', 'rgb(255,237,111)']
}
)

# a few HTML / X11 color names
common_html_colors = {
'red': 'rgb(255,0,0)',
'orange': 'rgb(255,165,0)',
'yellow': 'rgb(255,255,0)',
'green': 'rgb(0,128,0)',
'blue': 'rgb(0,0,255)',
'purple': 'rgb(128,0,128)',
'pink': 'rgb(255,192,203)',
'white': 'rgb(255,255,255)',
'grey': 'rgb(128,128,128)',
'gray': 'rgb(128,128,128)',
'black': 'rgb(0,0,0)',
'brown': 'rgb(139,69,19)',
'magenta': 'rgb(255,0,255)',
'cyan': 'rgb(0,255,255)',
}

0 comments on commit 059e39b

Please sign in to comment.