1

I have data with one column that is a list of labels for each data point. I would like to use dc.js to make a row chart that plots the number of occurrences of each label.

Data looks like this:

Date , Labels
1/1/2015 , "A, B, C"
1/2/2015 , "B"
1/3/2015 , "C, A"
1/4/2015 , "A"

I would like a row chart that aggregates them like this:
A: 3
B: 2
C: 2

My code so far:

var labels = ["A", "B", "C"];
var labelBar = dc.rowChart("#label-bar");
d3.csv('data.csv', function (csv) {
    var data = crossfilter(csv);
    var labelDim = data.dimension(function(d){return d["Labels"];});
    var labelGroup = labelDim.group().reduce(
        function(p,v) { //add
            for (i = 0; i < labels.length; i++) {
                if(v["Labels"].indexOf(labels[i]) > -1)
                    p[labels[i]]++;
            }
            return p;
        },
        function(p,v) { //subtract
            for (i = 0; i < labels.length; i++) {
                if(v["Labels"].indexOf(labels[i]) > -1)
                    p[labels[i]]--;
            }
            return p;
        },
        function(p,v) { //initial
            p = {};
            for (i = 0; i < labels.length; i++) {
                p[labels[i]] = 0;
            }
            return p;
        });
    labelBar
        .dimension(labelDim)
        .group(labelGroup)
        .elasticX(true);
});

The code only creates a row chart with one bar for each data point, not for each label. Any help would be appreciated.

Ethan Jewett
  • 6,002
  • 16
  • 25
Eric
  • 244
  • 5
  • 10

1 Answers1

2

You will need to use dimension.groupAll for this and manage the groupings on your own. If you put together a working example with your dimension, I can show you how to do this.

However, have you looked at Reductio, which makes this pretty easy? https://github.com/esjewett/reductio#groupall-aggregations

With your data you would do something like

var dim = data.dimension(function(d) { return d.Labels.split(','); });
groupAll = dim.groupAll();

reducer = reductio()
  .groupAll(function(record) {
    return record.Labels.split(',');
  })
  .count(true);

reducer(groupAll);
groupAll.all(); // Should give you groups with keys "A", "B", "C"

Working example: https://jsfiddle.net/z4k78odx/4/

Ethan Jewett
  • 6,002
  • 16
  • 25
  • Thank you very much for your answer, Ethan! However, when I use this code, I get an error on line 811 of dc.js.
    TypeError: undefined is not a function (evaluating '_chart.group().all()')
    – Eric Nov 20 '15 at 16:40
  • I'm not able to interpret this error. Could you please put together a working example? – Ethan Jewett Nov 20 '15 at 16:42
  • Don't worry about that error actually. I think this approach will work, but I need to preprocess my data first. – Eric Nov 20 '15 at 17:02
  • Here's a nonworking jsfiddle... https://jsfiddle.net/4tcde2ve/5/ My issue is with the labelBar graph. When I put groupAll as the group, it shows labels (which are clickable) but not the bars. – Eric Nov 20 '15 at 18:04
  • Fixed the fiddle and posted a link in the answer. – Ethan Jewett Nov 20 '15 at 21:00
  • P.S. You'll need to strip spaces if they are in the data. Have updated the link with spaces removed from the data. – Ethan Jewett Nov 20 '15 at 21:02
  • You, sir, are amazingly awesome and generous :) Thank you very much for your help. However, I noticed one issue. When I click on the bars in the row chart, they select the items that only have that item. I updated the jsfiddle with a table so you can see. Do you know how to fix this? https://jsfiddle.net/z4k78odx/3/ – Eric Nov 20 '15 at 23:37
  • 1
    The default filter handler expects the group key to equal the dimension key. This is not the case here. In our case the dimension key is an array and the group key is an element of that array. I've updated the example with a filterHandler that behaves correctly: https://jsfiddle.net/z4k78odx/4/ – Ethan Jewett Nov 20 '15 at 23:48
  • That's awesome. Thank you! – Eric Nov 21 '15 at 01:02