在 D3.js 中绘制多条线

发布于 2024-12-23 14:59:15 字数 1422 浏览 2 评论 0原文

到目前为止,我一直在使用循环将线条元素添加到 D3 可视化中,但这似乎不符合 API 的精神。

假设我有一些数据,

var data = {time: 1, value: 2, value2: 5, value3: 3,value4: 2},
           {time: 2, value: 4, value2: 9, value3: 2,value4: 4},
           {time: 3, value: 8, value2:12, value3: 2,value4:15}]);

我想要四行,时间作为所有 4 行的 X。

我可以做这样的事情:

var l = d3.svg.line()
        .x(function(d){return xScale(d[keys[0]]);})
        .y(function(d,i){
            return yScale(d[keys[1]]);})
        .interpolate("basis");
var l2 = d3.svg.line()
        .x(function(d){return xScale(d[keys[0]]);})
        .y(function(d,i){
            return yScale(d[keys[2]]);})
        .interpolate("basis");
var l3 = d3.svg.line()
        .x(function(d){return xScale(d[keys[0]]);})
        .y(function(d,i){
            return yScale(d[keys[3]]);})
        .interpolate("basis");  
var l4 = d3.svg.line()
        .x(function(d){return xScale(d[keys[0]]);})
        .y(function(d,i){
            return yScale(d[keys[4]]);})
        .interpolate("basis");

然后将它们一一相加(或通过循环)。

var line1 = group.selectAll("path.path1")
        .attr("d",l(data));
var line2 = group.selectAll("path.path2")
        .attr("d",l2(data));
var line3 = group.selectAll("path.path3")
        .attr("d",l3(data));
var line4 = group.selectAll("path.path4")
        .attr("d",l4(data));

有没有更好更通用的方法来添加这些路径?

Up until now, I've been using loops to add line elements to a D3 visualization, but this doesn't seem in the spirit of the API.

Let's say I have got some data,

var data = {time: 1, value: 2, value2: 5, value3: 3,value4: 2},
           {time: 2, value: 4, value2: 9, value3: 2,value4: 4},
           {time: 3, value: 8, value2:12, value3: 2,value4:15}]);

I'd like four lines, with time as the X for all 4.

I can do something like this:

var l = d3.svg.line()
        .x(function(d){return xScale(d[keys[0]]);})
        .y(function(d,i){
            return yScale(d[keys[1]]);})
        .interpolate("basis");
var l2 = d3.svg.line()
        .x(function(d){return xScale(d[keys[0]]);})
        .y(function(d,i){
            return yScale(d[keys[2]]);})
        .interpolate("basis");
var l3 = d3.svg.line()
        .x(function(d){return xScale(d[keys[0]]);})
        .y(function(d,i){
            return yScale(d[keys[3]]);})
        .interpolate("basis");  
var l4 = d3.svg.line()
        .x(function(d){return xScale(d[keys[0]]);})
        .y(function(d,i){
            return yScale(d[keys[4]]);})
        .interpolate("basis");

And then add these one by one (or by a loop).

var line1 = group.selectAll("path.path1")
        .attr("d",l(data));
var line2 = group.selectAll("path.path2")
        .attr("d",l2(data));
var line3 = group.selectAll("path.path3")
        .attr("d",l3(data));
var line4 = group.selectAll("path.path4")
        .attr("d",l4(data));

Is there a better more general way of adding these paths?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

攒一口袋星星 2024-12-30 14:59:15

是的。首先,我将重组您的数据以便于迭代,如下所示:

var series = [
  [{time: 1, value: 2}, {time: 2, value: 4}, {time: 3, value: 8}],
  [{time: 1, value: 5}, {time: 2, value: 9}, {time: 3, value: 12}],
  [{time: 1, value: 3}, {time: 2, value: 2}, {time: 3, value: 2}],
  [{time: 1, value: 2}, {time: 2, value: 4}, {time: 3, value: 15}]
];

现在您只需要一条通用行:

var line = d3.svg.line()
    .interpolate("basis")
    .x(function(d) { return x(d.time); })
    .y(function(d) { return y(d.value); });

然后您可以一次性添加所有路径元素:

group.selectAll(".line")
    .data(series)
  .enter().append("path")
    .attr("class", "line")
    .attr("d", line);

如果您想让数据结构格式更小,您可以还将时间提取到单独的数组中,然后使用二维数组作为值。看起来像这样:

var times = [1, 2, 3];

var values = [
  [2, 4, 8],
  [5, 9, 12],
  [3, 2, 2],
  [2, 4, 15]
];

由于矩阵不包含时间值,因此您需要从行生成器的 x 访问器中查找它。另一方面,y 访问器被简化,因为您可以将矩阵值直接传递到 y 尺度:

var line = d3.svg.line()
    .interpolate("basis")
    .x(function(d, i) { return x(times[i]); })
    .y(y);

创建元素保持不变:

group.selectAll(".line")
    .data(values)
  .enter().append("path")
    .attr("class", "line")
    .attr("d", line);

Yes. First I would restructure your data for easier iteration, like this:

var series = [
  [{time: 1, value: 2}, {time: 2, value: 4}, {time: 3, value: 8}],
  [{time: 1, value: 5}, {time: 2, value: 9}, {time: 3, value: 12}],
  [{time: 1, value: 3}, {time: 2, value: 2}, {time: 3, value: 2}],
  [{time: 1, value: 2}, {time: 2, value: 4}, {time: 3, value: 15}]
];

Now you need just a single generic line:

var line = d3.svg.line()
    .interpolate("basis")
    .x(function(d) { return x(d.time); })
    .y(function(d) { return y(d.value); });

And, you can then add all of the path elements in one go:

group.selectAll(".line")
    .data(series)
  .enter().append("path")
    .attr("class", "line")
    .attr("d", line);

If you want to make the data structure format smaller, you could also extract the times into a separate array, and then use a 2D array for the values. That would look like this:

var times = [1, 2, 3];

var values = [
  [2, 4, 8],
  [5, 9, 12],
  [3, 2, 2],
  [2, 4, 15]
];

Since the matrix doesn't include the time value, you need to look it up from the x-accessor of the line generator. On the other hand, the y-accessor is simplified since you can pass the matrix value directly to the y-scale:

var line = d3.svg.line()
    .interpolate("basis")
    .x(function(d, i) { return x(times[i]); })
    .y(y);

Creating the elements stays the same:

group.selectAll(".line")
    .data(values)
  .enter().append("path")
    .attr("class", "line")
    .attr("d", line);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文