Reputation: 23
I am creating a dashboard, and the data format is as such:
var data = [
{"id": 'CDE', "count": 1, "name": 'ajdkf', "type": 'E', "state": 'A'},
{"id": 'CDE', "count": 0, "name": 'ajdkf', "type": 'E', "state": 'A'},
{"id": 'CDE', "count": 0, "name": 'ajdkf', "type": 'E', "state": 'A'},
{"id": 'CDE', "count": 0, "name": 'ajdkf', "type": 'E', "state": 'A'},
{"id": 'HFG', "count": 1, "name": 'ajdkf', "type": 'E', "state": 'B'},
{"id": 'HFG', "count": 0, "name": 'ajdkf', "type": 'E', "state": 'B'},
{"id": 'HFG', "count": 0, "name": 'ajdkf', "type": 'E', "state": 'B'},
{"id": 'HFG', "count": 0, "name": 'ajdkf', "type": 'E', "state": 'B'},
{"id": 'ABF', "count": 1, "name": 'ghedw', "type": 'G', "state": 'A'},
{"id": 'ABF', "count": 0, "name": 'ghedw', "type": 'G', "state": 'A'},
{"id": 'ABF', "count": 0, "name": 'ghedw', "type": 'G', "state": 'A'},
{"id": 'ABF', "count": 0, "name": 'ghedw', "type": 'G', "state": 'A'},
{"id": 'DEF', "count": 1, "name": 'huiqs', "type": 'E', "state": 'A'},
{"id": 'DEF', "count": 0, "name": 'huiqs', "type": 'E', "state": 'A'},
{"id": 'DEF', "count": 0, "name": 'huiqs', "type": 'E', "state": 'A'},
{"id": 'DEF', "count": 0, "name": 'huiqs', "type": 'E', "state": 'A'},
...
{"id": 'ABC', "count": 1, "name": 'asbsd', "type": 'D', "state": 'B'},
{"id": 'ABC', "count": 0, "name": 'asbsd', "type": 'D', "state": 'B'},
{"id": 'ABC', "count": 0, "name": 'asbsd', "type": 'D', "state": 'B'},
{"id": 'ABC', "count": 0, "name": 'asbsd', "type": 'D', "state": 'B'}
];
I am trying to create a table that looks like:
Name State A Count State B Count
ajdkf 1 1
ghedw 1 0
huiqs 1 0
asbsd 0 1
I currently have:
<body>
<div style='clear:both;'>
<table id="Stats">
<thead>
<tr class="header">
<th> name </th>
<th> State A Count </th>
<th> State B Count </th>
</tr>
</thead>
</table>
</div>
</body>
<script>
...
var dataTable = dc.dataTable("#Stats");
var dataTableDim = ndx.dimension(function(d) {return d.name;});
dataTable
.dimension(dataTableDim)
.group(function(d) {return d.name})
.columns([
function(d) { return d.name; },
function(d) { if (d.state == 'A') {return +d.count;} else {return 0;} },
function(d) { if (d.state == 'B') {return +d.count;} else {return 0;} },
]);
...
</script>
And it is giving me a table that looks like:
Name State A Count State B Count
asbsd
asbsd 0 1
asbsd 0 0
asbsd 0 0
asbsd 0 0
ajdkf
ajdkf 1 0
ajdkf 0 0
ajdkf 0 0
ajdkf 0 0
ajdkf 0 1
ajdkf 0 0
ajdkf 0 0
ajdkf 0 0
huiqs
huiqs 1 0
huiqs 0 0
huiqs 0 0
huiqs 0 0
ghedw
ghedw 0 0
ghedw 1 0
ghedw 0 0
ghedw 0 0
What do I need to do to get the table that I desire? I would love to have under "State A" 2 'columns' (Count and Percent) and the same for State B. Something like:
Name State A State B
Count Percent Count Percent
jsfiddle: https://jsfiddle.net/56hgjgsz/14/
I couldn't get the fiddle to read external files, so I had to add them to the js.. sorry :( (https://jsfiddle.net/56hgjgsz/29/)
This "works" but doesn't do the row reduction in the table and the ordering is backwards -> same address but with /32/ instead of /14/ or /29/
Upvotes: 1
Views: 718
Reputation: 20130
A couple of years after dc.js came out, people discovered that you can actually pass a group as the .dimension()
for a data table. That's what you want here, since you are doing crossfilter reductions to get the state counts.
This is noted in the documentation here.
The method for reducing multiple values in a crossfilter group is standard:
var dataTableGroup = dataTableDim.group().reduce(
function(p, v) {
++p.number;
p.total += +v.count;
p.stateA += (v.state === 'A' ? v.count : 0);
p.stateB += (v.state === 'B' ? v.count : 0);
return p;
},
function(p, v) {
--p.number;
p.total -= +v.count;
p.stateA -= (v.state === 'A' ? v.count : 0);
p.stateB -= (v.state === 'B' ? v.count : 0);
return p;
},
function() {
return {
number: 0,
total: 0,
stateA: 0,
stateB: 0
}
}
);
Then we can make a "fake dimension" for the data table to read the top or bottom N values, keeping only bins that have a value for either stateA
or stateB
. Note we have to pass N
through, unlike for fake groups:
function remove_empty_bins_dt(source_group) {
return {
top: function(N) {
return source_group.top(N).filter(function(d) {
return d.value.stateA !== 0 || d.value.stateB !== 0;
});
},
bottom: function(N) { // hacky but should work
return source_group.top(Infinity).filter(function(d) {
return d.value.stateA !== 0 || d.value.stateB !== 0;
}).slice(-N).reverse();
}
};
}
Again, the data table is unique in dc.js in that it is designed to read data from a crossfilter dimension not a group. So we need to pass this fake dimension to .dimension()
instead of .group()
(which means something completely different sigh)
Working fork of your fiddle: https://jsfiddle.net/gordonwoodhull/d86foxyq/5/
(if I understood it correctly)
One could generalize this to look at an arbitrary number of fields, but I'm out of time for today. 😉
Upvotes: 2