1

I'm working on creating a graph that will show unemployment rates by county in the United States. It's based on Mike Bostock's County-level map here, and it looks like this:

enter image description here

It works by pulling data from a CSV, assigning that data to a Javascript Map, and using that to color the various counties with a d3 color scale. My CSV data looks like this:

county,area,rate2007,rate2008,rate2009,rate2010,rate2011,rate2012,rate2013,rate2014,rate2015,rate2016
01001,Autauga County,3.3,5.1,9.7,8.9,8.4,6.9,6.2,5.9,5.3,5.3
01003,Baldwin County,3.1,4.6,9.8,10.0,9.0,7.5,6.6,6.1,5.6,5.4
01005,Barbour County,6.3,8.8,14.3,12.3,11.5,11.5,10.2,10.6,8.8,8.6
01007,Bibb County,4.1,5.8,13.3,11.4,10.5,8.5,7.9,7.2,6.7,6.6
01009,Blount County,3.2,4.7,10.0,9.8,8.7,6.9,6.3,6.1,5.4,5.5
etc...

Here's my issue: I want to be able to change this data over time, and to do so must be able to include multiple values in my Map. However, I cannot get this to work. In attempting to "upgrade" my map, I tweak the code slightly to use an array as the value in the key-value pair in the Map:

d3.queue()
   .defer(d3.json, "https://d3js.org/us-10m.v1.json")
   .defer(d3.csv, "unemploymentEdited.csv", function(d) {
        unemployment.set(d.county, [+d.rate2007, +d.rate2008]);
   }) // I use an array here to include multiple values.
   .await(ready);

When I log this to the console, my data is indeed formatted as I would expect:

enter image description here

However, I cannot use these values to color my paths correctly. When I use a relatively simple function to access the data from the Map, it logs this error to the console: "TypeError: unemployment.get(...) is undefined."

Even more strangely, when I log this same thing to the console outside of my "fill" attribute, I get the number I would expect, meaning I get the values inside my Map. Like if I write console.log(unemployment.get(d.id)[0]) I get 4.6, or whatever the value is. What am I doing wrong? Why does the "get" function return undefined, even though I can see that the data structure is not?

Here's my full code:

var width = 960;
var height = 600;
var margin = {top: 50, bottom: 0, left: 0, right: 0}

var path = d3.geoPath(); // Geopath generator

var unemployment = new Map();
var color =  d3.scaleSequential()
        .domain([0.0,30.0])
        .interpolator(d3.interpolateInferno);

var svg = d3.select("body").append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.bottom + margin.top)
  .style("background-color","lightgrey")

d3.queue()
    .defer(d3.json, "https://d3js.org/us-10m.v1.json")
    .defer(d3.csv, "unemploymentEdited.csv", function(d){
      unemployment.set(d.county, [+d.rate2007,+d.rate2008])
    })
    .await(ready);

function ready(error, us) {

  console.log(unemployment)

  svg.append("g")
      .attr("class", "counties")
      .attr("transform",`translate(0,${margin.top})`)
    .selectAll("path")
    .data(topojson.feature(us, us.objects.counties).features)
    .enter().append("path")
    .attr("fill", function(d){
      return color(unemployment.get(d.id)[0])
    })
    .attr("d", path)

}
5
  • 1
    As you have two different data sets (the TopoJSON and the CSV), which adds complexity, the best idea is creating a running code. In your case, try Blockbuilder. Just copy/paste the code and upload the two data files, with the correct names and extensions. Also, it's important checking if d.id exactly matches d.county. Commented Jan 11, 2018 at 2:32
  • Here's the bl.ock (I do use blockbuilder, it's great). Same problem though. bl.ocks.org/KingOfCramers/raw/93fba8eb9f797c31fe4f1cab52a3ed32/… Commented Jan 11, 2018 at 3:03
  • 1
    We cannot edit a bl.ock, that's why I suggested a blockbuilder. I'm having a look at it now. Commented Jan 11, 2018 at 3:05
  • Sorry, it's here: blockbuilder.org/KingOfCramers/93fba8eb9f797c31fe4f1cab52a3ed32 Commented Jan 11, 2018 at 3:06
  • No worries, it's just a matter of changing bl.ocks.org to blockbuilder.org (normally). +1 for the well documented question, I wish they were always like that. Commented Jan 11, 2018 at 3:23

1 Answer 1

1

Well, your d3.map() is correct, that's not the problem.

The problem is that your CSV doesn't have data for all counties. Therefore, sometimes, this...

unemployment.get(d.id)

... is undefined, which explains your error:

unemployment.get(d.id)[0] --> Cannot read property '0' of undefined

Solution

Check for undefined:

.attr("fill", function(d){
    return unemployment.get(d.id) ? color(unemployment.get(d.id)[0]) : "#ccc";
})

Here, if unemployment.get(d.id) is undefined, the function will return #ccc. Change this according to the colour you want.

Here is the updated bl.ocks: https://bl.ocks.org/anonymous/3adc7518e4423d816f6b6842ef48d27f/414e4b738dd4c2d8e91a9ca2fb8511dcec747b9c

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I will have to make sure to check for undefined in all my data in the future. Real-world data is more sloppy than what I am used to using while learning D3. Also, I checked out your visualizations on neocities, very cool stuff! :)

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.