首页 > 解决方案 > 交叉过滤器减少正在崩溃

问题描述

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

无法读取未定义的属性“总计”

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

我该如何解决这个问题?

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

标签: dc.jscrossfilter

解决方案


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. 在 add 和 reduce 函数中,我们将遍历所有堆栈名称
  2. 堆栈名称是每行中可能存在或不存在的字段。如果堆栈名称存在于当前行中...
  3. 我们将从stack_name当前 bin 中具有相同名称的字段中添加或减去行字段。

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

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

当我们定义组时,我们将传递levelsroot_function()

var ygroup = root_function(xdim,levels)

我看到您在“维度”的英语/数学定义和交叉过滤维度之间有些混淆。是的,在英语中“Y”是一个维度,但在 crossfilter 和 dc.js 中,“维度”是您聚合的内容,而组是通常进入 Y 的聚合。(命名很困难。)

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

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

将月份传递到序数比例域告诉 dc.js 以该顺序绘制条形图。(警告:折线图有点复杂,因为您还必须对输入数据进行排序。)

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

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

按级别堆叠的屏幕截图

演示小提琴


推荐阅读