I do not have a good understanding of D3, or really javascript - I am very new to all of this. I've been wokring on a project to replicate this, which I have been essentially borrowing directly from to create my code. I am hoping to make a cartogram that changes my data by the amount of visitor info. I switched out a lot of the variables for my own data, but I have been getting an error message saying:

d3.v2.min.js:2 Uncaught TypeError: Cannot read property 'length' of undefined
at n (d3.v2.min.js:2)
at Array.ks.data (d3.v2.min.js:2)
at (index):140

it is flagging the error at the first line of

                .text(function (d) {
                    return d.properties.ZONE;

The svg with the map is displaying fine, it is the resizing based on visitor population data (stored i the csv as .YTD.) I am fairly certain my json is a topojson, I went through the whole process to make it one based on previous implementations and the arrangement of the code within it looks correct. I do have a column in my JSON named ZONE, and a column in my csv names zone - but I thought that since js is case sensitive this would not be a problem.

I've tried switching a few things around - heres my code. I'm including the commented out sections from the original tutorial code that provide some context.


    <title>Gate Cartogram V2</title>
    <meta charset="utf-8">
    <script src="lib/d3.v2.min.js"></script>
    <script src="lib/topojson.js"></script>
    <script src="lib/cartogram.js"></script>
    <link href='http://fonts.googleapis.com/css?family=Open+Sans:300' rel='stylesheet' type='text/css'>
    <style type="text/css">
        body {
            font-family:'Open Sans', sans-serif;
            font-weight: 300;
            font-size: 14px;
            line-height: 1.4em;
            padding-top: 20px;
            margin: 0 auto;
            width: 600px;
        #map-container {
            height: 500px;

            position: relative;
            margin: 10px 0;

        #map {
            overflow: visible;
        #click_to_run {
            width: 600px;
            font-size: 2em;
            text-align: center;
            cursor: pointer;
            padding-top: 30px;
        path.zones {
            stroke: #AAA;
            stroke-width: .5;
        path.zones:hover {
            stroke: #000;

    <div id="click_to_run" 
        onclick="do_update()" >
    <div id="map-container">
        <svg id="map"></svg>

        //the colour scheme for the different winning parties.
//        var colour_map = {
//            "ANC": "#FFCC00",
//            "DA": "#005CA7",
//            "IFP": "#FF1800"
//        };

        var map = d3.select("#map");

        var zone = map.append("g")
            .attr("id", "zone")

        var proj = d3.geo.albers()

        var topology,

        var park_data = d3.map();

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

         // the data came from some rolling up of info I got from iec.org.za site. 
         // It lists the winning party, number or registered voters and votes 
         // cast per local municipality.
        d3.csv("data/park_2017.csv", function (data) {
            data.forEach(function (d) {
                park_data.set(d.ZONE, d.YTD);

         // this loads test the topojson file and creates the map.
        d3.json("data/GATE_V5.topojson", function (data) {
            topology = data;
            geometries = topology.objects.GATE_v5.geometries;

            //these 2 below create the map and are based on the topojson implementation
            var features = carto.features(topology, geometries),
                path = d3.geo.path()

            zone = zone.data(features)
                .attr("class", "zone")
                .attr("id", function (d) {
                    return d.properties.ZONE;
                .attr("d", path);

            d3.select("#click_to_run").text("click here to run");

        function do_update() {
            setTimeout(function () {

                // this sets the value to use for scaling, per munic. Here I used the total number 
                // of voters per munic. the scaling is relative to the max value.
                carto.value(function (d) {
                    return +park_data.get(d.properties["ZONE"])[1];

                if (carto_features == undefined)
                    //this regenrates the topology features for the new map based on 
                   // carto_features = carto(topology, geometries).features;

                //update the map data
                    .text(function (d) {
                        return d.properties.ZONE;

                    .each("end", function () {
                    .attr("d", carto.path);
            }, 10);


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.