1

here is my sample fiddle

It is a 2 basic chart dc.js charts. What I am trying to understand is how the charts interact with each other. For instance:

If i select Aziz on the row chart(on the right chart) the other values in this chart are greyed out and in the ring chart(left chart) 2012 fills up the whole Ring Chart. Then if i select Aziz again the both charts are reset.

If I select 2012 on the ring chart(on the left chart) the other values in this chart are greyed out and in the row chart(right chart) Aziz is the only value shown in the row chart(right chart). Then if i select 2012 again the both charts are reset.

Basically how is this interaction working?

The four variables being passed to these charts are yearDim spendDim spendPerYear spendPerName but the only commonality here is xfilter maybe that's what it is, but that does not fully explain it for me. Can anyone advise to help me understand this better?

var xfilter = crossfilter(data1),
    yearDim  = xfilter.dimension(function(d) {return +d.Year;}),
    spendDim = xfilter.dimension(function(d) {return Math.floor(d.Spent/10);}),
    nameDim  = xfilter.dimension(function(d) {return d.Name;}),

    spendPerYear = yearDim.group().reduceSum(function(d) {return +d.Spent;}),
    spendPerName = nameDim.group().reduceSum(function(d) {return +d.Spent;});
function render_plots(){
    yearRingChart
        .width(200).height(200)
        .dimension(yearDim)
        .group(spendPerYear)
        .innerRadius(50);
    spenderRowChart
        .width(250).height(200)
        .dimension(nameDim)
        .group(spendPerName)
        .elasticX(true);
    dc.renderAll();
}

NOTE here and here might be related, it's on charts interactivity or not being linked.
good chart example in an answer here


EDIT1

see this fiddle

with the 2nd graph if I change this line .group(spendPerName) to this .group(spendPerYear) I would now be grouping by the same grouping on both the charts. this changes the charts interactivity.

Now I can select 2012 on the row chart and it will be highlighted. And I can toggle this from highlighted to unhighlighted. But when it is highlighted and I select another year in the row chart, they all collapse(dissapear). All the while nothing is happening on the ring chart.

With the ring chart I can select a year, and it will be highlighted, toggling this will highlight the year, then the whole ring. But again all the while nothing is happening on the row chart.

So it effectively has lost the interactivity. This is probably a silly example but it might help me understand it a bit better. why has it lost the interactivity? Or put another way, how can I present the data the same way in the graphs and not lose the interactivity? So if I select 2012 on the row chart this would be highlighted (or be shown as the whole ring) on the ring chart? maybe it is to do with my dataset.

might be useful: Why are some of my charts not filtering?

HattrickNZ
  • 4,373
  • 15
  • 54
  • 98
  • 1
    The Crossfilter library handles coordinating the filters on your data and updating all dimensions and groups that have been created after a dimension is filtered. The dc.js library handles coordinating the charts, so after a chart applies a filter, dc.js signals all the other charts in the chart group to update themselves by re-querying the Crossfilter dimensions/groups they use. – Ethan Jewett Sep 15 '16 at 15:38
  • @EthanJewett tks if I could pose the question another way in edit1 maybe you could help me understand it better? – HattrickNZ Sep 16 '16 at 03:31

1 Answers1

4

I'll answer only edit1, since your original question seems pretty broad.

There are two important facts here:

  1. Data comes from groups, and filters are applied through dimensions. You might think of the group as the view, the dimension as the controller, and the crossfilter as the model. Crossfilter doesn't fit that pattern exactly, but the concept does apply of always writing to one type of object, and reading from another object which reflects the changes.
  2. A group will not observe changes to its own dimension. This supports the common use case where each chart has its own dimension and reads data from a group on that dimension. You usually don't want a chart to filter itself.

So your groups should almost always match your dimensions. Having a name dimension for a chart that is displaying years does not make sense on the face of it, and what will happen is that it will attempt to filter by values which are not in the dimension.

I have no idea why it works for the first click, but on the second click it will register a filter function which will exclude everything but, say, 2012 and 2014, from the name dimension - so nothing will match.

Also, because of point 2, the row chart's group is observing the row chart's dimension, causing it to disappear. You usually don't want a chart to observe its own filters.

Two charts filtering each other

If you want the two charts to filter each other, duplicate the dimension and group so that they will observe each other:

    yearDim  = xfilter.dimension(function(d) {return +d.Year;}),
    yearDim2 = xfilter.dimension(function(d) {return +d.Year;}),
    spendPerYear = yearDim.group().reduceSum(function(d) {return +d.Spent;}),
    spendPerYear2 = yearDim2.group().reduceSum(function(d) {return +d.Spent;}),

    yearRingChart
        .width(200).height(200)
        .dimension(yearDim)
        .group(spendPerYear)
        .innerRadius(50);
    spenderRowChart
        .width(250).height(200)
        .dimension(yearDim2)
        .group(spendPerYear2)
        .elasticX(true);

https://jsfiddle.net/gordonwoodhull/yodzpnsL/1/

Two charts with "linked brushing"

If you want the two charts to apply to the same dimension, and not filter each other but have their highlights synched, that's something that's not directly supported by dc.js. dc.js doesn't have any way of knowing what charts are sharing a dimension, and where the highlights can be shared.

I've done some experiments with "filter groups" to explicitly set multiple charts to use the same filter. You'll still have to tell dc.js which charts to link. The enhancement request is https://github.com/dc-js/dc.js/issues/681

This isn't ready, but you can simulate it now. Here is a function that builds an event listener that reflects the filter state to other specified charts:

    function reflect_filters(targets) {
        var recursionGuard = false; // don't recurse forever
        if(!Array.isArray(targets))
            targets = [targets];
        return function(chart) {
            if(recursionGuard)
                return;
            recursionGuard = true;
            targets.forEach(function(target) {
                target.replaceFilter(chart.filters() ? [chart.filters()] : null);
            });
            recursionGuard = false;
        }
    }

For this to work, we want the charts to share the same dimension and group:

    yearRingChart
        .width(200).height(200)
        .dimension(yearDim)
        .group(spendPerYear)
        .innerRadius(50);
    spenderRowChart
        .width(250).height(200)
        .dimension(yearDim)
        .group(spendPerYear)
        .elasticX(true);

Apply reflect_filters like this:

    yearRingChart.on('filtered', reflect_filters(spenderRowChart));
    spenderRowChart.on('filtered', reflect_filters(yearRingChart));

(Pass an array of charts if you have more than two charts you want linked.)

Another fork: https://jsfiddle.net/gordonwoodhull/yodzpnsL/10/

Woof. So there's two answers to the narrow question. The broad question, one could write a book!

Gordon
  • 19,811
  • 4
  • 36
  • 74