1
votes

I have a dashboard where I'm showing Headcount over time. One is a line Graph that shows headcount over time period, the other is a rowChart that is split by HCLevel1 - that is simply there to allow users to filter.

I would like the rowChart to show Heads for the latest period within the date filter (rather than showing the full sum of heads for the full period which would be wrong).

I can do this by combining two fields into a dimension, but the problem with this is that when I use the rowChart to filter by business, I only see one month in the line chart - whereas I'd like to see the full period that's filtered. I can't work out how I could do this with a fake group, because the rowChart's dimension/key is HCLevel1.

My data is formatted like this:

var data =  = [
{
  "HCLevel1": "Commercial",
  "HCLevel2": "Portfolio TH",
  "Period": 201407,
  "Heads": 720
},

I've tried to use this custom reduce (picked up from another SO question) but it doesn't work correctly (minus values, incorrect values etc).

function reduceAddAvgPeriods(p, v) {
    if (v.Period in p.periodsArray) {
        p.periodsArray[v.Period] += v.Heads;
    } else {
        p.periodsArray[v.Period] = 0;
        p.periodCount++;
    }
    p.heads += v.Heads;
    return p;
}

Currently, my jsfiddle example is combining 2 fields for the dimension, but as you can see, I can't then filter using the rowChart to show me the full period on the line chart.

I can use reductio to give me the average, but I'd like to provide actual Heads value for most recent date filtered.

https://jsfiddle.net/kevinelphick/4ybekqey/3/

I hope this is possible, any help would be much appreciated, thanks!

1

1 Answers

1
votes

I glanced at this a few days ago, but it took me a little while to figure out. Tricky!

We can restrict the design by considering these two facts:

  1. We want to filter the row chart by "Level". That's simply

    var dimLevel = cf.dimension(function (d) { return d.HCLevel1 || ''; });
    
  2. A group does not observe its own dimension's filters. So we probably want to use the dimension from #1 to produce the data (the group) for the row chart.

Given these two restrictions, maybe we can dimension and group by level, but inside the bins of the group, keep track of the periods that contribute to that bin?

This is a common pattern often used for stacked charts:

var levelPeriodGroup = dimLevel.group().reduce(
    function(p, v) {
        p[v.Period] = (p[v.Period] || 0) + v.Heads;
        return p;
    },
    function(p, v) {
        p[v.Period] -= v.Heads;
        return p;
    },
    function() {
        return {};
    }
);

Here, we'll just 'peel off' the top stack, dropping any zeros:

function last_period(group, maxPeriod) {
    return {
        all: function() {
            var max = maxPeriod();
            return group.all().map(function(kv) {
                return {key: kv.key, value: kv.value[max]};
            }).filter(function(kv) {
                return kv.value > 0;
            });
        }
    };
}

To keep last_period somewhat general, maxPeriod is now a function, which we'll define like this:

function max_period() {
    return dimPeriod.top(1)[0].Period;
}

Bringing it all together and supplying it to the row chart:

rowChart
    .group(last_period(levelPeriodGroup, max_period))
    .dimension(dimLevel)
    .elasticX(true);

Since the period is no longer part of the labels of the chart, we can put it in a headline:

<h4>Last Period: <span id="last-period"></span></h4>

and update it whenever the row chart is drawn:

rowChart.on('pretransition', function(chart) {
    d3.select('#last-period').text(max_period());
});