使用D3.js嵌套数据 [英] Using nested data with D3.js

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

问题描述

我想用D3显示一个美丽的线形图。我有数据格式的问题。



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

  var data = [
{
label:name,
data:[[14444123,0.012321312],
[14444123 ,0.012321312],
[14444123,0.012321312],...]
},{
标签:另一个名称,
数据:[[14444123,0.012321312],
[14444123,0.012321312],
[14444123,0.012321312],...]
}
];

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



我的问题是它不能正常工作。 p>

这是我现在的D3代码:

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

var vis = d3.select(options.element)
.data(data)
.append(svg:svg)
.attr ,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% ;})
.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 (d){
return y(d [1]);
})));

'd'内的数据不是点阵列[x,y]每个数组。



含义,第一项,d包含x坐标,第二项,它有y坐标,第三项,它包含x坐标下一个点等等。



这就像是递归地进入数组,然后再对每个值的内部。



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

解决方案

这里有一些问题。



首先,将svg:path元素附加到svg:text元素。在我看来,像你试图创建一个svg:g元素与类规则,但你的代码定义选择 rules 作为一组svg:text元素。先创建svg:g元素,然后附加svg:text元素:

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

rules.append(svg:text)
...

第二个问题是数据运算符每个组评估一次,而不是每个元素一次。有关详细信息,请参阅API参考中的选择操作部分。您在 vis 中有一个svg:svg元素,因此您在 rules 中有一个组,因此您的数据函数只调用一次:

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

然后,结果数据元素映射到



一个简单的解决方法是使用

href =https://github.com/mbostock/d3/wiki/Selections#wiki-map>地图运算符,而不是数据运算符,每个元素评估一次,而不是每个组一次。 p>

  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 {return y(d [1]);});

rules.append(svg:path)
.attr(d d.data); })
...

希望这有帮助!


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.

解决方案

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!

这篇关于使用D3.js嵌套数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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