将嵌套数据与 D3.js 结合使用

发布于 2024-11-30 04:50:23 字数 2179 浏览 2 评论 0原文

我正在尝试使用 D3 显示漂亮的折线图。我遇到的问题是数据的格式。

我有以下数据(作为示例):

var data = [
    {
      label: "name",
      data: [[14444123, 0.012321312],
             [14444123, 0.012321312],
             [14444123, 0.012321312], ...]
    },{
      label: "another name",
      data: [[14444123, 0.012321312],
             [14444123, 0.012321312],
             [14444123, 0.012321312], ...]
    }
];

每个条目都包含它的名称以及带有点数组的数据属性(每个点表示为一个数组,其中 item[0] 是 x 时间戳,item[1]是值)。

我的问题是它无法正常工作。

这是我现在拥有的 D3 代码:

var w = options.width,
    h = options.height,
    p = options.padding,
    x = d3.scale.linear()
        .domain([0, 1])
        .range([0, w]),
    y = d3.scale.linear()
        .domain([options.ydomainstart, options.ydomainend])
        .range([h, 0]);

var vis = d3.select(options.element)
    .data(data)
   .append("svg:svg")
    .attr("width", w + p * 2)
    .attr("height", h + p * 2)
   .append("svg:g");

vis.append("svg:line")
    .attr("stroke", '#808080')
    .attr("x1", p)
    .attr("x2", p)
    .attr("y1", 0)
    .attr("y2", h - p);

vis.append("svg:line")
    .attr("stroke", '#808080')
    .attr("x1", p)
    .attr("x2", w)
    .attr("y1", h - p)
    .attr("y2", h - p);

var rules = vis.selectAll("g.rule")
    .data(data)
   .enter()
   .append("svg:text")
    .attr("x", w - p)
    .attr("y", function(d, i) { return 15 + i*12; })
    .attr("text-anchor", "end")
    .attr("font-size", 12)
    .attr("fill", function(d, i) { return defaultColors[i % 5]; })
    .text(function(d) { return d.label;});

var lines = rules.data(function(d, i) {
        return d.data;
    })
   .append("svg:path")
    .attr("stroke", function(d, i) { return defaultColors[i % 5]; })
    .attr("d", d3.svg.line()
    .x(function(d) {
        return x(d[0]);
    })
    .y(function(d) {
        return y(d[1]);
    }));

我遇到的问题出现在这部分代码中:

.x(function(d) {
    return x(d[0]);
})
.y(function(d) {
    return y(d[1]);
}));

“d”内的数据不是点数组 [x, y],而是每个数组内的每个值。

意思是,在第一项上,d 包含 x 坐标,在第二项上,它包含 y 坐标,在第三项上,它包含下一个点的 x 坐标,依此类推。

这就像它递归地进入数组,然后再次进入数组中的每个值。

我不知道如何解决这个问题。

I am trying to display a beautiful line graph using D3. The problem I have is with the format of the data.

I have the following data (as an example):

var data = [
    {
      label: "name",
      data: [[14444123, 0.012321312],
             [14444123, 0.012321312],
             [14444123, 0.012321312], ...]
    },{
      label: "another name",
      data: [[14444123, 0.012321312],
             [14444123, 0.012321312],
             [14444123, 0.012321312], ...]
    }
];

Each entry contains the name of it as well as a data attribute with array of points (each point is represented as an array, where item[0] is x timestamp and item[1] is the value).

My problem is that it is not working correctly.

This is the D3 code I have as of now:

var w = options.width,
    h = options.height,
    p = options.padding,
    x = d3.scale.linear()
        .domain([0, 1])
        .range([0, w]),
    y = d3.scale.linear()
        .domain([options.ydomainstart, options.ydomainend])
        .range([h, 0]);

var vis = d3.select(options.element)
    .data(data)
   .append("svg:svg")
    .attr("width", w + p * 2)
    .attr("height", h + p * 2)
   .append("svg:g");

vis.append("svg:line")
    .attr("stroke", '#808080')
    .attr("x1", p)
    .attr("x2", p)
    .attr("y1", 0)
    .attr("y2", h - p);

vis.append("svg:line")
    .attr("stroke", '#808080')
    .attr("x1", p)
    .attr("x2", w)
    .attr("y1", h - p)
    .attr("y2", h - p);

var rules = vis.selectAll("g.rule")
    .data(data)
   .enter()
   .append("svg:text")
    .attr("x", w - p)
    .attr("y", function(d, i) { return 15 + i*12; })
    .attr("text-anchor", "end")
    .attr("font-size", 12)
    .attr("fill", function(d, i) { return defaultColors[i % 5]; })
    .text(function(d) { return d.label;});

var lines = rules.data(function(d, i) {
        return d.data;
    })
   .append("svg:path")
    .attr("stroke", function(d, i) { return defaultColors[i % 5]; })
    .attr("d", d3.svg.line()
    .x(function(d) {
        return x(d[0]);
    })
    .y(function(d) {
        return y(d[1]);
    }));

The problem I have appears in this part of the code:

.x(function(d) {
    return x(d[0]);
})
.y(function(d) {
    return y(d[1]);
}));

The data inside 'd' is NOT the point array [x, y] but instead each value inside each array.

Meaning, on first item, d contains the x coordinate, on second item, it has the y coordinate, on third item, it contains the x coordinate on next point and so on.

It's like it's recursively going into the array, and then again for each value inside.

I have no idea how to fix this.

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

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

发布评论

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

评论(1

深府石板幽径 2024-12-07 04:50:23

这里有一些问题。

首先,您将 svg:path 元素附加到 svg:text 元素。在我看来,您似乎正在尝试使用“rule”类创建一个 svg:g 元素,但您的代码将选择 rules 定义为一组 svg:text 元素。首先创建 svg:g 元素,然后附加 svg:text 元素:

var rules = vis.selectAll("g.rule")
    .data(data)
  .enter().append("svg:g")
    .attr("class", "rule");

rules.append("svg:text")
    …

第二个问题是数据运算符每组计算一次,而不是每个元素计算一次。有关更多详细信息,请参阅 API 参考中的“对选择进行操作”部分。您在 vis 中有一个 svg:svg 元素,因此您在 rules 中有一组,因此您的数据函数仅被调用一次:

function(d, i) {
  return d.data;
}

然后,映射结果数据元素到 rules 选择...它已经定义了先前 selectAll 中的数据并在创建时追加。

简单的修复方法是使用 map 运算符而不是数据运算符,该运算符每个值都会计算一次元素而不是每组一次。

rules.append("svg:path")
    .map(function(d) { return d.data; })
    .attr("d", d3.svg.line()
    …

或者,您可以将数据直接传递到行生成器,但这需要您提前声明行生成器而不是内联它:

var line = d3.svg.line()
    .x(function(d) { return x(d[0]); })
    .y(function(d) { return y(d[1]); });

rules.append("svg:path")
    .attr("d", function(d) { return line(d.data); })
    …

希望这有帮助!

There’s a few problems here.

First, you’re appending an svg:path element to an svg:text element. It seems to me like you’re trying to create an svg:g element with the class "rule", but your code defines the selection rules as a set of svg:text elements. Create the svg:g elements first, and then append svg:text elements:

var rules = vis.selectAll("g.rule")
    .data(data)
  .enter().append("svg:g")
    .attr("class", "rule");

rules.append("svg:text")
    …

The second problem is that the data operator is evaluated once per group, rather than once per element. See the section "Operating on Selections" in the API reference for more details. You have one svg:svg element in vis, so you have one group in rules, and so your data function is only called once:

function(d, i) {
  return d.data;
}

Then, the resulting data elements are mapped to the rules selection… which already have defined data from the previous selectAll and append when they were created.

The simple fix is to use the map operator rather than the data operator, which is evaluated once per element rather than once per group.

rules.append("svg:path")
    .map(function(d) { return d.data; })
    .attr("d", d3.svg.line()
    …

Alternatively, you could pass the data directly to the line generator, but that requires you declaring the line generator ahead of time rather than inlining it:

var line = d3.svg.line()
    .x(function(d) { return x(d[0]); })
    .y(function(d) { return y(d[1]); });

rules.append("svg:path")
    .attr("d", function(d) { return line(d.data); })
    …

Hope this helped!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文