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 似乎可以正常工作,我稍后会整理它:)

https://jsfiddle.net/dolomite/6eeahs6z/126/