Choropleth map returning undefined

痴心易碎 提交于 2020-01-06 02:52:09

问题


I'm attempting a choropleth map of US Counties, and am essentially using Mike Bostock's example from here https://bl.ocks.org/mbostock/4060606 I am using education instead of unemployment, but otherwise it's the same. I'd like to add just one more piece to it and have the county name display along with the rate. However, when I call the county name, I get "undefined" returned. To be clear 'rate' returns just fine, 'county' shows up undefined. Can anyone help? Thanks!

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.counties {
  fill: none;
  /*stroke: black;*/
}

.states {
  fill: none;
  stroke: #fff;
  stroke-linejoin: round;
}

</style>
<svg width="960" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<script>

var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height");

var Bachelor = d3.map();

var path = d3.geoPath();

var x = d3.scaleLinear()
    .domain([0, 70])
    .rangeRound([600, 860]);

var color_domain = [10, 20, 30, 40, 50, 60, 70]
var ext_color_domain = [10, 20, 30, 40, 50, 60, 70]
var color = d3.scaleThreshold()
    .domain(color_domain)
    .range([" #85c1e9", "#5dade2", "#3498db", "#2e86c1", "#2874a6", " #21618c"," #1b4f72"]);
var g = svg.append("g")
    .attr("class", "key")
    .attr("transform", "translate(0,40)");

g.selectAll("rect")
  .data(color.range().map(function(d) {
      d = color.invertExtent(d);
      if (d[0] == null) d[0] = x.domain()[0];
      if (d[1] == null) d[1] = x.domain()[1];
      return d;
    }))
  .enter().append("rect")
    .attr("height", 8)
    .attr("x", function(d) { return x(d[0]); })
    .attr("width", function(d) { return x(d[1]) - x(d[0]); })
    .attr("fill", function(d) { return color(d[0]); });

g.append("text")
    .attr("class", "caption")
    .attr("x", x.range()[0])
    .attr("y", -6)
    .attr("fill", "#000")
    .attr("text-anchor", "start")
    .attr("font-weight", "bold")
    .text("% of Adults with Bachelor's or higher");

g.call(d3.axisBottom(x)
    .tickSize(13)
    .tickFormat(function(x, i) { return i ? x : x; })
    .tickValues(color.domain()))
  .select(".domain")
    .remove();

d3.queue()
    .defer(d3.json, "https://d3js.org/us-10m.v1.json")
    .defer(d3.tsv, "Bachelor2.tsv", function(d) { Bachelor.set(d.id, d.rate, d.county); })
    .await(ready);


function ready(error, us) {
  if (error) throw error;


  svg.append("g")
      .attr("class", "counties")
    .selectAll("path")
    .data(topojson.feature(us, us.objects.counties).features)
    .enter().append("path")
      .attr("fill", function(d) { return color(d.rate = Bachelor.get(d.id)); })
      .attr("d", path)
    .append("title")
      .text(function(d) { return (d.county +" " d.rate +"%"); });

  svg.append("path")
      .datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; }))
      .attr("class", "states")
      .attr("d", path);
}

</script>

回答1:


There are two problems in your code.

The first problem in your code lies here:

Bachelor.set(d.id, d.rate, d.county);

In both javascript maps and D3 maps (which are slightly different), you cannot set two values for the same key. Therefore, the syntax has to be:

map.set(key, value)

Let's show it.

This works, setting the value "bar" to "foo":

var myMap = d3.map();
myMap.set("foo", "bar");
console.log(myMap.get("foo"))
<script src="https://d3js.org/d3.v4.min.js"></script>

However, this will not work:

var myMap = d3.map();
myMap.set("foo", "bar", "baz");
console.log(myMap.get("foo"))
<script src="https://d3js.org/d3.v4.min.js"></script>

As you can see, the value "baz" was not set.

That was assuming that country is a property in your Bachelor2.tsv file. And that brings us to the second problem:

In your paths, this is the data:

topojson.feature(us, us.objects.counties).features

If you look at your code, you set a property named rate (using your map) to that data...

.attr("fill", function(d) { return color(d.rate = Bachelor.get(d.id)); })
//you set 'rate' to the datum here --------^

...but you never set a property named country. Therefore, there is no such property for you to use in the callbacks.

As explained above, you cannot set it using the same map you used to set the rate. A solution is using an object instead. Alternatively, you could use two maps, which seems to be the fastest option.



来源:https://stackoverflow.com/questions/46509772/choropleth-map-returning-undefined

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!