散点图上的plot/add节点如何使用d3一一对应?

How to use d3 to plot/add node on scatter plot one by one?

我对 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

怎么了?感谢您的帮助:/

所以,您遇到了一个相当常见的逻辑错误,它是 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);

这有道理吗?我强烈建议您通读文档。这就是我学习的方式,随着文档的发展,它的布局非常好,易于理解,还有大量示例。

根据 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/