Making a Cartogram

Mike Bostok has a fantastic tutorial on how to make a map using d3 and topojson. Having done some mapping work recently for a client, I was keen to learn more and try do a d3 based cartogram. I found some good examples of non-contiguous cartograms, but I wanted to make a South African version of a contiguous one using Shawn Allen’s d3 implementation.

Here is the final product, and I’ll take you through some of the tricky parts that I had to deal with.

Open map in a new window

The first image is the ZA map using the local municipality demarcations. Using the 2011 voting data from www.iec.org.za, I mapped the winning party of each local municipality to the different colours.

ANC = Yellow, DA = Blue, IFP = Red and Other = Black.

What I wanted to see was how the area sizes changed when you mapped this against registered voters in the municipality. Again using the IEC data, I passed the number of registered voters to the cartogram function to change relative size of each municipality, depending on the number of voters. You can see how the City of Johannesburg grows substantially in the map above.

Shawn’s code has a lot of data options, and uses US state info and geography. Since a state and municipality are similar enough, I tried to map a TopoJSON file for South African municipalities on his code. It took a while and I only started to understand how it worked after simplifying things down significantly.

You can grab the code here. I have commented the trickier parts and vastly reduced the scope of the project from Shawn’s original implementation to make modifying it a bit more easy to understand.

The first issue was having the correct versions of the libraries. cartogram.js uses d3.v2.min.js and a particular version of topojson.js. Using the versions on d3js.org seemed to break. You can just grab the ones linked to from my map for in the zip bundle.

 <script src="lib/d3.v2.min.js"></script>
 <script src="lib/topojson.js"></script>
 <script src="lib/cartogram.js"></script>

Shawn’s example used data from from a CSV file to create the properties used in the map. However my topojson file already included properties with each municipality. The .properties method adds the properties you can use for names or colours etc.

 var carto = d3.cartogram()
            .projection(proj)
            .properties(function (d) {
                // this adds the "properties" properties 
                // to the geometries
                return d.properties;
            });

d3.cartogram uses d3.topojson to create the features data and adds the capability to recalculate the individual area shapes based on some numerical input. To create the original features, call cartogram like this:

var features = carto.features(topology, geometries)

To change / distort the shapes, call cartogram like this:

carto.value(function (d) {
    return +vote_data.get(d.properties["CAT_B"])[1];
});
var features = carto(topology, geometries).features;

I’ll be honest and say I really don’t understand the difference between those two ways of creating the features data, but it seems to work. The number you return in carto.value() will set the area relative to the maximum and minimum numbers you return. As an example if you were to return 1 then the shapes adjust to have the same area.

carto-1carto-2

 

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

5 thoughts on “Making a Cartogram”

  1. thank your for this great example! the simplification of the cartogram example helped me a lot.
    unfortunately I can’t create my source map identical to the structure of yours.
    could you help me out, that what kind of criteria did you use when creating the topojson file?

    thank you

    1. Hi there,

      I didn’t follow any particular structure, but the process I went through to make the topoJSON map is listed here:
      https://github.com/fletchjeff/datavizmeetup

      Part 1: Getting and preparing the data

      Shape files from the demarcations board

      http://www.demarcation.org.za/

      Convert to GeoJSON here

      http://converter.mygeodata.eu/vector

      Combine with topojson

      https://github.com/mbostock/topojson/wiki/Command-Line-Reference

      $ topojson -o za.json –properties wards.json prov.json

      Shrink with MapShaper

      http://www.mapshaper.org/

      1. thank you for the quick response!
        I’ve managed to create a similar structure to yours by these commands in terminal using topojson:

        topojson \
        --id-property \
        -p \
        -o map.json \
        map.shp

        i am working with the map of europe. the script is functioning, without any errors, but unfortunately the amount of distortion is nearly seamless when I run it.

        wouldn’t it be possible to somehow increase the amount of distortion so it is visible?

        download link for the directory/files I am working with.
        http://d.pr/f/1ep9S

        thank you

        1. Hiya,

          Been travelling the last little while and not had a chance to look at this yet. Will look at your code over the weekend and let you know.

        2. Hi, the code you sent me is missing a file:

          Failed to load resource: the server responded with a status of 404 (File not found) http://localhost:8000/data/dx_derex_big.csv

Leave a Reply

Your email address will not be published. Required fields are marked *