我有一个D3堆积区域图表,我试图在刷牙时重新计算Y轴。问题在于,当我重新计算Y轴的最大值时,它不是所有不同层的组合,它只是最后一层。例如,如果我刷了1/17和1/20日期,我会得到45作为最大Y轴值而不是95(50 + 45)。这是数据:
[
{
"key": "Failed",
"vis": "1",
"values": [
{
"date": "2014-01-17T05:00:00.000Z",
"total": 50
},
{
"date": "2014-01-20T05:00:00.000Z",
"total": 23
}
]
},
{
"key": "Success",
"vis": "1",
"values": [
{
"date": "2014-01-17T05:00:00.000Z",
"total": 45
},
{
"date": "2014-01-20T05:00:00.000Z",
"total": 12
}
]
}
]
以下是我正在使用的一些示例代码。我知道外循环的每次迭代都消灭了之前的循环,但我不确定如何修复它:
for (var i = 0; i < dataSeries.length; i++) {
if(dataSeries[i]['vis'] === "1") {
dataFiltered = dataSeries[i]['values'].filter(function(d) {
if((d.date >= main_x.domain()[0]) && (d.date <= main_x.domain()[1])) {
// this is just returning the biggest total in the date range from the last layer (i.e.: 'Failed'),
// not the greatest of all the layers for that day
return yValue(d);
}
});
}
}
这是fiddle - 如果您刷过一系列日期,Y轴最大值将不正确,图表顶部将被切断。谢谢你的帮助。
答案 0 :(得分:1)
你在dataFiltered
的每次迭代中都在dataSeries
。在dataSeries
中,您的堆栈中的每个级别都有一个元素,因此这意味着dataFiltered
将只包含最后一个元素的值。
但是,即使您解决了这个问题,您设置y比例域的方式仍然有些奇怪:
main_y.domain([0, d3.sum(dataFiltered.map(function(d) { return d.total; }))]);
这是将域的上限值设置为刷新范围内所有数据点的总和。您可能真正想要的是该范围内的最大完全堆叠高度。
您可以这样做:
var dataFiltered = dataSeries.map(function(series) {
return series.values.filter(function(d) {
if((d.date >= main_x.domain()[0]) && (d.date <= main_x.domain()[1])) {
return yValue(d);
}
});
});
此时dataFiltered
看起来就像dataSeries
,除了它应该只包含有刷范围的数据点。
现在您需要将其内部转出,以便数据点以堆栈方式定向,而不是以系列方式定位:
var dataStackSums = {};
dataFiltered.forEach(function(series) {
series.values.forEach(function(d) {
if (!dataStackSums[d.date]) { dataStackSums[d.date] = 0; }
dataStackSums[d.date] += d.total;
});
});
此时dataStackSums
包含每个X轴值(日期)的属性,其值表示该堆栈的总和Y轴。从这里你只需要确定最大堆栈:
var max = 0;
Object.keys(dataStackSums).forEach(function(key) {
max = Math.max(max, dataStackSums[key]);
});
然后您可以设置域名:
main_y.domain([0, max]);
请注意,为了清晰起见,我打破了这些步骤,但您可以将过滤和堆栈定位分解为一步,以提高效率。