Crossfilter reduce :: find number of uniques
Asked Answered
S

1

5

I am trying to create a custom reduce function for a dataset attribute group that would sum a number of unique values for another attribute.

For example, my dataset looks like a list of actions on projects by team members:

{ project:"Website Hosting", teamMember:"Sam", action:"email" },
{ project:"Website Hosting", teamMember:"Sam", action:"phoneCall" },
{ project:"Budjet", teamMember:"Joe", action:"email" },
{ project:"Website Design", teamMember:"Joe", action:"design" },
{ project:"Budget", teamMember:"Sam", action:"email" }

So, team members work on a variable number of projects by performing one action per line. I have a dimension by team member, and would like to reduce it by the number of projects (uniques).

I tried the below (storing project in a uniques array) without success (sorry, this might hurt your eyes):

var teamMemberDimension = dataset.dimension(function(d) {
    return d.teamMember;
});

        var teamMemberDimensionGroup = teamMemberDimension.group().reduce(
            // add
            function(p,v) {
                if( p.projects.indexOf(v.project) == -1 ) {
                    p.projects.push(v.project);
                    p.projectsCount += 1;
                }
                return p;
            },
            // remove
            function(p,v) {
                if( p.projects.indexOf(v.projects) != -1 ) {
                    p.projects.splice(p.projects.indexOf(v.projects), 1);
                    p.projectsCount -= 1;
                }
                return p;
            },
            // init
            function(p,v) {
                return { projects:[], projectsCount:0 }
            }
        );

Thanks a lot!

Edit after DJ Martin's answer ::

So, to be clearer, I would like to get the numbers I am after here would be:

-----------
Sam : 2 (projects he is workin on, no matter the number of actions)
Joe : 2 (projects he is workin on, no matter the number of actions)
-----------

The answer provided by DJ Martin gets me there. But rather than hard coding a table, I would like to find a way to use these numbers for my DC.JS bar chart. When I was only using the number of actions (so just a reduceCount() ), I did it like below:

teamMemberChart.width(270)
    .height(220)
    .margins({top: 5, left: 10, right: 10, bottom: 20})
    .dimension(teamMemberDimension)
    .group(teamMemberDimensionGroup)
    .colors(d3.scale.category20())
    .elasticX(true)
    .xAxis().ticks(4);

I guess there might be something to change in the group().

Sevastopol answered 20/1, 2014 at 16:56 Comment(0)
E
16

UPDATED ANSWER

Sorry I misunderstood the question... you are actually on the right track. You'll just need to maintain a count of each project so that your subtract function can know when to remove the value.

teamMemberGroup = teamMemberDimension.group().reduce(

        function (p, d) {
            if( d.project in p.projects)
                p.projects[d.project]++;
            else p.projects[d.project] = 1;
            return p;
        },

        function (p, d) {
            p.projects[d.project]--;
            if(p.projects[d.project] === 0)
                delete p.projects[d.project];
            return p;
        },

        function () {
            return {projects: {}};
        });

Here is an updated fiddle: http://jsfiddle.net/djmartin_umich/3LyhL/

Emotionality answered 20/1, 2014 at 22:10 Comment(8)
Thanks a lot for your answer! It did not cross my mind to combine fields but it makes a lot of sense. The issue I have with this solution is that the end result doesn't really produce the numbers I am after. Sorry if it was not clear, but I try to obtain something like: Sam - (workin on) 2 projects (no matter how many actions) Joe - (workin on) 2 projects (no matter how many actions)Sevastopol
Ahh, I see. Updated the answer to achieve this.Emotionality
Also I think the associative array {} helped in this case.Emotionality
Great, thanks! That gives me the numbers (although I am still unsure why my solution did not work - maybe I should not use an array in this function). I have added the last bit of my problem because I cannot see how to feed these numbers to the chart.Sevastopol
I added a rowChart to the fiddle. The key is to use a valueAccessor. Other charts will work similarly, though I think the rowChart makes more sense than a bar chart in this case...Emotionality
.valueAccessor!!! That's the one I completely missed in the doc! Thanks a million!Sevastopol
@DJMartin The example does not work anymore. Probably one of the updates screwed something up.Kinchinjunga
@Kinchinjunga - The d3 repository moved, references are now updated. Thanks.Emotionality

© 2022 - 2024 — McMap. All rights reserved.