我有一个基于JSON有效负载生成的多重系列折线图的基本演示。它按预期工作,但我感觉我没有充分利用D3库来正确解析或绑定数据。
嵌套数据的最佳格式是什么?例如,对象的对象,数组的数组等?
http://jsfiddle.net/thinkin3d/nc2sgmcz/
JSON有效负载如下所示:
var data = {
"Series 1": {
"20141020": 3.5003987252672744,
"20141019": 2.505802351020492,
"20141018": 1.511804171940014},
"Series 2": {
"20141008": 3.386547593121662,
"20141009": 2.1369256424188166,
"20141010": 0.88701610875722286},
"Series 3": {
"20141024": 1.041445076319178,
"20141025": 1.1241181263211502,
"20141026": 1.38667149365412}
}
我调用d3.entries将其转换为数组:
var entries = d3.entries(data);
然后我再次调用d3.entries,每次我想访问第二层中的特定键值对:
var entry = d3.entries(d.value);
我多次打电话给我并重复自己,这就是为什么我觉得必须有一种我不知道的更好的方式。
我没有使用D3库的哪些部分?
理想情况下,我希望能够维护JSON有效负载格式,但如果在发送之前进行简单的重新排列会让D3更容易,那么我全都是耳朵!
代码:
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y%m%d").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([0, height]);
var color = d3.scale.category20();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var area = d3.svg.area()
.interpolate("basis")
.x(function (d) {
return x(parseDate(d.key));
})
.y0(height)
.y1(function (d) {
return y(d.value);
});
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var entries = d3.entries(data);
color.domain(entries.map(function (d) {
return d;
}));
var minX = d3.min(entries, function (kv) {
var entry = d3.entries(kv.value);
return d3.min(entry, function (d) {
return parseDate(d.key);
})
});
var maxX = d3.max(entries, function (kv) {
var entry = d3.entries(kv.value);
return d3.max(entry, function (d) {
return parseDate(d.key);
})
});
var minY = d3.min(entries, function (kv) {
var entry = d3.entries(kv.value);
return d3.min(entry, function (d) {
return d.value;
})
});
var maxY = d3.max(entries, function (kv) {
var entry = d3.entries(kv.value);
return d3.max(entry, function (d) {
return d.value;
})
});
x.domain([minX, maxX]);
y.domain([minY, maxY]);
var element = svg.selectAll(".element")
.data(entries)
.enter().append("g")
.attr("class", "element");
element.append("path")
.attr("class", "area")
.attr("d", function (d) {
var entry = d3.entries(d.value);
return area(entry);
})
.style("fill", function (d) {
return color(d.key);
});
element.append("text")
.datum(function (d) {
var entry = d3.entries(d.value);
return {
name: d.key,
date: parseDate(entry[entry.length - 1].key),
value: entry[entry.length - 1].value
};
})
.attr("transform", function (d) {
return "translate(" + x(d.date) + "," + y(d.value) + ")";
})
.attr("x", -6)
.attr("dy", ".35em")
.text(function (d) {
return d.name;
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
答案 0 :(得分:0)
如果首先获取所有x和y值,然后获取这些数组的范围,则可以大大简化代码。这是相对简单的,唯一需要注意的是你需要展平嵌套数组:
var allX = d3.values(data).map(d3.keys)
.reduce(function(a,b) { return a.concat(b); }).map(parseDate);
var allY = d3.values(data).map(d3.values)
.reduce(function(a,b) { return a.concat(b); });
x.domain(d3.extent(allX));
y.domain(d3.extent(allY));
这将获取初始数据结构中的值以及每个键或值中的值,具体取决于您是否需要x或y。然后使用.reduce()
展平此嵌套数组。对于y,我们已经完成了,对于x,日期被解析。然后,您可以直接使用d3.extend()
获取域的值。
完整演示here。