在d3中绘制for循环中的多行

时间:2018-03-14 15:08:48

标签: d3.js svg plot

如果你只添加一次svg对象,网上有很多案例如何在d3中绘制几行,例如

   svg.selectAll("line")
   .data(dataset)
   .enter().append("line")
   .style("stroke", "black")  // colour the line
   .attr("x1", function(d) { console.log(d); return xScale(d.x1); })
   .attr("y1", function(d) { return yScale(d.y1); })
   .attr("x2", function(d) { return xScale(d.x2); })
   .attr("y2", function(d) { return yScale(d.y2); }); 

此图创建一行。我想在数组smth中创建许多不同的行,如

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

   for (a_ind=1; a_ind<3; a_ind++){
   dataset_a=dataset.filter(function(d) { return (d.a==a_ind)})

   svg.selectAll("line")
   .data(dataset_a) - //!!! using new dataset in each cycle
   .enter().append("line")
   .style("stroke", "black")  // colour the line
   .attr("x1", function(d) { console.log(d); return xScale(d.x1); })
   .attr("y1", function(d) { return yScale(d.y1); })
   .attr("x2", function(d) { return xScale(d.x2); })
   .attr("y2", function(d) { return yScale(d.y2); }); 
   }

我被告知这是不可能的。或者也许有办法?如果我想通过点击鼠标删除它,如何从dataset_a访问然后行?

2 个答案:

答案 0 :(得分:2)

好吧,如果你想绘制线条,我建议你追加...... <line> s!

具有D3输入选择的东西非常简单:附加元素的数量是数据数组中与任何元素都不匹配的对象数。

因此,您只需要一个包含多个对象的数据数组。例如,让我们创建50个:

var data = d3.range(50).map(function(d) {
  return {
    x1: Math.random() * 300,
    x2: Math.random() * 300,
    y1: Math.random() * 150,
    y2: Math.random() * 150,
  }
});

并且,如下面的演示我选择null,所有这些都将在输入选择中。这是演示:

var svg = d3.select("svg");
var data = d3.range(50).map(function(d) {
  return {
    x1: Math.random() * 300,
    x2: Math.random() * 300,
    y1: Math.random() * 150,
    y2: Math.random() * 150,
  }
});
var color = d3.scaleOrdinal(d3.schemeCategory20);
var lines = svg.selectAll(null)
  .data(data)
  .enter()
  .append("line")
  .attr("x1", function(d) {
    return d.x1
  })
  .attr("x2", function(d) {
    return d.x2
  })
  .attr("y1", function(d) {
    return d.y1
  })
  .attr("y2", function(d) {
    return d.y2
  })
  .style("stroke", function(_, i) {
    return color(i)
  })
  .style("stroke-width", 1);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

最后,提示:因为这是JavaScript,您可以在任何地方使用for循环。但是,使用for循环在D3代码中追加元素。这是不必要的,而不是惯用的。

话虽如此,无论谁告诉你这是不可能错了,显然是可能的。这是一个演示(但不要这样做,这是一个非常麻烦和丑陋的代码):

var svg = d3.select("svg");
var data = d3.range(50).map(function(d, i) {
  return {
    x1: Math.random() * 300,
    x2: Math.random() * 300,
    y1: Math.random() * 150,
    y2: Math.random() * 150,
    id: "id" + i
  }
});
var color = d3.scaleOrdinal(d3.schemeCategory20);

for (var i = 0; i < data.length; i++) {

  var filteredData = data.filter(function(d) {
    return d.id === "id" + i
  });

  var lines = svg.selectAll(null)
    .data(filteredData)
    .enter()
    .append("line")
    .attr("x1", function(d) {
      return d.x1
    })
    .attr("x2", function(d) {
      return d.x2
    })
    .attr("y1", function(d) {
      return d.y1
    })
    .attr("y2", function(d) {
      return d.y2
    })
    .style("stroke", function() {
      return color(i)
    })
    .style("stroke-width", 1);

}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

答案 1 :(得分:1)

我会做这样的事情。制作每个数据集(每行1个数据集),an array inside the final data array .enter().append()将正常工作。要在点击时删除该行,我添加了一个事件处理程序,它将选择刚刚单击的行并将其删除。

var data = [[dataset_a], [dataset_b], [dataset_c], [dataset_d], [dataset_e]];

var xValue = function(d){return d.x;}
var yValue = function(d){return d.y;}

var lineFunction = d3.line()
  .x(function(d) { return xScale(xValue(d)); })
  .y(function(d) { return yScale(yValue(d)); });

var lines = d3.select("svg").selectAll("path")

lines.data(data)
  .enter().append("path")
  .attr("d", lineFunction)
  .on("click", function(d){
    d3.select(this).remove();
  });