首页 > 解决方案 > 如何将百分比列添加到 dc.js 数据表?

问题描述

我有这个只有两列的 dc.js 数据表,其中一列是数字。我需要添加第三列,具有相同的数字,但表示为占总数的百分比:

VENDOR   SCORE      PERCENT
-------  -----      -------
Charles  5          50.0 %  
Sarah    4          40.0 %
John     1          10.0 %

如果表格是静态的,我只需计算百分比并将它们添加到数据数组中,然后再将其传递给 Crossfilter:

let sum = data.reduce((accum, d) => accum + d.score, 0);
data.forEach(d => { d.percent = 100 * d.score / sum; });

但是可以过滤数据(使用 dc.js 图表和 selectMenus),例如,用户可以选择仅显示女性供应商,然后表格将仅显示 Sarah……但使用她的旧百分比,40% 而不是重新计算它到 100%。

有什么办法可以解决这个问题吗?我想没有办法自动计算百分比。但也许我可以在过滤数据之后、但在 dc.js 重绘表格之前触发的某个事件中添加一个侦听器?


顺便说一句,如果它有什么不同......更糟糕的是,我没有直接使用数据维度,而是将一个假组传递给表(从这里借来的代码):

function filteredGroup(originalGroup, filterFunction) {
  return {
    all: () => originalGroup.all().filter(filterFunction),
    top: n => originalGroup.top(Infinity).filter(filterFunction).slice(0, n),
    bottom: n => originalGroup.top(Infinity).filter(filterFunction).slice(-n).reverse()
  };
}

let ndx = crossfilter(data);
let dim = ndx.dimension(d => d.vendor);
let grp = filteredGroup(dim.group().reduceCount(), d => d.value > 0);

dc.dataTable('#id')
  .dimension(grp)
  .group(d => d.someOtherField)
  .showGroups(true)
  .columns([d => d.vendor, d => d.score])
  ...

(我的实际数据数组将包含查尔斯的 5 个条目,莎拉的 4 个条目和约翰的 1 个条目。每个条目都包含更多信息,例如日期和时间,这些信息在 selectMenus 中用于允许过滤。但我需要表格上的聚合数据。这就是我使用组而不是维度的原因。)

标签: javascriptdc.jscrossfilter

解决方案


这实际上很容易做到。我失去了视角,“群体”并不是一个神奇的东西。它只是一个具有 3 个函数的对象:all,它返回一个包含所有数据的数组,topand bottom,它做同样的事情,但只返回前 N 个或最后 N 个元素。正如 Gordon 在他的评论中指出的那样,每次显示表格时都会调用这些函数。

所以,我只需要在假组定义中计算我的百分比:

function filteredGroup(originalGroup, filterFunction) {
  return {
    all: () => calc(originalGroup.all().filter(filterFunction)),
    top: n => calc(originalGroup.top(Infinity).filter(filterFunction)).slice(0, n),
    bottom: n => calc(originalGroup.top(Infinity).filter(filterFunction)).slice(-n).reverse()
  };
}

function calc(data) {
  let sum = data.reduce((accum, d) => accum + d.score, 0);
  data.forEach(d => { d.percent = 100 * d.score / sum; });
  return data;
}

推荐阅读