Как добавить процентный столбец в таблицу данных dc.js?

1

У меня есть этот dtsjs dataTable с двумя столбцами, одним из которых является число. И мне нужно добавить третий столбец с тем же номером, но выраженный в процентах от общего числа:

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), например, пользователь может отображать только женщин-продавцов, а затем в таблице будет отображаться только Сара... но со своим старым процентом, 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 записей для Charles, 4 для Sarah и 1 для John. Каждый из них содержит дополнительную информацию, такую как дата и время, которое используется в selectMenus для фильтрации. Но мне нужны агрегированные данные в таблице. Вот почему я использую группу вместо измерения.)

  • 1
    Что вы можете. Группа вычисляется каждый раз, когда отображается таблица (поэтому все / верх / низ - функции). Таким образом, вы можете вычислить итоговые суммы / суммы баллов в исходной группе, а затем рассчитать проценты в вашей отфильтрованной группе или в ваших средствах доступа к столбцам.
  • 0
    Кто-то еще задал почти тот же вопрос сегодня, может быть, это поможет: stackoverflow.com/questions/52871245/…
Показать ещё 2 комментария
Теги:
dc.js
crossfilter

1 ответ

1
Лучший ответ

На самом деле это очень легко сделать. Я потерял перспективу, "группа" - не таинственная вещь, которая работает волшебным образом. Это просто объект с тремя функциями: all, который возвращает массив со всеми данными, а также top и bottom, которые делают то же самое, но возвращают только первые N или последние N элементов. И, как указал Гордон в своем комментарии, эти функции вызываются каждый раз, когда отображается таблица.

Итак, мне просто нужно было вычислить мои проценты внутри определения поддельной группы:

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;
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню