如何在 dc.js/reductio/crossfilter 中生成滚动标准折线图
How to generate a rolling std line chart in dc.js/reductio/crossfilter
我想显示一个折线图,其中包含一个日期区间的值总和的滚动标准。
生成crossfilter/reductio对象的代码是:
myCrossfilter = crossfilter(data);
function getRunningDates(numDays) {
return function getDates(d) {
var s = d.ValueDate;
var e = new Date(s);
e.setDate(e.getDate() + numDays);
a = [];
while (s < e) {
a.push(s);
s = new Date(s.setDate(
s.getDate() + 1
))
}
return a;
}
}
var dim1 = myCrossfilter.dimension(getRunningDates(20), true);
var dim2 = myCrossfilter.dimension(dc.pluck("ValueDate"));
var group1 = dim1.group();
var group2 = dim2.group();
var reducerRolling = reductio()
.std("value");
reducerRolling(group1);
var reducer = reductio()
.sum("value")
reducer(group2);
我已将所有内容放入 jsFiddle 以说明我的意思(不相关的问题:我不明白图表上的日期如何超出 dateToInit
中定义的 [=] 变量28=]).
我希望底部图表是顶部图表中值的滚动 std
。最终发生的是底部图中的 std
计算没有首先进行 sum
聚合(我理解这是有道理的)。
有没有办法将一个组用作另一个组的维度?
如果没有,如何实现我想要做的事情?
好的,所以我根据 Gordon 建议的 'fake group' 方法想出了一个解决方案。
我已将 jsFiddle 更新为可用版本。
它的要点是定义自定义减少函数:
reduceAddRunning = function(p,v) {
if (!p.datesData.hasOwnProperty(v.ValueDate)) {
p.datesData[v.ValueDate]=0;
}
p.datesData[v.ValueDate]+=+v.value;
p.value+=+v.value;
return(p);
};
reduceRemoveRunning = function(p,v) {
p.datesData[v.ValueDate]-=+v.value;
p.value-=+v.value;
return(p);
};
reduceInitRunning = function(p,v) {
return({
value:0,
datesData:{},
});
};
然后像这样建立一个假群:
var running_group = function (source_group,theRunningFn) {
return {
all:function () {
return source_group.all().map(function(d) {
var arr = [];
for (var date in d.value.datesData) {
if (d.value.datesData.hasOwnProperty(date)) {
arr.push(d.value.datesData[date]);
}
}
return {key:d.key, value:theRunningFn(arr)};
});
}
};
}
在我的例子中 theRunningFn
是 math.std
。
我还剩下 2 个问题,我想这将是一个新问题的基础:
- 这很慢。很高兴听到加快速度的建议。 (我的图表更新过去很快速,现在很慢。仍然可用但很慢)
- 我不知道如何处理边缘情况。时间序列开头显示的值没有意义,因为它们基于较少的历史记录。当我按日期过滤数据时,同样的问题也适用。
编辑:以下是基于戈登评论的更好解决方案(再次!)。
只需做一个常规总和组并应用以下假组函数:
var running_group_2 = function (source_group,numDays,theRunningFn) {
return {
all:function () {
var source_arr = source_group.all();
var keys = source_arr.map(function(d) {return d.key;});
var values = source_arr.map(function(d) {return d.value;});
var output_arr = [];
for (var i = numDays;i<source_arr.length;i++) {
if (i<numDays) {
output_arr.push({key:keys[i],value:0});
} else {
output_arr.push({
key:keys[i],
value:theRunningFn(values.slice(i-numDays,i))
});
}
}
return output_arr;
}
};
}
它解决了速度问题(因为它不那么麻烦并且不存储所有要使用的每日值,而是使用已经聚合的值)和边缘情况(即使它不容易推广到我的范围之外就边缘情况而言的情况:当我没有足够的点数来计算 运行 变量时,我不会显示值。
这是第二个(更适合我的目的)解决方案的 jsFiddle。
我想显示一个折线图,其中包含一个日期区间的值总和的滚动标准。
生成crossfilter/reductio对象的代码是:
myCrossfilter = crossfilter(data);
function getRunningDates(numDays) {
return function getDates(d) {
var s = d.ValueDate;
var e = new Date(s);
e.setDate(e.getDate() + numDays);
a = [];
while (s < e) {
a.push(s);
s = new Date(s.setDate(
s.getDate() + 1
))
}
return a;
}
}
var dim1 = myCrossfilter.dimension(getRunningDates(20), true);
var dim2 = myCrossfilter.dimension(dc.pluck("ValueDate"));
var group1 = dim1.group();
var group2 = dim2.group();
var reducerRolling = reductio()
.std("value");
reducerRolling(group1);
var reducer = reductio()
.sum("value")
reducer(group2);
我已将所有内容放入 jsFiddle 以说明我的意思(不相关的问题:我不明白图表上的日期如何超出 dateToInit
中定义的 [=] 变量28=]).
我希望底部图表是顶部图表中值的滚动 std
。最终发生的是底部图中的 std
计算没有首先进行 sum
聚合(我理解这是有道理的)。
有没有办法将一个组用作另一个组的维度? 如果没有,如何实现我想要做的事情?
好的,所以我根据 Gordon 建议的 'fake group' 方法想出了一个解决方案。
我已将 jsFiddle 更新为可用版本。
它的要点是定义自定义减少函数:
reduceAddRunning = function(p,v) {
if (!p.datesData.hasOwnProperty(v.ValueDate)) {
p.datesData[v.ValueDate]=0;
}
p.datesData[v.ValueDate]+=+v.value;
p.value+=+v.value;
return(p);
};
reduceRemoveRunning = function(p,v) {
p.datesData[v.ValueDate]-=+v.value;
p.value-=+v.value;
return(p);
};
reduceInitRunning = function(p,v) {
return({
value:0,
datesData:{},
});
};
然后像这样建立一个假群:
var running_group = function (source_group,theRunningFn) {
return {
all:function () {
return source_group.all().map(function(d) {
var arr = [];
for (var date in d.value.datesData) {
if (d.value.datesData.hasOwnProperty(date)) {
arr.push(d.value.datesData[date]);
}
}
return {key:d.key, value:theRunningFn(arr)};
});
}
};
}
在我的例子中 theRunningFn
是 math.std
。
我还剩下 2 个问题,我想这将是一个新问题的基础:
- 这很慢。很高兴听到加快速度的建议。 (我的图表更新过去很快速,现在很慢。仍然可用但很慢)
- 我不知道如何处理边缘情况。时间序列开头显示的值没有意义,因为它们基于较少的历史记录。当我按日期过滤数据时,同样的问题也适用。
编辑:以下是基于戈登评论的更好解决方案(再次!)。
只需做一个常规总和组并应用以下假组函数:
var running_group_2 = function (source_group,numDays,theRunningFn) {
return {
all:function () {
var source_arr = source_group.all();
var keys = source_arr.map(function(d) {return d.key;});
var values = source_arr.map(function(d) {return d.value;});
var output_arr = [];
for (var i = numDays;i<source_arr.length;i++) {
if (i<numDays) {
output_arr.push({key:keys[i],value:0});
} else {
output_arr.push({
key:keys[i],
value:theRunningFn(values.slice(i-numDays,i))
});
}
}
return output_arr;
}
};
}
它解决了速度问题(因为它不那么麻烦并且不存储所有要使用的每日值,而是使用已经聚合的值)和边缘情况(即使它不容易推广到我的范围之外就边缘情况而言的情况:当我没有足够的点数来计算 运行 变量时,我不会显示值。
这是第二个(更适合我的目的)解决方案的 jsFiddle。