dc.js / crossfilter维度(年/周)

时间:2015-12-29 15:36:39

标签: d3.js charts dc.js crossfilter

我无法按周(和不同年份)制作显示数据组的正确图表。

伪SQL会给出:

select sum ('task')
group by 'year', 'week' (and maybe later 'site')

我的数据或多或少看起来像这样:

{ "date" : "20150427", "week" : 18, "site" : "a" "task" : 3, } 
{ "date" : "20150427", "week" : 18, "site" : "b" "task" : 4, } 
{ "date" : "20150427", "week" : 18, "site" : "c" "task" : 2, } 
{ "date" : "20150427", "week" : 18, "site" : "d" "task" : 3, } 
{ "date" : "20150428", "week" : 18, "site" : "a" "task" : 3, } 
{ "date" : "20150428", "week" : 18, "site" : "b" "task" : 3, } 
{ "date" : "20150429", "week" : 18, "site" : "c" "task" : 2, } 
{ "date" : "20150429", "week" : 18, "site" : "d" "task" : 3, } 
{ "date" : "20140512", "week" : 20, "site" : "d" "task" : 6, } 
{ "date" : "20140512", "week" : 20, "site" : "a" "task" : 6, } 
{ "date" : "20140513", "week" : 20, "site" : "b" "task" : 4, } 
{ "date" : "20140513", "week" : 20, "site" : "c" "task" : 1, } 
{ "date" : "20140519", "week" : 21, "site" : "b" "task" : 2, } 
{ "date" : "20140519", "week" : 21, "site" : "c" "task" : 1, } 
{ "date" : "20140519", "week" : 21, "site" : "d" "task" : 3, } 
{ "date" : "20140519", "week" : 21, "site" : "a" "task" : 1, } 
{ "date" : "20140520", "week" : 21, "site" : "b" "task" : 2, } 
{ "date" : "20140520", "week" : 21, "site" : "c" "task" : 3, } 
{ "date" : "20140520", "week" : 21, "site" : "d" "task" : 1, } 
{ "date" : "20140520", "week" : 21, "site" : "a" "task" : 1, }

这是我的数据样本,它可以有不同的年份,网站或任务

我尝试了这个并且它没有用,因为barChart积累了所有年份的一周:

d3.json("/graph", function(dataJson) {


var dataTable = dc.dataTable("#dc-table-graph");
var barChart  = dc.barChart("#chart-bar-ordersperweek");

var data = dataJson;
var dateFormat = d3.time.format("%Y%m%d");
data.forEach(function (d) { d.date = dateFormat.parse(d.date); });


//dimension
var dateDim = ndx.dimension(function (d) { return d.date; });
var weekDim = ndx.dimension(function(d) {return d.week;});

//group
var orderByWD = weekDim.group().reduceSum(function (d) { return d.task; });


barChart
    .width(1000).height(250)
    .dimension(weekDim)
    .group(orderByWD)
    .x(d3.scale.ordinal().domain(d3.range(minWeek.week-1,maxWeek.week+1)))
    .xUnits(dc.units.ordinal)
    .y(d3.scale.linear().domain([0, 6000]))
    .margins({top: 20, right: 30, bottom: 50, left: 80})
    .label(function(d) { return d.value})
    ;


dataTable.width(800).height(800)
        .dimension(dateDim)     
        .group( function (d) { return 'Week ' + d.week} )
        .size(5000)
        .columns([
            function (d) { var format = d3.format('02d');
                return d.date.getFullYear() +'/'+ format(d.date.getMonth()+1) + '/' + format(d.date.getDate()); },
            function (d) { return d.week; },
            function (d) { return d.site; },
            function (d) { return d.task; }
        ])
        .sortBy( function (d) { return Number(d.date) + d.task; })
        .order(d3.descending);

        dataTable.on('renderlet', function(chart){
            chart.selectAll('.dc-table-group').classed('info',true);
        });

dc.renderAll();

我的目标是对同一周内发生的所有任务进行求和并将其绘制到行图中,当我选择一周更新所选周的数据表时。

在dataTable中,我如何按周分组累计(累计)任务?

感谢您的帮助

修改 我添加了一个jsfiddle https://jsfiddle.net/d4qsd8wh/

4 个答案:

答案 0 :(得分:1)

所以,你要做的是为dataTable创建一个虚假的“维度”。在您当前的方法中,您可以这样做:

// Actually a dimension keyed on week and site
var fakeDateDim = {
  top: function(d) {
    var m = dc.d3.map();
    dateDim.top(Infinity).forEach(function(g) {
      if(m.has(g.week + g.site)) {
        m.get(g.week + g.site).task += g.task
      } else {
        // Create the "record"
        m.set(g.week + g.site, {
            week: g.week,
          site: g.site,
          task: g.task
        })
      }
    })

    return m.values();
  }
}

然后在dataTable中,使用fakeDateDim代替当前dateDim。 (您还必须删除日期和星期的表格列。)

以下是基于您放在一起的示例的工作示例:https://jsfiddle.net/s2c9rhxw/

请注意,您可以使用@ ian-h的答案中提到的d3.nest,但它掩盖了您正在做的一些事情,所以我认为使用像Map或d3这样的低级构造可能会更好。映射,直到您对计算感到满意为止。无论您如何实际执行计算,关键是将其包装在dc.js能够使用的假维度对象中。

答案 1 :(得分:1)

我不确定我的问题是否正确,因为其他答案似乎正在解决不同的问题。我会假设您只是询问如何在您的字段中的一周输入未指定年份的情况下逐周工作 - 因此您可以将不同年份的周数汇集到一起。

换句话说,我认为这是你问题的核心:

  

我尝试了这个并且它没有用,因为barChart积累了所有年份的一周

这不是关于dataTable而是关于barChart。

要回答这个问题:是的,我认为您的week字段无用。相反,使用解析日期和d3.time.week按周分类:

var weekDim = ndx.dimension(function(d) {return d3.time.week(d.date);});

然后将条形图设置为使用日期单位而不是序数:

barChart
    ...
    .x(d3.time.scale())
    .xUnits(d3.time.weeks)
    .elasticX(true) // or calculate minWeek/maxWeek using date objects

d3.time.week与其他d3 time interval functions一样,返回间隔开头的日期。 (由于d3.time.weekd3.time.sunday的同义词,因此它会在每个日期之前的星期日返回午夜 - 如果您希望使用基于星期一的星期,请使用d3.time.monday。)将每个日期剪切到开头它的间隔是一个很好的方式来记录日期,而不会忘记它们所属的年份。

然后d3.time.weeks(注意s)是一个相关函数,可以计算任何时间范围内的间隔数(周)。 dc.js需要xUnits计数功能才能确定要显示的柱数。

鉴于您已经获得了三个不同问题的答案,您可能需要花一分钟时间来完善下一个问题,以确保其清晰。

答案 2 :(得分:0)

D3有一些非常强大的工具可以帮助您塑造数据。这只是一个例子。通过制作年+周的关键,我们可以总结任务

var out = d3.nest()
  .key(function(d) { return d.date.substring(0,4)+d.week; })
  .rollup(function(v) { return {
      date: v[0].date,
      task: d3.sum(v, function(d) { return d.task; })
     };
   })
  .entries(data);

这将使out成为一个看起来像这样的对象数组。

[
  {
    "key": "201420",
    "values": {
      "date": "20140512",
      "task": 17
    }
  },
  {
    "key": "201421",
    "values": {
      "date": "20140519",
      "task": 14
    }
  },
  {
    "key": "201518",
    "values": {
      "date": "20150427",
      "task": 23
    }
  }
]

由于您按周分组,因此日期大多是任意的,所以我只是让它显示分组日期列表中的第一个。您还可以按网站在第一个.key(function(d) { return d.site; }下添加另一个.key到子组。

答案 3 :(得分:0)

您需要按如下方式创建weekDim:

function reduceAdd(p, v) {
    return p + v.task;
}

function reduceRemove(p, v) {
    return p - v.task;
}

function reduceInitial() {
    return 0;
}
var m = weekDim.group().reduce(reduceAdd,reduceRemove,reduceInitial);

然后在此维度上创建组,如下所示:

<item
    ...
    android:actionViewClass="<custom class>"
</item>

然后你得到m.top(Infinity)的结果。 我不知道你如何使用这个dataTable,但上面的输出正是你想要的。 希望这有帮助