I have this dc.js dataTable with only two columns, one of which is a number. And I need to add a third column, with that same number but expressed as a percentage over the total:
VENDOR SCORE PERCENT
------- ----- -------
Charles 5 50.0 %
Sarah 4 40.0 %
John 1 10.0 %
If the table was static, I would just calculate the percentages and add them to the data array before passing it to Crossfilter:
let sum = data.reduce((accum, d) => accum + d.score, 0);
data.forEach(d => { d.percent = 100 * d.score / sum; });
But the data can be filtered (using dc.js charts and selectMenus), for example the user could choose to display only female vendors, and then the table would show only Sarah... but with her old percentage, 40% instead of recalculating it to 100%.
Is there any way I can work around this? I guess there is no way to automatically calculate the percentage. But maybe I can add a listener to some event which triggers after the data is filtered, but before dc.js redraws the table?
By the way, in case it makes any difference... to make things worse, I'm not working directly with the data dimension, instead I'm passing a fake group to the table (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])
...
(My actual data array would contain 5 entries for Charles, 4 for Sarah and 1 for John. Each includes more information, such as date and time, which is used in the selectMenus to allow filtering. But I need aggregated data on the table. That's why I'm using a group instead of the dimension.)