Javascript D3工具提示中未定义的属性

Javascript D3工具提示中未定义的属性,javascript,d3.js,Javascript,D3.js,我试图在工具提示中添加两个属性,但一直失败。我可以在工具提示中显示四个属性中的两个,但不是全部。可以显示“id”和“比率”,但不能显示“州”和“县”。我认为这是由于错误的数据加载,但无法修复它。你能帮忙吗 我还在底部列出了我的部分数据 这是我的密码: <!DOCTYPE html> <meta charset="utf-8"> <style> .counties { fill: none; } .states { fill: none; str

我试图在工具提示中添加两个属性,但一直失败。我可以在工具提示中显示四个属性中的两个,但不是全部。可以显示“id”和“比率”,但不能显示“州”和“县”。我认为这是由于错误的数据加载,但无法修复它。你能帮忙吗

我还在底部列出了我的部分数据

这是我的密码:

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

.counties {
  fill: none;
}

.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 unemployment = d3.map();

var path = d3.geoPath();

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

var color = d3.scaleThreshold()
    .domain([0, 1, 2, 4, 8, 10])
    .range(d3.schemeBlues[6]);

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("x", x.range()[0] - 30)
    .attr("y", -6)
    .attr("fill", "#000")
    .attr("text-anchor", "start")
    .attr("font-weight", "bold")
    .text("House Price to Income Ratio Rate");

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, "data.tsv", function(d) { unemployment.set(d.id, +d.rate, d.state, 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 = unemployment.get(d.id)); })
    .attr("d", path)
    .append("title")
    .text(function(d) { var q = d3.format(".2f")
        return 'State:' + d.state + ' ' + d.county + ' ' +d.id + ':' +(q(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>

您的问题在于,您正在访问每个地理要素的数据,而不是tsv中的行,如下所示:

 .text(function(d) { var q = d3.format(".2f")
        return 'State:' + d.state + ' ' + d.county + ' ' +d.id + ':' +(q(d.rate)); }
        );
d
此函数中包含来自geojson的特征数据,如下所示:

Object { type: "Feature", id: "18121", properties: Object, geometry: Object }  
Object { type: "Feature", id: "39103", properties: Object, geometry: Object }
Object { $47035: 0.66, $47089: 1.26, $47129: 1.08, $47155: 1.34, $47105: 1.16, $47145: 1.1, $47151: 1.26, $47067: 1.21, $47173: 1.03, $47063: 1.22, 28 more… }
您需要正确映射数据并使用d3.map()访问它。看起来您正在使用,并且您的修改看起来很直观,但是:

.defer(d3.tsv, "data.tsv", function(d) { unemployment.set(d.id, +d.rate, d.state, d.county); })
产生如下数据结构:

Object { type: "Feature", id: "18121", properties: Object, geometry: Object }  
Object { type: "Feature", id: "39103", properties: Object, geometry: Object }
Object { $47035: 0.66, $47089: 1.26, $47129: 1.08, $47155: 1.34, $47105: 1.16, $47145: 1.1, $47151: 1.26, $47067: 1.21, $47173: 1.03, $47063: 1.22, 28 more… }
我不相信d3.map().set()允许每个键有多个值。相反,您可以使用对象作为值:

.defer(d3.tsv, "data.tsv", function(d) { unemployment.set(d.id, d); })
要访问tsv文件中的列,您可以使用以下行:

unemployment.get(d.id).state

最后,可能每个县都有一个完整的数据集,尽管您可能只查看选定的县,在这种情况下,您可以添加一个检查以查看数据是否存在(否则,当您查找每个县的数据时,您的d3.map()将返回未定义的某些县的数据。类似这样的操作可以:

.attr("fill", function(d) {  if(unemployment.get(d.id)) { return color(d.rate = unemployment.get(d.id).rate); } else { return "none"; } })
.attr("d", path)
.append("title")
.text(function(d) { var q = d3.format(".2f"); 
    if (unemployment.get(d.id)) {
            return 'State:' + unemployment.get(d.id).state + ' ' + unemployment.get(d.id).county + ' ' +d.id + ':' +(q(d.rate)); 
        }
        else {
            return "no data";
        }
    });
一切都在行动

请注意,在上面的代码块中,d.rate是在显示颜色时设置的,因此在以后设置文本内容时不需要使用失业映射来设置该值。在您正在处理的示例中,这也是正确的