问题
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