如何使用d3逐个在散点图上绘制/添加节点?

时间:2016-03-25 07:36:22

标签: javascript d3.js scatter-plot

我对D3.js和Javascript都很陌生。对不起,如果问一些愚蠢的话。 我刚刚浏览了D3的教程,现在可以绘制保存在 csv-file 中的所有数据。(由d3.csv函数加载)

我很好奇,有可能逐一绘制点,而不是将它们全部绘制一次?

var dataset;
d3.csv("testcase.csv", function(data) { 
    dataset = data;
    var w = $(window).width();
    var h = $(window).height();

    var svg = d3.select("body")
                .append("svg")
                .attr({
                    width: w,
                    height: h,
                });

    function draw(data){
        var circle = svg.selectAll("circle")
                    .data(data);

        circle.enter().append("circle")
              .attr({
                  "cx": data["x"],
                  "cy": data["y"],
                  "r": data["r"],
                  "fill": "rgb(0,0,0)",
              });
    }

    draw(dataset[0]);

    var index = 1;
    setInterval(function() {
        if(index<dataset.length){
          draw(dataset[index]);
          index++;
        }
     }, 1500);

这是我在此刻绘制点的方法,在csv文件中它保存了点的坐标,以及它的半径。例如:

x,y,r 100,100,50 200,100,30 400,300,20 500,400,50 470,800,40 400,600,40

我尝试使用setInterval函数让它逐个绘制点,但它没有绘制任何东西(包括应由draw(dataset[0])触发的第一个) 而且当使用console.log函数来检查值是否正确时,它似乎完全正常。 the output of console pad

出了什么问题?谢谢你的帮助:/

2 个答案:

答案 0 :(得分:3)

继Matthew的回答之后,如果你使用d3过渡而不是setInterval,那么你不必建立一个循环来单独处理节点,也避免了他描述的问题(至少在第一次传递,稍后再添加节点,您将再次需要数据密钥)

     var data = "x,y,r\n"+
"100,100,50\n"+
"200,100,30\n"+
"400,300,20\n"+
"500,400,50\n"+
"470,800,40\n"+
"400,600,40\n"
;

var dataset = d3.csv.parse (data);

var svg = d3.select("body")
.append("svg")
.attr({
  width: 600,
  height: 400,
});

var circle = svg.selectAll("circle")
.data(dataset);

circle.enter().append("circle")
  .each (function (d,i) {
  d3.select(this).transition()
    .delay(i * 1200)  // <- this does what you intended setinterval to do
    .attr({
    "cx": d.x,
    "cy": d.y,
    "r": d.r,
    "fill": "rgb(0,0,0)",
  });

});
;

http://jsfiddle.net/Qh9X5/7807/

答案 1 :(得分:0)

因此,您遇到了一个相当常见的逻辑错误,它是d3的新手。每次调用绘图函数时,都会重新绑定数据。然而,除了告诉d3关于新数据之外,这还消除了旧数据的d3内存。因此,你有效地告诉d3:这个新数据是真实的,忘记了我过去告诉你的任何数据。

好的,上面的内容有点过分了。

d3实际上并没有忘记你已经告诉过的内容。但是,它需要一种方法来了解什么是新的,已经存在的以及什么是旧的。为此,.data根据数据数组中的索引为每个数据分配一个键。因为每次绑定一个元素时,它总是得到一个0的键。因此,d3从不认为你要求它绑定一些新的东西。

要解决此问题,请将关键功能传递给dataas described in in the documentation

您的代码应该看起来像:

function draw(data, key){
    var circle = svg.selectAll("circle")
                .data(data, function(d){ return key; });

    circle.enter().append("circle")
          .attr({
              "cx": data["x"],
              "cy": data["y"],
              "r": data["r"],
              "fill": "rgb(0,0,0)",
          });
}

draw(dataset[0], 0);

var index = 1;
setInterval(function() {
    if(index<dataset.length){
      draw(dataset[index], index);
      index++;
    }
 }, 1500);

这有道理吗?我强烈建议您仔细阅读文档。这是我学习的方式,而且随着文档的发展,它的布局非常好,易于理解,并且有很多例子。