dc.js使用三列的最小最大平均值创建dataTable

cra*_*wap 5 crossfilter dc.js

尝试使用样本数据中3列的最小值,最大值和平均值创建d3/dc/xfilter dataTable.一直在苦苦挣扎但无法理解如何将reduceAdd,reduceRemove,reduceInitial函数集成到dataTable中以创建三个必要的行.

期望的输出将如下所示:

------------------------------------------
|  Value   |  Cars  |  Bikes  |  Trucks  |
------------------------------------------
|    Min   |   125  |   310   |    189   |
------------------------------------------
|    Max   |   230  |   445   |    290   |
------------------------------------------
|    Avg   |   178  |   385   |    245   |
------------------------------------------
Run Code Online (Sandbox Code Playgroud)

也看不出如何添加第一个(标签)列.我知道reduceInitial可以返回一个数组(例如['min', 'max', 'avg'])但是如何引用它的标签?

var myCSV = [	
{"shift":"1","date":"01/01/2016/08/00/00","car":"178","truck":"255","bike":"317","moto":"237"},
{"shift":"2","date":"01/01/2016/17/00/00","car":"125","truck":"189","bike":"445","moto":"273"},
{"shift":"3","date":"02/01/2016/08/00/00","car":"140","truck":"219","bike":"328","moto":"412"},
{"shift":"4","date":"02/01/2016/17/00/00","car":"222","truck":"290","bike":"432","moto":"378"},
{"shift":"5","date":"03/01/2016/08/00/00","car":"200","truck":"250","bike":"420","moto":"319"},
{"shift":"6","date":"03/01/2016/17/00/00","car":"230","truck":"220","bike":"310","moto":"413"},
{"shift":"7","date":"04/01/2016/08/00/00","car":"155","truck":"177","bike":"377","moto":"180"},
{"shift":"8","date":"04/01/2016/17/00/00","car":"179","truck":"203","bike":"405","moto":"222"},
{"shift":"9","date":"05/01/2016/08/00/00","car":"208","truck":"185","bike":"360","moto":"195"},
{"shift":"10","date":"05/01/2016/17/00/00","car":"150","truck":"290","bike":"315","moto":"280"},
{"shift":"11","date":"06/01/2016/08/00/00","car":"200","truck":"220","bike":"350","moto":"205"},
{"shift":"12","date":"06/01/2016/17/00/00","car":"230","truck":"170","bike":"390","moto":"400"},
];


dataTable = dc.dataTable('#dataTable');
lc1 = dc.lineChart("#line1");
lc2 = dc.lineChart("#line2");
lc3 = dc.lineChart("#line3");

var dateFormat = d3.time.format("%d/%m/%Y/%H/%M/%S");

myCSV.forEach(function (d) {
	d.date = dateFormat.parse(d.date);
});

myCSV.forEach(function (d) {
	d['car'] = +d['car'];
	d['bike'] = +d['bike'];
	d['moto'] = +d['moto'];
});

//console.log(myCSV);

var facts = crossfilter(myCSV);
var dateDim = facts.dimension(function (d) {return d.date});

var carDim = facts.dimension(function (d) {return d['car']});
var dgCar = dateDim.group().reduceSum(function (d) {return d['car']});

var bikeDim = facts.dimension(function (d) {return d['bike']});
var dgBike = dateDim.group().reduceSum(function (d) {return d['bike']});

var motoDim = facts.dimension(function (d) {return d['moto']});
var dgMoto = dateDim.group().reduceSum(function (d) {return d['moto']});

var minDate = new Date ("2016-01-01T08:00:00.000Z");
var maxDate = new Date ("2016-01-03T17:00:00.000Z");	

var maxY = d3.max(myCSV, function(d) {return d['car']});

function reduceAdd(i,d){ return i+1; }
function reduceRemove(i,d){return i-1; }
function reduceInitial(){ return ['min','max','avg'];}


dataTable
  .width(jsTablWidth)
  .height(400)
  .dimension(dateDim)
  .group( function(d){return '';} )
  .columns([
    {
      label: 'Value',
      format: function(d) { return dateGroup1.reduce(reduceAdd,reduceRemove,reduceInital); }
    },
    {
      label: tSel1.replace(/_/g, " "),
      format: function(d) { return //avg cars ; }
    },
    {
      label: tSel2.replace(/_/g, " "),
      format: function(d) { return //avg bikes ; }
    },
    {
      label: tSel3.replace(/_/g, " "),
      format: function(d) { return //avg moto; }
    }
  ]);


dc.renderAll();
dc.redrawAll();
Run Code Online (Sandbox Code Playgroud)
svg{height:280px;}
Run Code Online (Sandbox Code Playgroud)
<script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.3.3/d3.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.1/crossfilter.min.js"></script>
<script src="http://dc-js.github.io/dc.js/js/dc.js"></script>
<link href="http://dc-js.github.io/dc.js/css/dc.css" rel="stylesheet"/>

<svg id="dataTable"></svg>
<svg id="line1"></svg>
<svg id="line2"></svg>
<svg id="line3"></svg>
Run Code Online (Sandbox Code Playgroud)

Gor*_*don 5

好的,希望您可以将桌子对角线对换,将运输方式设置为行而不是列。如果不弄清楚那部分,这个解决方案已经很古怪了。

样本输出

除了跟踪所有值之外,实际上没有其他方法可以计算出最小值和最大值。因此,我们将使用复杂缩减示例中的缩减。这些实际上根本不会减少,但会维护已过滤行的排序数组。

我们需要一个唯一键来保留排序后的数组(以便我们删除正确的行。幸运的是,您在shift字段中有该键。

因此,这里是那些功能,或者更确切地说是在给定唯一键访问器的情况下生成缩减器的功能。

  function groupArrayAdd(keyfn) {
      var bisect = d3.bisector(keyfn);
      return function(elements, item) {
          var pos = bisect.right(elements, keyfn(item));
          elements.splice(pos, 0, item);
          return elements;
      };
  }
  function groupArrayRemove(keyfn) {
      var bisect = d3.bisector(keyfn);
      return function(elements, item) {
          var pos = bisect.left(elements, keyfn(item));
          if(keyfn(elements[pos])===keyfn(item))
              elements.splice(pos, 1);
          return elements;
      };
  }
  function groupArrayInit() {
      return [];
  }
Run Code Online (Sandbox Code Playgroud)

由于这些保留对整个行的引用,因此我们只需要一组即可。我们在计算以下指标时将使用更具体的访问器。

在这里,我们需要crossfilter.groupAll,它将所有内容减少到一个bin中。这是因为行没有被任何键分区。每行都有助于所有运输方式:

var filteredRows = facts.groupAll().reduce(
  groupArrayAdd(dc.pluck('shift')),
  groupArrayRemove(dc.pluck('shift')),
  groupArrayInit
);
Run Code Online (Sandbox Code Playgroud)

现在是最荒谬的部分。我们将创建您见过的最假的尺寸对象。重要的是,它是具有.bottom()动态计算每一行方法的对象:

var fakeDim = {
  bottom: function() {
    return [
      {key: 'Car', value: filteredRows.value(), acc: dc.pluck('car')},
      {key: 'Truck', value: filteredRows.value(), acc: dc.pluck('car')},
      {key: 'Bike', value: filteredRows.value(), acc: dc.pluck('bike')},
      {key: 'Moto', value: filteredRows.value(), acc: dc.pluck('moto')}
    ];
  }
};
Run Code Online (Sandbox Code Playgroud)

除了,等等,看起来根本没有做任何计算,只是在获取值吗?那有什么奇怪的acc

好吧,我们正在准确地生成生成表行所需的源数据,并且我们将使用format下面的访问器实际计算所有内容。我们将key“”用作“标签列”,将原始行保留在value成员中;并且我们将提供acc用于计算指标的访问器。

数据表定义如下所示:

dataTable
  .width(400)
  .height(400)
  .dimension(fakeDim)
  .group( function(d){return '';} )
  .columns([
    {
      label: 'Value',
      format: function(d) { 
        return d.key;
      }
    },
    {
      label: 'Min',
      format: function(d) {
        return d3.min(d.value, d.acc);
      }
    },
    {
      label: 'Max',
      format: function(d) {
        return d3.max(d.value, d.acc);
      }
    },
    {
      label: 'Avg',
      format: function(d) {
        return d3.mean(d.value, d.acc);
      }
    }
  ]);
Run Code Online (Sandbox Code Playgroud)

这是所有指标最终计算出来的地方。我们将提供所有可用的行,并且每个表行都有一个访问器。d3数组具有方便的功能,可用于计算数组的最小值,最大值和平均值。繁荣,完成。

我把一个堆积的图表放到这个小提琴中进行测试。(我知道堆叠这些值可能没有任何意义,这只会有助于进行过滤。)

http://jsfiddle.net/gordonwoodhull/g4xqvgvL/21/

旋转数据表

对此的额外奖励使我想起了我从来没有解决过表转换问题,所以我想看看一下,因为它很有趣。我仍然认为赏金应该归@SergGr,但这是根据类别,维和列访问器/格式器转置表的解决方案。

首先,我们需要类别列表,因此让我们更好地组织类别和字段名称:

var categories = {  
  Car: 'car',
  Truck: 'truck',
  Bike: 'bike',
  Moto: 'moto'
};
Run Code Online (Sandbox Code Playgroud)

现在可以简化伪维,因为它是从以下类别映射生成的:

function fake_dimension(cats) {
  return {
    bottom: function() {
      return Object.keys(cats).map(function(k) {
        return {
          key: k,
          value: filteredRows.value(),
          acc: dc.pluck(cats[k])
        };
      });
    }
  };
}
var fakeDim = fake_dimension(categories);
Run Code Online (Sandbox Code Playgroud)

我们需要将列定义从图表定义中拉出,因为我们将对其进行转换:

var columns = [
  {
    label: 'Value',
    format: function(d) { 
      return d.key;
    }
  },
  {
    label: 'Min',
    format: function(d) {
      return d3.min(d.value, d.acc);
    }
  },
  {
    label: 'Max',
    format: function(d) {
      return d3.max(d.value, d.acc);
    }
  },
  {
    label: 'Avg',
    format: function(d) {
      return d3.mean(d.value, d.acc);
    }
  }
];
Run Code Online (Sandbox Code Playgroud)

最后,我们可以编写转置函数:

function transpose_datatable(cats, dim, cols) {
  var cols2 = d3.map(cols, function(col) { // 1
    return col.label;
  });
  return {
    dim: { // 2
      bottom: function() {
        var dall = d3.map(dim.bottom(Infinity), function(row) { // 3
          return row.key;
        });
        return cols.slice(1).map(function(col) { // 4
          var row = {
            label: col.label
          };
          Object.keys(cats).forEach(function(k) {
            row[k] = dall.get(k);
          });
          return row;
        });
      }
    },
    cols: [ // 5
      {
        label: cols[0].label,
        format: function(d) {
          return d.label;
        }
      }
    ].concat(Object.keys(cats).map(function(k) { // 6
      return {
        label: k,
        format: function(d) {
          return cols2.get(d.label).format(d[k]);
        }
      }
    }))
  };
}

var transposed = transpose_datatable(categories, fakeDim, columns)
Run Code Online (Sandbox Code Playgroud)
  1. 首先,我们将需要原始列与其定义的映射,因为它们将成为行。我们可以使用一个d3.maphere,它的行为就像一个行为良好的JavaScript对象。
  2. 我们将创建一个新的伪维,以及一个新的列定义数组。伪维只有一种.bottom()方法,就像上面的方法一样。
  3. 的定义.bottom()将需要所有原始数据,并按键(类别名称)索引。因此,我们也将其放入d3.map对象中。
  4. 现在,我们可以构建伪造的尺寸数据。第一列只是标题(现在将是列标题),因此我们将跳过它。该行的数据将是新标题(以前的列标签),以及每个类别的字段。这些字段将填充原始维度中的行。
  5. 新的列定义需要替换标签,列,其余的从类别名称生成。
  6. 现在,每列的标签为类别名称,并.format()调用原始列的format,使用类别名称获取数据。

新屏幕截图:

旋转数据表的屏幕截图