dc.js复合图 - 为每个人绘制新行

时间:2017-01-28 01:32:18

标签: d3.js dc.js crossfilter

晚上好,每个人,

我正在尝试从充满小时报告(名称,时间戳,工作小时数等)的数据库中获取数据,并使用dc.js创建一个可视化数据的图。我希望时间戳在x轴上,y轴上特定时间戳的小时总和,以及同一图表上每个唯一名称的新条形图。

根据我的目标,使用crossfilter.js显示时间戳应该是我的'维度',然后小时数应该是我的'组'。

问题1,我如何使用维度和组根据人名进一步拆分数据,然后创建条形图以添加到我的复合图?我希望crossfilter.js功能保持不变,这样如果我添加日期范围工具或其他一些用户可控制的过滤器,一切都会相应更新。

问题2,我的时间戳是MySQL日期时间格式:YYYY-mm-dd HH:MM:SS那么我将如何降低精度?例如,如果我想将同一天的所有条目组合成一个条目(日精度),或者将一个月内的所有条目组合成一个条目(月精度)。

提前致谢!

----已添加于2017/01/28 16:06

为了进一步澄清,我正在引用Crossfilter& amp; DC API与DC NASDAQComposite示例一起使用。 Composite示例向我展示了如何在单个图形上放置多个线条/条形图。在我创建的复合图表上,我在每个条形图中添加了一个基于数据集中时间戳的维度。现在我想弄清楚如何为每个组定义组。我希望每个条形图代表每个时间戳的总工作时间。

例如,我的数据库中有五个人,所以我希望单个复合图表中有五个条形图。今天所有五份提交的报告都说他们工作了8个小时,所以现在所有五个条形图都应该在x轴上显示01/28/2017处的标记,在y轴上显示8小时。

    var parseDate = d3.time.format('%Y-%m-%d %H:%M:%S').parse;
    data.forEach(function(d) {
      d.timestamp = parseDate(d.timestamp);
    });
    var ndx              = crossfilter(data);
    var writtenDimension = ndx.dimension(function(d) {
      return d.timestamp;
    });
    var hoursSumGroup    = writtenDimension.group().reduceSum(function(d) {
      return d.time_total;
    });
    var minDate = parseDate('2017-01-01 00:00:00');
    var maxDate = parseDate('2017-01-31 23:59:59');
    var mybarChart = dc.compositeChart("#my_chart");
    mybarChart
      .width(window.innerWidth)
      .height(480)
      .x(d3.time.scale().domain([minDate,maxDate]))
      .brushOn(false)
      .clipPadding(10)
      .yAxisLabel("This is the Y Axis!")
      .compose([
        dc.barChart(mybarChart)
            .dimension(writtenDimension)
            .colors('red')
            .group(hoursSumGroup, "Top Line")
      ]);

所以基于我现在所拥有的和我提供的例子,在撰写部分我应该有5个图表,因为有5个人(显然这需要最终是动态的)并且每个图表都应该仅显示该人的时间戳:total_time数据。

此时我不知道如何根据每个人进一步分解小组hoursSumGroup,这就是我的问题#1所在的地方,我需要帮助搞清楚。

上面的问题#2是我想确保代码是动态的(更多的人可以在没有代码更改的情况下处理),当minDate和maxDate稍后绑定到用户输入字段时,图表会自动更新(我假设通过以某种方式调整维度变量),如果我添加名称过滤器,如果我取消选择图表将通过删除该人的数据更新的名称。

我现在意识到的一个问题#3我想弄明白的是如何让这个人的名字显示在指针工具提示(标题)中以及时间戳和total_time值。

1 个答案:

答案 0 :(得分:0)

有很多方法可以解决这个问题,但我认为最简单的方法是创建一个自定义缩减,将每个人减少到一个子仓。

首先,解决问题#2,您需要根据您感兴趣的时间间隔设置维度。例如,如果您要查看日期:

var writtenDimension = ndx.dimension(function(d) {
    return d3.time.hour(d.timestamp);
});
chart.xUnits(d3.time.hours);

这会导致每个时间戳向下舍入到最近的小时,并告诉图表相应地计算条宽。

接下来,这是一个自定义缩减(from the FAQ),它将为每个缩减值创建一个对象,并为每个人的名称设置值:

var hoursSumGroup = writtenDimension.group().reduce(
    function(p, v) { // add
        p[v.name] = (p[v.name] || 0) + d.time_total;
        return p;
    },
    function(p, v) { // remove
        p[v.name] -= d.time_total;
        return p;
    },
    function() { // init
        return {};
    });    

我没有使用我在评论中提到的系列示例,因为我认为复合键很难处理。这是另一种选择,如果有必要,我会扩大我的答案。

接下来,我们可以使用可以按名称获取值的值访问器来提供复合折线图。

假设我们有一个数组names

compositeChart.shareTitle(false);
compositeChart.compose(
    names.map(function(name) {
        return dc.lineChart(compositeChart)
            .dimension(writtenDimension)
            .colors('red')
            .group(hoursSumGroup)
            .valueAccessor(function(kv) {
                return kv.value[name];
            })
            .title(function(kv) {
                return name + ' ' + kv.key + ': ' + kv.value;
            });
    }));

同样,在这里使用条形图是没有意义的,因为它们会相互模糊。

如果您在其他位置过滤名称,则会导致名称行减少到零。让这条线完全消失可能不会那么简单。

以上shareTitle(false)确保子图表会绘制自己的标题; title函数只是将当前名称添加到这些标题(通常只是键:值)。