在d3中使用相邻数据值 [英] Using adjacent data values in d3

查看:65
本文介绍了在d3中使用相邻数据值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用D3可视化一些随时间更新的数据,并且我有一个(x,y)坐标列表;例如:

I am using D3 to visualize some data that updates with time, and I have a list of (x,y) coordinates; for example:

[[0.1,0.2],
 [0.3,0.4],
 [0.5,0.4],
 [0.7,0.2]]

我想从(0,0)到每个相邻坐标对中绘制三角形,例如,第一个三角形的坐标为(0,0),(0.1,0.2),(0.3,0.4)并且第二个三角形的坐标为(0,0),(0.3,0.4),(0.5,0.4)等.

I would like to draw triangles from (0,0) to each of the pairs of adjacent coordinates, for example, the first triangle would have coordinates (0,0), (0.1,0.2), (0.3,0.4) and the second triangle would have coordinates (0,0), (0.3,0.4), (0.5,0.4) and so on.

我的问题是,是否有一种方法可以访问D3中的相邻"值? D3范例似乎传递了一个函数,该函数可以分别访问每个数据值.因此,我能够做到这一点,但是只能通过从各个点的整个数据集中显式构造一个新的三角形坐标数据集来实现:

My question is whether there is a way to access "neighboring" values in D3; the D3 paradigm seems to be to pass in a function that gets access to each data value separately. So I was able to do this, but only by explicitly constructing a new data set of the triangle coordinates from the entire data set of the individual points:

var margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = 500 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
    
// add the graph canvas to the body of the webpage
var svg = d3.select("div#plot1").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);
var axis = svg.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
var xsc = d3.scaleLinear()
          .domain([-2, 2])  // the range of the values to plot
          .range([ 0, width ]);        // the pixel range of the x-axis

var ysc = d3.scaleLinear()
          .domain([-2, 2])
          .range([ height, 0 ]);
var closedLine = d3.line()
   .x(function(d){ return xsc(d[0]); })
   .y(function(d){ return ysc(d[1]); })
   .curve(d3.curveLinearClosed);

function attrfunc(f,attr) {
  return function(d) {
    return f(d[attr]);
  };
}


function doit(data)
{
  var items = axis.selectAll("path.item")
    .data(data);
  items.enter()
      .append("path")
        .attr("class", "item")
      .merge(items)
        .attr("d", attrfunc(closedLine, "xy"))
        .attr("stroke", "gray")
        .attr("stroke-width", 1)
        .attr("stroke-opacity", function(d) { return 1-d.age;})
        .attr("fill", "gray")
        .attr("fill-opacity", function(d) {return 1-d.age;});
  items.exit().remove();
}

var state = {
  t: 0,
  theta: 0,
  omega: 0.5,
  A: 1.0,
  N: 60,
  history: []
}
d3.timer(function(elapsed)
{
  var S = state;
  if (S.history.length > S.N)
    S.history.shift();
  var dt = Math.min(0.1, elapsed*1e-3);
  S.t += dt;
  S.theta += S.omega * dt;
  var sample = {
    t: S.t,
    x: S.A*(Math.cos(S.theta)+0.1*Math.cos(6*S.theta)),
    y: S.A*(Math.sin(S.theta)+0.1*Math.sin(6*S.theta))
  }
  S.history.push(sample);

  // Create triangular regions
  var data = [];
  for (var k = 0; k < S.history.length-1; ++k)
  {
     var pt1 = S.history[k];
     var pt2 = S.history[k+1];
		 data.push({age: (S.history.length-1-k)/S.N,
                xy:
                 [[0,0],
                  [pt1.x,pt1.y],
                  [pt2.x,pt2.y]]
               });
  }
  doit(data);
});

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.8.0/d3.min.js"></script>
<div id="plot1">
</div>

推荐答案

您可以使用第二个参数(即索引)获取数据数组中的任何点.

You can get any point in the data array using the second argument, which is the index.

在将基准传递给任何D3方法时,通常使用名为d(用于基准)的参数,实际上,您使用的是data[i]i是当前索引.您可以更改此索引以获取当前基准之前或之后的数据点.

When you pass a datum to any D3 method, traditionally using a parameter named d (for datum), you are in fact using data[i], i being the current index. You can change this index to get data points before or after the current datum.

因此,在任何D3方法中:

Thus, in any D3 method:

.attr("foo", function(d, i){
    console.log(d)//this is the current datum
    console.log(data[i])//this is the same current datum!
    console.log(data[i + 1])//this is the next (adjacent) datum
});

以下是显示此内容的简单代码段:

Here is a simple snippet showing this:

var data = ["foo", "bar", "baz", "foobar", "foobaz"];

var foo = d3.selectAll("foo")
  .data(data)
  .enter()
  .append("foo")
  .attr("foo", function(d, i) {
    if (data[i + 1]) {
      console.log("this datum is " + d + ", the next datum is " + data[i + 1]);
    }
  })

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

看看if语句:我们必须检查是否有data[i + 1],因为,当然,最后一个数据点之后没有相邻数据.

Have a look at the if statement: we have to check if there is a data[i + 1] because, of course, the last data point has no adjacent data after it.

以下是使用您的数据数组的演示:

Here is a demo using your data array:

var svg = d3.select("svg");

var scale = d3.scaleLinear()
  .domain([-1, 1])
  .range([0, 150]);

var data = [
  [0.1, 0.2],
  [0.3, 0.4],
  [0.5, 0.4],
  [0.7, 0.2]
];

var triangles = svg.selectAll("foo")
  .data(data)
  .enter()
  .append("polygon");

triangles.attr("stroke", "teal")
  .attr("stroke-width", 2)
  .attr("fill", "none")
  .attr("points", function(d, i) {
    if (data[i + 1]) {
      return scale(0) + "," + scale(0) + " " + scale(data[i][0]) + "," + scale(data[i][1]) + " " + scale(data[i + 1][0]) + "," + scale(data[i + 1][1]) + " " + scale(0) + "," + scale(0);
    }
  })

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

PS:我没有使用您的代码段,因为我正在使用多边形绘制三角形,但是原理是相同的.

PS: I'm not using your snippet because I'm drawing the triangles using polygons, but the principle is the same.

这篇关于在d3中使用相邻数据值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆