【问题标题】:dc.js / crossfilter dimensions (year / week)dc.js / crossfilter 维度(年/周)
【发布时间】:2015-12-29 15:36:39
【问题描述】:

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

伪 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();

我的目标是总结同一周内发生的所有任务并将其绘制到行图上,当我选择一个星期时,用选定的星期更新数据表。

在数据表中,我如何按按周分组的站点汇总(累积)任务?

感谢您的帮助

编辑 我添加了一个 jsfiddle https://jsfiddle.net/d4qsd8wh/

【问题讨论】:

  • 我认为 dataTable 基于维度而不是组运行,因此您可能需要创建一个假维度来返回要显示的记录。如果你使用 jsfiddle 或类似的东西组合了一个工作示例,我或这里的其他人可能会为你工作。
  • 我只是添加它jsfiddle.net/d4qsd8wh

标签: d3.js charts dc.js crossfilter


【解决方案1】:

因此,您要做的是为数据表创建一个虚假的“维度”。在您当前的方法中,您可以这样做:

// 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();
  }
}

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

这是一个基于您汇总的示例的工作示例:https://jsfiddle.net/s2c9rhxw/

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

【讨论】:

    【解决方案2】:

    我不确定我的问题是否正确,因为其他答案似乎在解决不同的问题。我假设您只是在询问如何在您的字段中的周条目未指定年份时按周分组工作 - 因此您可以将不同年份的周堆积成一个。

    换句话说,我将此解释为您问题的核心:

    我试过了,但它不起作用,因为 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 计数函数来确定要显示的条数。

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

    【讨论】:

    • 我认为可能有多个问题。也许我们可以整理一个综合答案:-)
    • 好的,这解决了我的部分问题:) 但是我如何将“星期一”定义为一周的开始(目前星期日是第一天)? 这部分是 d3.time.week(d.date) 感谢您的帮助 Gordon
    • 太好了,我希望其他一些答案也有帮助! d3.time.week 只是 d3.time.sunday 的同义词,所以你应该能够使用 d3.time.monday 来获得你想要的东西。我将在上面澄清它的作用。
    • 对于化妆品,我必须改变什么才能在标签上显示几周而不是几个月?示例:第 1 周 ... 第 5 周 ... 第 10 周 ...
    【解决方案3】:

    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 下添加另一个 .key(function(d) { return d.site; } 以按站点分组。

    【讨论】:

      【解决方案4】:

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

      var weekDim = ndx.dimension(function(d) {
          return d.date.substring(0,4) + "" + d.week;
      });
      

      然后在这个维度上创建组如下:

      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);
      

      你得到的结果是 m.top(Infinity)。 我不知道您如何使用此数据表,但上面的输出将正是您想要的。 希望这会有所帮助

      【讨论】:

      • 抱歉,我认为这没有帮助。这种减少相当于问题中的reduceSum,d3 有更好的处理时间的方法。感谢您的贡献!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-02
      • 1970-01-01
      • 2014-08-02
      相关资源
      最近更新 更多