【问题标题】:How can I add a percentage column to a dc.js dataTable?如何将百分比列添加到 dc.js 数据表?
【发布时间】:2018-10-18 17:07:23
【问题描述】:

我的 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 重绘表格之前触发的某个事件添加一个监听器?


顺便说一句,万一这有什么不同......更糟糕的是,我没有直接处理数据维度,而是将一个假组传递给表(code borrowed from here):

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 中用于允许过滤。但我需要表中的聚合数据。这就是我使用组而不是维度的原因。)

【问题讨论】:

  • 当然可以。每次显示表格时都会计算组(这就是为什么 all/top/bottom 都是函数)。因此,您可以计算原始组中的总和/分数总和,然后计算过滤组或列访问器中的百分比。
  • 今天有人问了几乎同样的问题,也许这会有所帮助:stackoverflow.com/questions/52871245/…
  • 谢谢戈登 :)。这非常容易做到,我不敢相信我花了这么多时间来解决这个问题!我在想组和“假组”,就像一些神奇的东西......实际上它们非常简单,只是一个具有 3 个返回数据数组的函数的对象。
  • 太好了,感谢您的跟进!就是这样,没有魔法!

标签: javascript dc.js crossfilter


【解决方案1】:

这实际上很容易做到。我失去了视角,“群体”并不是一个神奇的东西。它只是一个具有 3 个函数的对象:all,它返回一个包含所有数据的数组,topbottom,它们的作用相同,但只返回前 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;
}

【讨论】:

    猜你喜欢
    • 2017-09-02
    • 2018-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多