dc.js 和 crossfilter 自定义 valueAccessor
dc.js and crossfilter custom valueAccesor
我正在尝试按小时绘制平均计数图表,自定义 reduce 函数在这里几乎可以正常工作 https://jsfiddle.net/dolomite/6eeahs6z/
有一个问题是有些时间没有 activity,例如数据中可能有三个星期日,但只有两个 activity:
日期、小时、计数
周日 02/07/17, 22, 5
2017 年 7 月 9 日,22 日,3 日
数据包含日期 25/07/17,但没有第 22 小时的记录。因此,周日第 22 小时的正确平均值应该是 2.66,但当前方法生成的平均值是 4。
所以简而言之,我想弄清楚如何获得每小时的总计数,然后除以数据中的天数,无论所选日期是否有每小时的记录。
当前小时维度和自定义减少为:
hourDim = ndx.dimension(function (d) {
return d.EventHour;
})
hourAvgGroup = hourDim.group().reduce(
function (p, v) { // add
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) + 1 : 1);
//p.avg = average_map(p.map);
return p;
},
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
if(p.map.has(day) && p.map.get(day) == 0) p.map.remove(day);
//p.avg = average_map(p.map);
return p;
},
function () { // init
return { map: d3.map() };
}
)
平均值在图表 valueAccessor 中计算如下:
.valueAccessor(function(d){ return average_map(d.value.map)})
在哪里
function average_map(m) {
var sum = 0;
m.forEach(function(k, v) {
sum += v;
});
return m.size() ? sum / m.size() : 0;
}
如果有人试图做类似的事情,我创建了一个维度来保存数据中的所有记录:
allDim = ndx.dimension(function (d) {
return typeof Modality === 'string';
})
然后创建了一个组来保存数据中唯一天数的映射:
dayCountGroup = allDim.group().reduce(
function (p, v) { // add
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) + 1 : 1);
return p;
},
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
if(p.map.has(day) && p.map.get(day) == 0) p.map.remove(day);
return p;
},
function () { // init
return { map: d3.map() };
}
)
小时维度和分组为:
hourDim = ndx.dimension(function (d) {
return d.EventHour;
})
hourAvgGroup = hourDim.group().reduce(
function (p, v) { // add
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) + 1 : 1);
return p;
},
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
if(p.map.has(day) && p.map.get(day) == 0) p.map.remove(day);
return p;
},
function () { // init
return { map: d3.map() };
}
)
然后在我使用的条形图的值访问器中:
.valueAccessor(function(d){ return sum_map(d.value.map)/size_array_of_maps(dayCountGroup.top(Infinity)) ? sum_map(d.value.map)/size_array_of_maps(dayCountGroup.top(Infinity)) : 0})
其中使用的两个函数是:
function sum_map(m) {
var sum = 0;
m.forEach(function(k, v) {
sum += v;
});
return m.size() ? sum : 0;
}
function size_array_of_maps(myObject) {
var count = 0;
myObject.forEach(function(key,value) {
count += key.value.map.size();
})
return count;
}
我敢肯定这里有很多冗余代码,但是 Fiddle 似乎可以正常工作,我稍后会整理它:)
我正在尝试按小时绘制平均计数图表,自定义 reduce 函数在这里几乎可以正常工作 https://jsfiddle.net/dolomite/6eeahs6z/
有一个问题是有些时间没有 activity,例如数据中可能有三个星期日,但只有两个 activity:
日期、小时、计数
周日 02/07/17, 22, 5
2017 年 7 月 9 日,22 日,3 日
数据包含日期 25/07/17,但没有第 22 小时的记录。因此,周日第 22 小时的正确平均值应该是 2.66,但当前方法生成的平均值是 4。
所以简而言之,我想弄清楚如何获得每小时的总计数,然后除以数据中的天数,无论所选日期是否有每小时的记录。
当前小时维度和自定义减少为:
hourDim = ndx.dimension(function (d) {
return d.EventHour;
})
hourAvgGroup = hourDim.group().reduce(
function (p, v) { // add
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) + 1 : 1);
//p.avg = average_map(p.map);
return p;
},
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
if(p.map.has(day) && p.map.get(day) == 0) p.map.remove(day);
//p.avg = average_map(p.map);
return p;
},
function () { // init
return { map: d3.map() };
}
)
平均值在图表 valueAccessor 中计算如下:
.valueAccessor(function(d){ return average_map(d.value.map)})
在哪里
function average_map(m) {
var sum = 0;
m.forEach(function(k, v) {
sum += v;
});
return m.size() ? sum / m.size() : 0;
}
如果有人试图做类似的事情,我创建了一个维度来保存数据中的所有记录:
allDim = ndx.dimension(function (d) {
return typeof Modality === 'string';
})
然后创建了一个组来保存数据中唯一天数的映射:
dayCountGroup = allDim.group().reduce(
function (p, v) { // add
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) + 1 : 1);
return p;
},
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
if(p.map.has(day) && p.map.get(day) == 0) p.map.remove(day);
return p;
},
function () { // init
return { map: d3.map() };
}
)
小时维度和分组为:
hourDim = ndx.dimension(function (d) {
return d.EventHour;
})
hourAvgGroup = hourDim.group().reduce(
function (p, v) { // add
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) + 1 : 1);
return p;
},
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
if(p.map.has(day) && p.map.get(day) == 0) p.map.remove(day);
return p;
},
function () { // init
return { map: d3.map() };
}
)
然后在我使用的条形图的值访问器中:
.valueAccessor(function(d){ return sum_map(d.value.map)/size_array_of_maps(dayCountGroup.top(Infinity)) ? sum_map(d.value.map)/size_array_of_maps(dayCountGroup.top(Infinity)) : 0})
其中使用的两个函数是:
function sum_map(m) {
var sum = 0;
m.forEach(function(k, v) {
sum += v;
});
return m.size() ? sum : 0;
}
function size_array_of_maps(myObject) {
var count = 0;
myObject.forEach(function(key,value) {
count += key.value.map.size();
})
return count;
}
我敢肯定这里有很多冗余代码,但是 Fiddle 似乎可以正常工作,我稍后会整理它:)