d3.scale.quantize产生意外结果,如何调试?

时间:2015-12-19 13:26:41

标签: json d3.js

我有一个choropleth的工作示例,它从.csv文件中获取数据值并计算颜色范围。

一个地区可以采用四种可能的颜色,具体取决于人口。

对于我正在尝试开发的应用程序,我需要服务器从数据库加载数据。作为一个虚拟的例子,我做了一条返回json的路线。 json.features包含geojson信息和json.features.properties.value - 人口值。

这是我使用的功能。它正确绘制地图,工具提示上的人口值也是正确的。颜色域是[98,629725]。然而,只有一个区域采用非常暗的颜色,只有四个区域采用更亮的一个,而所有其他区域采用另一种颜色。如果你看一下我在顶部提供的链接 - 颜色的分布更均匀。但是在用这段代码制作的地图中 - 我有5000种人口和90000人口的地方颜色相同。

我现在卡住了,因为我真的没有看到问题出在哪里,而且我对如何调查它并不了解。您能否建议在这种情况下首先要检查的是什么?也许你已经看到这段代码出了问题?

function draw_map (dataroute) {
var w = 500;
var h = 800;

var projection = d3.geo.transverseMercator()
                       .rotate([-27,-65,0])
                       .translate([w/2, h/2])
                       .scale([3500])

var path = d3.geo.path()
    .projection(projection);

var color = d3.scale.quantize()
              .range(["#c6dbef","#6baed6","#2171b5","#084594"])
              .domain([0, 100]);

var svg = d3.select("#map")
    .attr("width", w)
    .attr("height", h);

svg.append("rect")
    .attr("class", "background")
    .attr("width", w)
    .attr("height", h);

var g = svg.append("g")


queue()
    .defer(d3.json, dataroute)
    .await(ready);

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

    color.domain([
        d3.min(json.features, function(d) { return d.properties.value; }),
        d3.max(json.features, function(d) { return d.properties.value; })
    ]);

    console.log([
        d3.min(json.features, function(d) { return d.properties.value; }),
        d3.max(json.features, function(d) { return d.properties.value; })
    ]);
    // returns [98, 629725]

    g.selectAll("path")
        .data(json.features)
        .enter()
        .append("path")
        .attr("d",path)
        .style("fill", colormap)
        .style("stroke", "#08306b")
        .attr("class", "feature")
        .on("mouseover", function(d) {
            d3.select(this)
                .style("fill", "#08306b");

            var coordinates = [0, 0];
            coordinates = d3.mouse(this);
            var target = d3.select("#tooltip")
                           .style("left", coordinates[0] + "px")
                           .style("top", coordinates[1]-80 + "px");

            target.select("#name")
                  .text(d.properties.text);
            target.select("#stat")
                  .text(json.statdata_name + ": " + d.properties.value);

            d3.select("#tooltip").classed("hidden", false);
        })
        .on("mouseout", function(d){
        // If this is active node, keep the color on mouseout

            d3.select(this)
              .style("fill", colormap(d));
            d3.select("#tooltip").classed("hidden", true);
        });
}

//Return color for path
var colormap = function(d) {
    var value = d.properties.value;
    //console.log(value);
    // If value exists, map to color
    if (value) {
        return color(value);
        //console.log(color(value));
    // if not, set color red
    } else {
        console.log("Undefined: " + d.properties.text + " " + value)
        return "red";
    }
}
}

在使用.csv文件的原始版本中,代码如下:

//Width and height
var w = 800;
var h = 800;
active = d3.select(null);
previous = d3.select(null);

var projection = d3.geo.transverseMercator()
                       .rotate([-27,-65,0])
                       .translate([w/2, h/2])
                       .scale([3500])

var path = d3.geo.path()
    .projection(projection);

var color = d3.scale.quantize()
              .range(["#c6dbef","#6baed6","#2171b5","#084594"])
              .domain([0, 100]);

var svg = d3.select("#map")
    .attr("width", w)
    .attr("height", h);

svg.append("rect")
    .attr("class", "background")
    .attr("width", w)
    .attr("height", h)
    .on("click", reset);

var g = svg.append("g")

// Click to zoom
function clicked(d) {
  // If this node is zoomed, unzoom
  if (active.node() === this) {
    d3.select(this).style("fill",colormap)
    return reset();
  } else {
  // Otherwise recolor previous one, to avoid contamination
    previous.style("fill",colormap)
  }

  active.classed("active", false);
  active = d3.select(this).classed("active", true);  
  // store previous to uncolor it after clicking new one
  previous = d3.select(this)

  d3.select(this).style("fill","#08306b")

  var bounds = path.bounds(d),
      dx = bounds[1][0] - bounds[0][0],
      dy = bounds[1][1] - bounds[0][1],
      x = (bounds[0][0] + bounds[1][0]) / 2,
      y = (bounds[0][1] + bounds[1][1]) / 2,
      scale = .3 / Math.max(dx / w, dy / h),
      translate = [w / 2 - scale * x, h / 2 - scale * y];

  g.transition()
      .duration(750)
      .style("stroke-width", 1.5 / scale + "px")
      .attr("transform", "translate(" + translate + ")scale(" + scale + ")");
}

function reset() {
  active.classed("active", false);
  active = d3.select(null);

  g.transition()
      .duration(750)
      .style("stroke-width", "1px")
      .attr("transform", "");
}

queue()
    .defer(d3.json, "/static/finland.geojson")
    .defer(d3.csv, "/static/kuntavakiluku.csv")
    .await(ready);

var finland_geojson_data
var csv_data

function ready(error, json, data) {
    if (error) throw error;
    finland_geojson_data = json;
    csv_data = data;
    color.domain([
            d3.min(data, function(d) { return d.Vakiluku; }),
            d3.max(data, function(d) { return d.Vakiluku; })
            ]);
    console.log(data.length);
    for (var i = 0; i < data.length; i++) {
        var dataState = data[i].Kunta;
        var dataValue = parseInt(data[i].Vakiluku);
        //Find the corresponding state inside the GeoJSON
        for (var j = 0; j < json.features.length; j++) {
            var jsonState = json.features[j].properties.text;
            //console.log(jsonState)
            if (dataState == jsonState ) {
                //Copy the data value into the JSON
                json.features[j].properties.value = dataValue;
                //Stop looking through the JSON
                break;
            }
        }
    }
    g.selectAll("path")
    .data(json.features)
    .enter()
    .append("path")
    .attr("d",path)
    .style("fill", colormap)
    .style("stroke", "#08306b")
    .attr("class", "feature")
    .on("mouseover", function(d) {
        d3.select(this)
            .style("fill", "#08306b");

        var coordinates = [0, 0];
        coordinates = d3.mouse(this);
        var target = d3.select("#tooltip")
                       .style("left", coordinates[0] + "px")
                       .style("top", coordinates[1]-80 + "px");

        target.select("#kunta")
              .text(d.properties.text);
        target.select("#vakiluku")
              .text("Väestö: " + d.properties.value);

        d3.select("#tooltip").classed("hidden", false);
    })
    .on("mouseout", function(d){
    // If this is active node, keep the color on mouseout
    if (active.node() === this) {
        d3.select(this).style("fill","#08306b")
    } else {
        d3.select(this)
          .style("fill", colormap(d));
    }
        d3.select("#tooltip").classed("hidden", true);
    })
    .on("click",clicked);
}

//Return color for path
var colormap = function(d) {
    var value = d.properties.value;
    // If value exists, map to color
    if (value) {
        return color(value);
    // if not, set color red
    } else {
        console.log("Undefined: " + d.properties.text + " " + value)
        return "red";
    }
}

1 个答案:

答案 0 :(得分:1)

量化比例是具有谨慎范围的线性比例(正如您在注释中提供的@seb链接中所见)。

所以在你的情况下,如果你提供4种颜色,那么比喻说,域将分为4个部分(你的比例是一个“地图”)。

因此,域的第一个季度将是第一个颜色等。

在你的探索中,域名是[98,629725],所以第一种颜色将从98开始,结束于(629725-98)/ 4 + 98 = 157'504.75

在代码中:

var scale = d3.scale.quantize()
 .range(["#c6dbef", "#6baed6", "#2171b5", "#084594"])
 .domain([98, 629725]);

所以你可以测试一下,例如here(检查控制台输出!)

你可以看到157504第二次产生col1,157505。 因此,毫不奇怪,5000和90000属于同一“部分”。