首页 文章

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

提问于
浏览
0

各位晚上好,

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

根据我的目标看来,使用crossfilter.js时间戳应该是我的“维度”,然后小时数应该是我的“组” .

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

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

提前致谢!

----在2017/01/28 16:06添加

为了进一步澄清,我引用了Crossfilter和DC API以及DC NASDAQComposite示例 . Composite示例向我展示了如何在单个图形上放置多个线条/条形图 . 在复合图表上,我've created, each of the bar charts I' ve根据数据集中的时间戳添加了维度 . 现在我想弄清楚如何为每个组定义组 . 我希望每个条形图代表每个时间戳的总工作时间 .

例如,我的数据库中有五个人,所以我希望单个复合图表中有五个条形图 . 今天所有五份提交的报告都说他们工作了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个人(显然这需要最终是动态的),并且每个图表都应该只显示timestamp:该人的total_time数据 .

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

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

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

1 回答

  • 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) 确保儿童图表将绘制自己的 Headers ; title 函数只是将当前名称添加到这些 Headers (通常只是键:值) .

相关问题