1
votes

Stacked Bar chart not able to filter on click of any Stack

I need to filter all the charts when clicking on any stack, which is not happening and struggling for a few days.

I've created a fiddle with link

http://jsfiddle.net/praveenNbd/09t5fd7v/13/

I feel am messing up with keys creation as suggested by gordonwoodhull.

function stack_second(group) {
    return {
        all: function () {
            var all = group.all(),
            m = {};
            // build matrix from multikey/value pairs
            all.forEach(function (kv) {
                var ks = kv.key;
                m[ks] = kv.value;
            });
            // then produce multivalue key/value pairs
            return Object.keys(m).map(function (k) {
                return {
                    key: k,
                    value: m[k]
                };
            });
        }
    };
}

I tried to follow this example https://dc-js.github.io/dc.js/examples/filter-stacks.html

Not able to figure out how below code works:

barChart.on('pretransition', function (chart) {
    chart.selectAll('rect.bar')
    .classed('stack-deselected', function (d) {
        // display stack faded if the chart has filters AND
        // the current stack is not one of them
        var key = multikey(d.x, d.layer);
        //var key = [d.x, d.layer];
        return chart.filter() && chart.filters().indexOf(key) === -1;
    })
    .on('click', function (d) {
        chart.filter(multikey(d.x, d.layer));
        dc.redrawAll();
    });
});

Can someone please point me out in the right direction.

Thanks for stopping by.

1
I am confused because your fiddle doesn't have any of the filter-stacks code. The reason it isn't filtering correctly is the expression d.value.count || d.value - this doesn't make sense because when the count is 0 you want to display 0, not d.value, which is an object. dc.js wants a number not an object.Gordon
Maybe you could edit your question and fiddle and add the filter-stacks stuff. It's hard for anyone to guess why it's not working without seeing your code.Gordon
using only d.value.count solved filtering of full bars.Praveen NC
I've edited the fiddle and added filter-stacks stuff, but splitkey function is causing issue, as x axis have 2 keys.Praveen NC

1 Answers

1
votes

You usually don't want to use multiple keys for the X axis unless you have a really, really good reason. It is just going to make things difficult

Here, the filter-stacks example is already using multiple keys, and your data also has multiple keys. If you want to use your data with this example, I would suggest crunching together the two keys, since it looks like you are really using the two together as an ordinal key. We'll see one way to do that below.

You were also trying to combine two different techniques for stacking the bars, stack_second() and your own custom reducer. I don't think your custom reducer will be compatible with filtering by stacks, so I will drop it in this answer.

You'll have to use the multikey() function, and crunch together your two X keys:

dim = ndx.dimension(function (d) {
    return multikey(d[0] + ',' + d[1], d[2]);
});

Messy, as this will create keys that look like 0,0xRejected... not so human-readable, but the filter-stacks hack relies on being able to split the key into two parts and this will let it do that.

I didn't see any good reason to use a custom reduction for the row chart, so I just used reduceCount:

var barGrp = barDim.group();

I found a couple of new problems when working on this.

First, your data doesn't have every stack for every X value. So I added a parameter to stack_second() include all the "needed" stacks:

function stack_second(group, needed) {
  return {
    all: function() {
      var all = group.all(),
          m = {};
      // build matrix from multikey/value pairs
      all.forEach(function(kv) {
        var ks = splitkey(kv.key);
        m[ks[0]] = m[ks[0]] || Object.fromEntries(needed.map(n => [n,0]));
        m[ks[0]][ks[1]] = kv.value;
      });
      // then produce multivalue key/value pairs
      return Object.entries(m).map(([key,value]) => ({key,value}));
    }
  };
}

Probably the example should incorporate this change, although the data it uses doesn't need it.

Second, I found that the ordinal X scale was interfering, because there is no way to disable the selection greying behavior for bar charts with ordinal scales. (Maybe .brushOn(false) is completely ignored? I'm not sure.)

I fixed it in the pretransition handler by explicitly removing the built-in deselected class, so that our custom click handler and stack-deselected class can do their work:

chart.selectAll('rect.bar')
  .classed('deselected', false)

All in all, I think this is way too complicated and I would advise not to use multiple keys for the X axis. But, as always, there is a way to make it work.

Here is a working fork of your fiddle.