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

时间:2017-06-19 04:55:44

标签: javascript d3.js

我正在尝试在工具提示中添加两个属性,但仍然失败。我可以在工具提示中显示四个属性中的两个,但不是全部。可以显示“id”和“rate”,但不能显示“state”和“county”。我认为这是由于错误的数据加载,但无法修复它。你能帮忙吗?

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

这是我的代码:

<!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>

数据:

id  rate    state   county
47035   0.66    TN  CUMBERLAND
47089   1.26    TN  JEFFERSON
47129   1.08    TN  MORGAN
47155   1.34    TN  SEVIER
47105   1.16    TN  LOUDON
47145   1.1 TN  ROANE
47151   1.26    TN  SCOTT
47067   1.21    TN  HANCOCK
47173   1.03    TN  UNION
47063   1.22    TN  HAMBLEN
47033   1.17    TN  CROCKETT
47157   1.06    TN  SHELBY
47167   1.02    TN  TIPTON
47045   0.75    TN  DYER
47069   1.19    TN  HARDEMAN
47075   1.3 TN  HAYWOOD
47097   1.05    TN  LAUDERDALE
47047   1.38    TN  FAYETTE
47095   1.16    TN  LAKE
47017   1.11    TN  CARROLL
47005   1.19    TN  BENTON
47079   0.99    TN  HENRY
47183   1.06    TN  WEAKLEY
47131   1.1 TN  OBION
47053   1.13    TN  GIBSON
47113   1.26    TN  MADISON
47109   1.25    TN  MCNAIRY
47039   1.37    TN  DECATUR
47071   1.28    TN  HARDIN
47077   1.45    TN  HENDERSON
47023   1.21    TN  CHESTER
47181   1.34    TN  WAYNE
47055   1.16    TN  GILES
47099   1.31    TN  LAWRENCE
47101   1.32    TN  LEWIS
47141   1.45    TN  PUTNAM
47049   1.46    TN  FENTRESS
47133   1.2 TN  OVERTON

1 个答案:

答案 0 :(得分:1)

您的问题在于您正在访问每个地理要素的基准,而不是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 }

您需要正确映射数据并使用d3.map()访问它。看起来您正在使用this example,并且您的修改看起来很直观,但是:

.defer(d3.tsv, "data.tsv", function(d) { unemployment.set(d.id, +d.rate, d.state, d.county); })

会产生如下数据结构:

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()当你查找每个县的数据时,会为某些县返回undefined。这样的东西会起作用:

.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";
        }
    });

Here's a block一切都在行动中。

请注意,在上面的代码块中,在显示颜色时设置了d.rate,因此在设置文本内容之后不需要使用失效贴图来设置该值。在您使用的可能示例中也是如此,in this block