Rather dairy or beef ? How to make a choropleth map with Processing

November 2014

Choropleth maps provide an easy way to visualize how a measurement varies across a geographic area.

When drawing a choropleth map there are two important advices: first is that darker colors are perceived as representing higher values, and second is that the human eye can easily distinguish only a limited number of color variations (generally, for a single-hue progressions, it is recommended to use less than ten color categories). Additional considerations include color blindness and various reproduction techniques. For example, a red-green bi-polar progression is likely to cause problems for dichromats. There are very useful tools for the selection of sequential or diverging color scheme, one of my favorite is this one.


choropleth_map_france choropleth_map_france choropleth_map_france


These choropleth maps encode French cattle census datas for the year 2010: dairy cattle (left) in blue, beef cattle (right) in red, and the ratio between both (center). Click on it to enlarge and see the legend.

The following code explain how to draw a choropleth map with Processing (script and data files can be downloaded at the bottom of this page):

// choroplethMap.pde
// by Gaël Beaunée
// November 2014

import processing.pdf.*; // to save in pdf format

PShape countyMap = loadShape("mapFranceDepBis.svg"); // load map data
String[] lines = loadStrings("CattleHeadcount.csv"); // load census data
color[] colors = { #ece7f2, #d0d1e6, #a6bddb, #74a9cf, #3690c0, #0570b0, #045a8d, #023858 };

size(1000, 850); smooth();

beginRecord(PDF, "choroplethMap_France_Dairy.pdf");

background(255);

for (int i = 0; i < lines.length; i++) {
  // get the id of the tile and the associated data
  String[] row = split(lines[i], ";");
  String id = row[0];
  float rate = float(row[6]);
  
  // assigning a rank
  int colorIndex = 0;
  if (rate > 150000)
      colorIndex = 7;
  else if (rate > 100000)
      colorIndex = 6;
  else if (rate > 75000)
      colorIndex = 5;
  else if (rate > 50000)
      colorIndex = 4;
  else if (rate > 25000)
      colorIndex = 3;
  else if (rate > 10000)
      colorIndex = 2;  
  else if (rate > 5000)
      colorIndex = 1;  
  else if (rate >= 0)
      colorIndex = 0; 
  
  // draw the tile
  PShape county = countyMap.getChild(id);
  if (county != null) {
    county.disableStyle();
    fill(colors[colorIndex]);
    stroke(colors[colorIndex]); strokeWeight(0.1);
    shape(county);
  }
}
    

// draw the legend
int[] posY = { 500, 540, 580, 620, 660, 700, 740, 780 };
rectMode(CENTER);

for (int i = 0; i < posY.length; i++) {
  fill(colors[i]); stroke(colors[i]);
  rect(75, posY[i], 40, 40);
}

String[] label = { "0 - 5k", "5k - 10k", "10k - 25k", "25k - 50k", "50k - 75k", "75k - 100k", "100k - 150k", "> 150k" };
PFont font = createFont("FZLTTHB--B51-0", 25);
textFont(font, 25); textSize(20);
textAlign(LEFT,CENTER);
fill(50);

for (int i = 0; i < posY.length; i++) {
  text(label[i],110,posY[i]-3);
}

// access to other elements
//PShape states = countyMap.getChild("State_Lines");
//PShape separator = countyMap.getChild("separator");

endRecord();
saveFrame("choroplethMap_France_Dairy.png");

ChoroplethMap_CodeAndDataFiles