crossfilter 减少崩溃

crossfilter reduction is crashing

我无法成功呈现 dc.js 堆叠条形图,并且收到控制台错误

unable to read property 'Total' of undefined

我是图书馆的新手,怀疑我的组或化简没有成功指定。

如何解决这个问题?

 $scope.riskStatusByMonth = function(){

    var data = [ 
                    {"Month":"Jan","High":12},{"Month":"Jan","Med":14},{"Month":"Jan","Low":2},{"Month":"Jan","Closed":8},
                    {"Month":"Feb","High":12},{"Month":"Feb","Med":14},{"Month":"Feb","Low":2},{"Month":"Feb","Closed":8},
                    {"Month":"Mar","High":12},{"Month":"Mar","Med":14},{"Month":"Mar","Low":2},{"Month":"Mar","Closed":8},
                    {"Month":"Apr","High":12},{"Month":"Apr","Med":14},{"Month":"Apr","Low":2},{"Month":"Apr","Closed":8},
                    {"Month":"May","High":12},{"Month":"May","Med":14},{"Month":"May","Low":2},{"Month":"May","Closed":8},
                    {"Month":"Jun","High":12},{"Month":"Jun","Med":14},{"Month":"Jun","Low":2},{"Month":"Jun","Closed":8},
                    {"Month":"Jul","High":12},{"Month":"Jul","Med":14},{"Month":"Jul","Low":2},{"Month":"Jul","Closed":8},
                    {"Month":"Aug","High":12},{"Month":"Aug","Med":14},{"Month":"Aug","Low":2},{"Month":"Aug","Closed":8},
                    {"Month":"Sep","High":12},{"Month":"Sep","Med":14},{"Month":"Sep","Low":2},{"Month":"Sep","Closed":8},
                    {"Month":"Oct","High":12},{"Month":"Oct","Med":14},{"Month":"Oct","Low":2},{"Month":"Oct","Closed":8},
                    {"Month":"Nov","High":12},{"Month":"Nov","Med":14},{"Month":"Nov","Low":2},{"Month":"Nov","Closed":8},
                    {"Month":"Dec","High":8},{"Month":"Dec","Med":6},{"Month":"Dec","Low":13},{"Month":"Dec","Closed":8},
               ]

    data.forEach(function(x) {
      x.Total = 0;
    });

    var ndx = crossfilter(data)

    var xdim = ndx.dimension(function (d) {return d.Month;});

    function root_function(dim,stack_name) {
        return dim.group().reduce(
      function(p, v) {
        p[v[stack_name]] = (p[v[stack_name]] || 0) + v.High;
        return p;},
        function(p, v) {
        p[v[stack_name]] = (p[v[stack_name]] || 0) + v.Med;
        return p;},
        function(p, v) {
        p[v[stack_name]] = (p[v[stack_name]] || 0) + v.Low;     <-------------------here is where error occurs
        return p;},
        function(p, v) {
        p[v[stack_name]] = (p[v[stack_name]] || 0) + v.Closed;
        return p;}, 
      function() {
        return {};
      });}

    var ydim = root_function(xdim,'Total')

    function sel_stack(i) {
    return function(d) {
      return d.value[i];
    };}

    $scope.monthlyRiskStatus = dc.barChart("#risk-status-by-month");

    $scope.monthlyRiskStatus
      .x(d3.scaleLinear().domain(xdim))
      .dimension(xdim)
      .group(ydim, '1', sel_stack("Jan"))
      .xUnits(dc.units.ordinal);


    month = [null,'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
    for(var i = 2; i<=12; ++i)
      $scope.monthlyRiskStatus.stack(ydim, ''+i, sel_stack(month[i]));

    $scope.monthlyRiskStatus.render();
}

group.reduce() 接受三个参数:add、remove、init。

你超过了 5。

看起来它正在尝试调用第三个作为初始值设定项,没有参数,因此 v 未定义。

如何按级别堆叠

看起来您真正想要做的是按月(X 轴)分组,然后按状态或级别堆叠。这是一种方法。

首先,您的函数采用堆栈名称是正确的,但我们希望它采用所有堆栈名称:

function root_function(dim,stack_names) {
    return dim.group().reduce(
  function(p, v) {
    stack_names.forEach(stack_name => { // 1
      if(v[stack_name] !== undefined) // 2
          p[stack_name] = (p[v[stack_name]] || 0) + v[stack_name] // 3
    });
    return p;}, 
  function(p, v) {
    stack_names.forEach(stack_name => { // 1
      if(v[stack_name] !== undefined) // 2
          p[stack_name] = (p[v[stack_name]] || 0) + v[stack_name] // 3
    });
    return p;}, 
  function() {
    return {};
  });}
  1. 在添加和减少函数中,我们将遍历所有堆栈名称
  2. 堆栈名称是每行中可能存在也可能不存在的字段。如果堆栈名称存在于当前行...
  3. 我们将从当前 bin 中具有相同名称的字段中添加或减去行字段 stack_name

我们将定义 levelsmonths 数组。 levels 将用于堆叠,months 将用于序数 X 域:

var levels = ['High', 'Med', 'Low', 'Closed']
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];

当我们定义组时,我们将levels传递给root_function()

var ygroup = root_function(xdim,levels)

我发现您对 "dimension" 的 English/math 定义和交叉过滤器维度有些混淆。是的,在英语中 "Y" 将是一个维度,但在 crossfilter 和 dc.js 中,"dimensions" 是您聚合的基础,而组是经常进入 Y 的聚合。(命名事物是难。)

我们将使用序数尺度(你有一半序数一半线性,这是行不通的):

$scope.monthlyRiskStatus
  .x(d3.scaleOrdinal().domain(months))
  .dimension(xdim)
  .group(ygroup, levels[0], sel_stack(levels[0]))
  .xUnits(dc.units.ordinal);

将月份传递给序数刻度的域告诉 dc.js 按该顺序绘制条形图。 (警告:它是折线图的 little more complicated,因为您还必须对输入数据进行排序。)

请注意,我们是按级别而不是按月堆叠的。也在这里:

for(var i = 1; i<levels.length; ++i)
  $scope.monthlyRiskStatus.stack(ygroup, levels[i], sel_stack(levels[i]));

我们也添加一个图例,这样我们就知道我们在看什么:

  .margins({left:75, top: 0, right: 0, bottom: 20})
  .legend(dc.legend())

Demo fiddle.