我正在尝试使用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坐标,依此类推。
就像它递归进入数组一样,然后再次进入内部的每个值。
我不知道如何解决这个问题。
答案 0 :(得分:10)
这里有一些问题。
首先,您将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参考中的"Operating on Selections"部分。您在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); })
…
希望这有帮助!