Illustrator data-driven maps

I have searched high and low for a way to colorize parts of a map based on a csv or xml file. For instance to illustrate results of a election. Doing it by hand is both tedious

I imagine being able to attach a path to an variable and being able to change the background-image or the swatch based on a numeric value.

Has any one got a idea on how to approach this?

Answer

Doing this is pretty simple. All you need is:

  • A data file in a CSV form with names and values.
  • Each region shape to be filled annotated by the name.

Then all you do is a loop over each column, although you may want 2 loops if you want to normalize data ranges. Here is the final result of a tutorial that I prepared for students in my university:

#target illustrator


(function () { // protect namespace

var doc = app.activeDocument;
var input = read_data_CSV();

var data = input[0];
var max = input[1];
var min = input[2];

for ( i = 0; i < data.length; i++ ) {  
    var name = data[i][0];
    var value = (data[i][1] - min)/(max-min)*100;

    try{
        var pathitem = doc.pageItems.getByName(name);

        var col = new CMYKColor();
        col.black = 0;
        col.cyan = 100 - value;
        col.magenta = value;
        col.yellow = 0;

        pathitem.fillColor = col;
        if (pathitem.typename === "CompoundPathItem")
            pathitem.pathItems[0].fillColor = col; 

    } catch(err) {
       alert(name+ " errors!");  
    }  
}


/**
 * Prompt user for a CSV file, two columns 
 * name and value. The CSV file is assumed
 * to be in form:
 *
 * name;10.5
 *
 * Where the column separator is ";" and 
 * the decimal separator is ".".
 *
 * @returns {array} containing the data, max
 *                  and min.
 */
function read_data_CSV(){
    var file = File.openDialog('data', 'center:*.csv');
    file.open( 'r' );  

    var max = Number.MIN_VALUE;
    var min = Number.MAX_VALUE;
    var data = [];

    while( !file.eof ) {  
        var input = file.readln().split( ';' );
        var numeric = parseFloat(input[1]);

        if (numeric > max) max = numeric;
        if (numeric < min) min = numeric;

        data.push([input[0], numeric]);
    }

    return [data, max, min];
}

})(); //run on load

Map

Image 1: Example map mapped with values form csv file

To test this on some real map data Ive prepared following files:

  • map.ai, a map containing the map of municipalities in Southern Finland. The map is based on “NLS Yleiskarttarasteri 1:1 000 000, 1.4.2013” you may share or mix this data as long as you attribute the source and list version where it was taken from.
  • population_31_12_2016_logarithmic.csv, containing the population data for the region in December 31 2016.
  • percentage_of_unemployment_2015.csv, containing unemployment data in year 2015.

Be sure to have the file to modify active. This is a example only I would need to be much more robust to share it as something else.

Attribution
Source : Link , Question Author : Jakob Thuemoes , Answer Author : joojaa

Leave a Comment