Mapbox Choropleth Maps in Python/v3

How to make a Mapbox Choropleth Map of the Florida Counties in Python with Plotly.


Note: this page is part of the documentation for version 3 of Plotly.py, which is not the most recent version.
See our Version 4 Migration Guide for information about how to upgrade.
The version 4 version of this page is here.

New to Plotly?¶

Plotly's Python library is free and open source! Get started by dowloading the client and reading the primer.
You can set up Plotly to work in online or offline mode, or in jupyter notebooks.
We also have a quick-reference cheatsheet (new!) to help you get started!

Version Check¶

Run pip install plotly --upgrade to update your Plotly version

In [1]:
import plotly
plotly.__version__
Out[1]:
'2.4.1'

In this tutorial, we will be creating a choropleth of Florida's counties with the Republican and Democratic counties colored red and blue respectively.

Mapbox Access Token¶

To plot on Mapbox maps with Plotly you'll need a Mapbox account and a Mapbox Access Token which you can add to your Plotly settings. If you're using a Chart Studio Enterprise server, please see additional instructions here: https://help.plot.ly/mapbox-atlas/.

Read the Data¶

Read both a GeoJSON file of the Florida counties and a webpage indicating Florida's voting registration by county

In [8]:
import pandas as pd
import string
import urllib

repub_democ_counties_url = 'http://dos.myflorida.com/elections/data-statistics/voter-registration-statistics/voter-registration-monthly-reports/voter-registration-current-by-county/'
florida_data_url = 'https://raw.githubusercontent.com/plotly/datasets/master/florida_county_data.geojson'

repub_democ_counties = urllib.urlopen(repub_democ_counties_url).read()
florida_data = pd.read_json(florida_data_url)

county_names = []
county_names_dict = {}

for county in florida_data['features']:
    for m in range(len(county['properties']['name'])):
        if county['properties']['name'][m:m+6] == 'County':
            county_names.append(county['properties']['name'][0:m-1])
            county_names_dict[county['properties']['name'][0:m-1]] = county['properties']['name']

print county_names
[u'Charlotte', u'Seminole', u'Baker', u'DeSoto', u'Levy', u'Alachua', u'Pasco', u'Hendry', u'Okeechobee', u'Broward', u'St. Johns', u'Gulf', u'Glades', u'Marion', u'Duval', u'Madison', u'Osceola', u'Lee', u'Volusia', u'Sarasota', u'Indian River', u'Clay', u'Putnam', u'Wakulla', u'Holmes', u'Escambia', u'Flagler', u'Union', u'Brevard', u'Suwannee', u'Orange', u'Martin', u'Nassau', u'Jefferson', u'Santa Rosa', u'Hamilton', u'Calhoun', u'Hernando', u'Miami-Dade', u'Pinellas', u'Palm Beach', u'Hillsborough', u'Collier', u'Gilchrist', u'Dixie', u'Bay', u'Gadsden', u'Okaloosa', u'Citrus', u'Lafayette', u'Manatee', u'Monroe', u'Columbia', u'Sumter', u'Washington', u'St. Lucie', u'Polk', u'Taylor', u'Leon', u'Lake', u'Highlands', u'Hardee', u'Bradford', u'Liberty', u'Franklin', u'Walton', u'Jackson']

Since we want to separate the counties into Republican and Democratic for the seperate coloring, and since the county names in the GeoJSON are fuller text descriptions of each county on the website, we need to parse through and convert the names in the GeoJSON to the website format

Color the Counties¶

We now run a script to color our counties based on political party. This involves parsing through our list of counties, finding their cooresponding Republican/Democratic votes on the website, and place our data into the cooresponding list red_counties or blue_counties, based on which party has more votes

In [9]:
red_counties = []
blue_counties = []

for k, county in enumerate(county_names):
    for j in range(len(repub_democ_counties)):
        county_len = len(county)
        if repub_democ_counties[j:j+county_len] == string.upper(county):
            new_j = j
            while True:
                try:
                    int(repub_democ_counties[new_j])
                    break
                except ValueError:
                    new_j += 1

    repub_votes = ''
    while repub_democ_counties[new_j] != '<':
        if repub_democ_counties[new_j] != ',':
            repub_votes += repub_democ_counties[new_j]
        new_j += 1

    # advance to next set of numbers
    new_j += 11

    democ_votes = ''
    while repub_democ_counties[new_j] != '<':
        if repub_democ_counties[new_j] != ',':
            democ_votes += repub_democ_counties[new_j]
        new_j += 1

    try:
        repub_votes = int(repub_votes)
    except ValueError:
        repub_votes = 0
    try:
        democ_votes = int(democ_votes)
    except ValueError:
        democ_votes = 0

    if repub_votes >= democ_votes:
        red_counties.append(florida_data['features'][k])
    else:
        blue_counties.append(florida_data['features'][k])
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/ipykernel_launcher.py:7: UnicodeWarning:

Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal

Create JSON Files¶

In plotly/datasets, you can find the generated JSON files below for the red counties and blue counties

In [10]:
import json

red_data = {"type": "FeatureCollection"}
red_data['features'] = red_counties

blue_data = {"type": "FeatureCollection"}
blue_data['features'] = blue_counties

with open('florida-red-data.json', 'w') as f:
    f.write(json.dumps(red_data))
with open('florida-blue-data.json', 'w') as f:
    f.write(json.dumps(blue_data))

and we can now plot our choropleth using Python. Make sure to have a Mapbox Access Tolken for the generation of the plot. For more information on plotting Mapbox maps in Python, checkout the documentation

In [11]:
import plotly.plotly as py
import plotly.graph_objs as graph_objs

mapbox_access_token = "ADD_YOUR_TOKEN_HERE"

data = graph_objs.Data([
    graph_objs.Scattermapbox(
        lat=['45.5017'],
        lon=['-73.5673'],
        mode='markers',
    )
])
layout = graph_objs.Layout(
    height=600,
    autosize=True,
    hovermode='closest',
    mapbox=dict(
        layers=[
            dict(
                sourcetype = 'geojson',
                source = 'https://raw.githubusercontent.com/plotly/datasets/master/florida-red-data.json',
                type = 'fill',
                color = 'rgba(163,22,19,0.8)'
            ),
            dict(
                sourcetype = 'geojson',
                source = 'https://raw.githubusercontent.com/plotly/datasets/master/florida-blue-data.json',
                type = 'fill',
                color = 'rgba(40,0,113,0.8)'
            )
        ],
        accesstoken=mapbox_access_token,
        bearing=0,
        center=dict(
            lat=27.8,
            lon=-83
        ),
        pitch=0,
        zoom=5.2,
        style='light'
    ),
)

fig = dict(data=data, layout=layout)
py.iplot(fig, filename='county-level-choropleths-python')
Out[11]:

Reference¶

See https://plotly.com/python/reference/#scattermapbox for more information about mapbox and their attribute options.