4

The goal here is to create a choropleth map of Canada in Python. Suppose I have a dictionary with values referring to each Canadian province/territory:

values={'Alberta': 1.0,
 'British Columbia': 2.0,
 'Manitoba': 3.0,
 'New Brunswick': 4.0,
 'Newfoundland and Labrador': 5.0,
 'Northwest Territories': 6.0,
 'Nova Scotia': 7.0,
 'Nunavut': 8.0,
 'Ontario': 9.0,
 'Prince Edward Island': 10.0,
 'Quebec': 11.0,
 'Saskatchewan': 12.0,
 'Yukon': 13.0}

Now I want to color each province based on the corresponding value in values, using a continuous colormap (e.g., shades of red). How to do that?

So far I have only been able to plot the Canadian provinces/territory within matplotlib, but their shapes appear in a unique color, and I don't know how to change that according to the numbers in values.

This is where you can find the shapefile: http://www.filedropper.com/canadm1

And this is my code to date:

import shapefile
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
#   -- input --
sf = shapefile.Reader("myfolder\CAN_adm1.shp")
recs    = sf.records()
shapes  = sf.shapes()
Nshp    = len(shapes)
cns     = []
for nshp in xrange(Nshp):
    cns.append(recs[nshp][1])
cns = array(cns)
cm    = get_cmap('Dark2')
cccol = cm(1.*arange(Nshp)/Nshp)
#   -- plot --
fig     = plt.figure()
ax      = fig.add_subplot(111)
for nshp in xrange(Nshp):
    ptchs   = []
    pts     = array(shapes[nshp].points)
    prt     = shapes[nshp].parts
    par     = list(prt) + [pts.shape[0]]
    for pij in xrange(len(prt)):
     ptchs.append(Polygon(pts[par[pij]:par[pij+1]]))
    ax.add_collection(PatchCollection(ptchs,facecolor=None,edgecolor='k', linewidths=.5))
ax.set_xlim(-160,-40)
ax.set_ylim(40,90)

This is the image I am getting so far:

enter image description here

2

2 Answers 2

2

In the spirit of your question, I too would use GeoPandas like gene said. However I'll also directly answer your question how to do this in matplotlib...

Create an object to map continuous values to colors. ScalarMappable is the matplotlib class to do this, and you can give it a Normalize behavior to anchor the min and max range of the values you want to plot to the extreme colors of your colormap.

cmap = matplotlib.cm.get_cmap('OrRd')
norm = matplotlib.colors.Normalize(min(myvalues.values()), max(myvalues.values()))
color_producer = matplotlib.cm.ScalarMappable(norm=norm, cmap=cmap)

Now color_producer has a method to_rgba that takes values from values and converts them to the correct colors. The colors you get back take forms of RGBA tuples (Red, Green, Blue, & Alpha transparency).

Now when you create each province's PatchCollection, you can set its facecolor to the RGBA tuple returned by color_producer:

# Change the province name passed as you iterate through provinces.
rgba = color_producer.to_rgba(myvalues['Manitoba'])
PatchCollection(ptchs, facecolor=rgba, edgecolor='k', linewidths=.5)
2

The simple way is to use GeoPandas

import geopandas as gpd
# read the shapefile as a GeoDataFrame
can = gpd.GeoDataFrame.from_file("CAN_adm1.shp")
# The first element
can.head(5)
### many data 
#plot the shapefile/GeoDataFrame
can.plot()

enter image description here

You can even plot a column

can.plot(column='NAME_1');

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.