首页 文章

d3 / dc.js - 如何在告诉crossfilter将数组中的元素视为单独的记录时创建堆积条形图?

提问于
浏览
3

NEW: 我在我的解决方案中发布的小提琴起作用(https://jsfiddle.net/jnf84n7c/) . 但是,当我尝试在我的项目中实现策略时,我是第一个图,我收到一条错误消息 .

未捕获的TypeError:a.group.all不是函数(错误位于dc.min.js中)

知道为什么它适用于小提琴但不适用于我的ruby-on-rails应用程序?

New code

var data = [
    {"key":"KEY-1","state":"MA","status":["A","R","C"],"items":["orange","meat","bread"],"date":"Y16"},
    {"key":"KEY-2","state":"MA","status":["A","O"],"items":["apple","bread"],"date":"Y15"},
    {"key":"KEY-3","state":"TX","status":["O"],"items":["bread"],"date":"Y16"},
    {"key":"KEY-4","state":"TN","status":["A","R"],"items":["apple","bread"],"date":"Y16"},
    {"key":"KEY-5","state":"TN","status":["A","O"],"items":["apple","orange"],"date":"Y15"},
    {"key":"KEY-6","state":"TN","status":[],"items":[],"date":"Y14"}
];
var cf = crossfilter(data);
var dates       = cf.dimension(function(d){ return d.date; });
var datesGroup  = dates.group();
var states      = cf.dimension(function(d){ return d.state; });
var statesGroup = states.group();
var itemsDim    = cf.dimension(function(d){ return d.items; });
var itemsGroup  = itemsDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value();
itemsGroup.all  = myAllFunction;
var states_items_group_apple  = states.group().reduce(reduceAdd_apple,  reduceRemove_apple,  reduceInitial_items);
var states_items_group_bread  = states.group().reduce(reduceAdd_bread,  reduceRemove_bread,  reduceInitial_items);
var states_items_group_orange = states.group().reduce(reduceAdd_orange, reduceRemove_orange, reduceInitial_items);
var states_items_group_meat   = states.group().reduce(reduceAdd_meat,   reduceRemove_meat,   reduceInitial_items);
var itemsGroup1  = itemsDim.groupAll().reduce(reduceAdd1, reduceRemove1, reduceInitial).value();
var itemsGroup2  = itemsDim.groupAll().reduce(reduceAdd2, reduceRemove2, reduceInitial).value();
var itemsGroup3  = itemsDim.groupAll().reduce(reduceAdd3, reduceRemove3, reduceInitial).value();
itemsGroup1.all  = myAllFunction;
itemsGroup2.all  = myAllFunction;
itemsGroup3.all  = myAllFunction;
var status       = cf.dimension(function(d){ return d.status; });
var statusGroup1 = status.groupAll().reduce(reduceAdd_group1, reduceRemove_group1, reduceInitial_group).value();
var statusGroup2 = status.groupAll().reduce(reduceAdd_group2, reduceRemove_group2, reduceInitial_group).value();
var statusGroup3 = status.groupAll().reduce(reduceAdd_group3, reduceRemove_group3, reduceInitial_group).value();
var statusGroup4 = status.groupAll().reduce(reduceAdd_group4, reduceRemove_group4, reduceInitial_group).value();
statusGroup1.all = myAllFunction;
statusGroup2.all = myAllFunction;
statusGroup3.all = myAllFunction;
statusGroup4.all = myAllFunction;
var statusGroup  = status.groupAll().reduce(reduceAdd_group, reduceRemove_group, reduceInitial_group).value();
statusGroup.all  = myAllFunction;
var row = dc.rowChart("#rowchart");
row.height(170)
   .dimension(itemsDim)
   .group(itemsGroup)
   .ordering(function(d){return -d.value;})
   .renderLabel(true)
   .ordinalColors(["#008600","#80FF80","#FF80FF","#860086"])
   .xAxis().ticks(3);
row.filterHandler(myFilterFunction);
var pie1 = dc.pieChart("#piechart1");
pie1.height(75).width(75)
    .dimension(dates)
    .group(datesGroup);
var pie2 = dc.pieChart("#piechart2");
pie2.height(75).width(75)
    .dimension(states)
    .group(statesGroup);
var pie3 = dc.pieChart("#piechart3");
pie3.height(75).width(75)
    .dimension(status)
    .group(statusGroup);
pie3.filterHandler(myFilterFunction);
var bar = dc.barChart("#barchart");
bar.width(500).height(200)
   .dimension(states)
   .group(states_items_group_bread,  'bread')
   .stack(states_items_group_orange, 'orange')
   .stack(states_items_group_apple,  'apple')
   .stack(states_items_group_meat,   'meat')
   .valueAccessor(function(p){ return p.value.count; })
   .renderHorizontalGridLines(true)
   .renderLabel(true)
   .legend(dc.legend().x(100).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(100))
   .gap(10)
   .elasticX(true).elasticY(true)
   .yAxisLabel("count")
   .x(d3.scale.ordinal())
   .xUnits(dc.units.ordinal)
   .margins({top:30,left:50,right:10,bottom:50});    
var bar2 = dc.barChart("#barchart2");
bar2.width(500).height(200)
    .dimension(itemsDim)
    .group(itemsGroup1,'MA')
    .stack(itemsGroup2,'TN')
    .stack(itemsGroup3,'TX')
    .renderHorizontalGridLines(true)
    .renderLabel(true)
    .legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60))
    .gap(10)
    .yAxisLabel("count")
    .x(d3.scale.ordinal())
    .xUnits(dc.units.ordinal)
    .ordinalColors(["#008600","#80FF80","#FF80FF","#860086"])
    .margins({top:30,left:50,right:10,bottom:50});
bar2.filterHandler(myFilterFunction);
var bar3 = dc.barChart("#barchart3");
bar3.width(500).height(200)
    .dimension(status)
    .group(statusGroup1,"bread")
    .stack(statusGroup2,"apple")
    .stack(statusGroup3,"orange")
    .stack(statusGroup4,"meat")
    .renderHorizontalGridLines(true)
    .renderLabel(true)
    .legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60))
    .gap(10)
    .yAxisLabel("count")
    .x(d3.scale.ordinal())
    .xUnits(dc.units.ordinal)
    .margins({top:30,left:50,right:10,bottom:50});
bar3.filterHandler(myFilterFunction);
dc.renderAll();
function reduceAdd(p,v){
    if (v.items[0] === "") return p;
    v.items.forEach(function(val,idx){
        p[val] = (p[val] || 0) + 1;
    });
    return p;
}
function reduceRemove(p,v){
    if (v.items[0] === "") return p;
    v.items.forEach(function(val,idx){
        p[val] = (p[val] || 0) - 1;
    });
    return p;
}
function reduceInitial(){
    return {
        bread: 0,
        apple: 0,
        orange: 0,
        meat: 0
    };
}
function reduceAdd1(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "MA"){
        v.items.forEach(function(val,idx){
            p.bread  += (val === 'bread'  ? 1 : 0);
            p.apple  += (val === 'apple'  ? 1 : 0);
            p.orange += (val === 'orange' ? 1 : 0);
            p.meat   += (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceRemove1(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "MA"){
        v.items.forEach(function(val,idx){
            p.bread  -= (val === 'bread'  ? 1 : 0);
            p.apple  -= (val === 'apple'  ? 1 : 0);
            p.orange -= (val === 'orange' ? 1 : 0);
            p.meat   -= (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceAdd2(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "TN"){
        v.items.forEach(function(val,idx){
            p.bread  += (val === 'bread'  ? 1 : 0);
            p.apple  += (val === 'apple'  ? 1 : 0);
            p.orange += (val === 'orange' ? 1 : 0);
            p.meat   += (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceRemove2(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "TN"){
        v.items.forEach(function(val,idx){
            p.bread  -= (val === 'bread'  ? 1 : 0);
            p.apple  -= (val === 'apple'  ? 1 : 0);
            p.orange -= (val === 'orange' ? 1 : 0);
            p.meat   -= (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceAdd3(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "TX"){
        v.items.forEach(function(val,idx){
            p.bread  += (val === 'bread'  ? 1 : 0);
            p.apple  += (val === 'apple'  ? 1 : 0);
            p.orange += (val === 'orange' ? 1 : 0);
            p.meat   += (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceRemove3(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "TX"){
        v.items.forEach(function(val,idx){
            p.bread  -= (val === 'bread'  ? 1 : 0);
            p.apple  -= (val === 'apple'  ? 1 : 0);
            p.orange -= (val === 'orange' ? 1 : 0);
            p.meat   -= (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceAdd_apple(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count += (val === 'apple' ? 1 : 0);
    });
    return p;
}
function reduceRemove_apple(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count -= (val === 'apple' ? 1 : 0);
    });
    return p;
}
function reduceAdd_bread(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count += (val === 'bread' ? 1 : 0);
    });
    return p;
}
function reduceRemove_bread(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count -= (val === 'bread' ? 1 : 0);
    });
    return p;
}
function reduceAdd_orange(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count += (val === 'orange' ? 1 : 0);
    });
    return p;
}
function reduceRemove_orange(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count -= (val === 'orange' ? 1 : 0);
    });
    return p;
}
function reduceAdd_meat(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count += (val === 'meat' ? 1 : 0);
    });
    return p;
}
function reduceRemove_meat(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count -= (val === 'meat' ? 1 : 0);
    });
    return p;
}
function reduceAdd_group1(p,v){
    if (v.items[0]  === "") return p;
    if (v.status[0] === "") return p;
    v.items.forEach(function(val1,idx1){
        if (val1 === "bread"){
            v.status.forEach(function(val2,idx2){
                if(idx1 === idx2){
                p.A += (val2 === 'A' ? 1 : 0);
                p.O += (val2 === 'O' ? 1 : 0);
                p.C += (val2 === 'C' ? 1 : 0);
                p.R += (val2 === 'R' ? 1 : 0);
                }
            });
        }
    });
    return p;
}
function reduceRemove_group1(p,v){
    if (v.items[0]  === "") return p;
    if (v.status[0] === "") return p;
    v.items.forEach(function(val1,idx1){
        if(val1 === "bread"){
            v.status.forEach(function(val2,idx2){
                if(idx1 === idx2){
                p.A -= (val2 === 'A' ? 1 : 0);
                p.O -= (val2 === 'O' ? 1 : 0);
                p.C -= (val2 === 'C' ? 1 : 0);
                p.R -= (val2 === 'R' ? 1 : 0);
                }
            });
        }
    });
    return p;
}
function reduceAdd_group2(p,v){
    if (v.items[0]  === "") return p;
    if (v.status[0] === "") return p;
    v.items.forEach(function(val1,idx1){
        if(val1 === "apple"){
            v.status.forEach(function(val2,idx2){
                if(idx1 === idx2){
                p.A += (val2 === 'A' ? 1 : 0);
                p.O += (val2 === 'O' ? 1 : 0);
                p.C += (val2 === 'C' ? 1 : 0);
                p.R += (val2 === 'R' ? 1 : 0);
                }
            });
        }
    });
    return p;
}
function reduceRemove_group2(p,v){
    if (v.items[0]  === "") return p;
    if (v.status[0] === "") return p;
    v.items.forEach(function(val1,idx1){
        if(val1 === "apple"){
            v.status.forEach(function(val2,idx2){
                if(idx1 === idx2){
                p.A -= (val2 === 'A' ? 1 : 0);
                p.O -= (val2 === 'O' ? 1 : 0);
                p.C -= (val2 === 'C' ? 1 : 0);
                p.R -= (val2 === 'R' ? 1 : 0);
                }
            });
        }
    });
    return p;
}
function reduceAdd_group3(p,v){
    if (v.items[0]  === "") return p;
    if (v.status[0] === "") return p;
    v.items.forEach(function(val1,idx1){
        if(val1 === "orange"){
            v.status.forEach(function(val2,idx2){
                if(idx1 === idx2){
                p.A += (val2 === 'A' ? 1 : 0);
                p.O += (val2 === 'O' ? 1 : 0);
                p.C += (val2 === 'C' ? 1 : 0);
                p.R += (val2 === 'R' ? 1 : 0);
                }
            });
        }
    });
    return p;
}
function reduceRemove_group3(p,v){
    if (v.items[0]  === "") return p;
    if (v.status[0] === "") return p;
    v.items.forEach(function(val1,idx1){
        if(val1 === "orange"){
            v.status.forEach(function(val2,idx2){
                if(idx1 === idx2){
                p.A -= (val2 === 'A' ? 1 : 0);
                p.O -= (val2 === 'O' ? 1 : 0);
                p.C -= (val2 === 'C' ? 1 : 0);
                p.R -= (val2 === 'R' ? 1 : 0);
                }
            });
        }
    });
    return p;
}
function reduceAdd_group4(p,v){
    if (v.items[0]  === "") return p;
    if (v.status[0] === "") return p;
    v.items.forEach(function(val1,idx1){
        if(val1 === "meat"){
            v.status.forEach(function(val2,idx2){
                if(idx1 === idx2){
                p.A += (val2 === 'A' ? 1 : 0);
                p.O += (val2 === 'O' ? 1 : 0);
                p.C += (val2 === 'C' ? 1 : 0);
                p.R += (val2 === 'R' ? 1 : 0);
                }
            });
        }
    });
    return p;
}
function reduceRemove_group4(p,v){
    if (v.items[0]  === "") return p;
    if (v.status[0] === "") return p;
    v.items.forEach(function(val1,idx1){
        if(val1 === "meat"){
            v.status.forEach(function(val2,idx2){
                if(idx1 === idx2){
                p.A -= (val2 === 'A' ? 1 : 0);
                p.O -= (val2 === 'O' ? 1 : 0);
                p.C -= (val2 === 'C' ? 1 : 0);
                p.R -= (val2 === 'R' ? 1 : 0);
                }
            });
        }
    });
    return p;
}
function reduceAdd_group(p,v){
    if (v.status[0] === "") return p;
    v.status.forEach(function(val,idx){
        p[val] = (p[val] || 0) + 1;
    });
    return p;
}
function reduceRemove_group(p,v){
    if (v.status[0] === "") return p;
    v.status.forEach(function(val,idx){
        p[val] = (p[val] || 0) - 1;
    });
    return p;
}
function reduceInitial_group(){
    return {
        A: 0,
        O: 0,
        C: 0,
        R: 0
    };
}
function reduceInitial_items(){
    return {
        count: 0,
        state: ''
    };
}
//filter function:
function myFilterFunction(dimension,filters){
    dimension.filter(null);
    if (filters.length === 0)
        dimension.filter(null);
    else
        dimension.filterFunction(function(d){
            for(var i=0; i<d.length; i++){
                if (filters.indexOf(d[i]) >= 0) return true;
            }
            return false;
        });
    return filters;
}
function myAllFunction(){
    var newObject = [];
    for(var key in this){
        if(this.hasOwnProperty(key) && key != "all"){
            newObject.push({
                key: key,
                value: this[key]
            });
        }
    }
    return newObject;
};

Old Question: 我很抱歉再创一个问题 . 不幸的是,我无法评论其他帖子来提问我的问题 . 与我的相似的两个问题是:dc.js - how to group by unique idIs there a way to tell crossfilter to treat elements of array as separate records instead of treating whole array as single key?

我正在使用后一个解释的代码 . 但是,我希望能够堆叠 . 正如您将能够在jsfiddle中看到的那样,底部条形图不会列出x轴中的项目,而是堆叠不同的状态计数 . 任何帮助将不胜感激 . 谢谢!

这是最初的小提琴:https://jsfiddle.net/7qwqcakr/1/

我几乎有这个小提琴:https://jsfiddle.net/wq0ed5hr/但是堆积的条形图都是一种颜色,即使图例将它们作为不同的颜色 . 如何修复颜色问题?

修复了颜色问题:https://jsfiddle.net/rmc2zpr4/

现在唯一的问题是处理“计数问题”,正如我在下面的解决方案和评论中所解释的那样 .

这是 updated 代码:

var data = [
    {"key":"KEY-1","state":"MA","items":["orange","meat","bread"],"date":"Y16"},
    {"key":"KEY-2","state":"MA","items":["apple","bread"],"date":"Y15"},
    {"key":"KEY-3","state":"TX","items":["bread"],"date":"Y16"},
    {"key":"KEY-4","state":"TN","items":["apple","bread"],"date":"Y16"},
    {"key":"KEY-5","state":"TN","items":["apple","orange"],"date":"Y15"},
    {"key":"KEY-6","state":"TN","items":[],"date":"Y14"}
];
var cf = crossfilter(data);
var dates       = cf.dimension(function(d){ return d.date; });
var datesGroup  = dates.group().reduceCount(function(d){ return d.key; });
var states      = cf.dimension(function(d){ return d.state; });
var statesGroup = states.group().reduceCount(function(d){ return d.key; });
var itemsDim    = cf.dimension(function(d){ return d.items; });
var itemsGroup  = itemsDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value();
itemsGroup.all  = myAllFunction;
var statesDim   = cf.dimension(function(d){ return d.state; });
var states_items_group_apple  = statesDim.group().reduce(reduceAdd_apple,  reduceRemove_apple,  reduceInitial_items);
var states_items_group_bread  = statesDim.group().reduce(reduceAdd_bread,  reduceRemove_bread,  reduceInitial_items);
var states_items_group_orange = statesDim.group().reduce(reduceAdd_orange, reduceRemove_orange, reduceInitial_items);
var states_items_group_meat   = statesDim.group().reduce(reduceAdd_meat,   reduceRemove_meat,   reduceInitial_items);
var items        = cf.dimension(function(d){ return d.items; })
var itemsGroup1  = items.groupAll().reduce(reduceAdd1, reduceRemove1, reduceInitial).value();
var itemsGroup2  = items.groupAll().reduce(reduceAdd2, reduceRemove2, reduceInitial).value();
var itemsGroup3  = items.groupAll().reduce(reduceAdd3, reduceRemove3, reduceInitial).value();
itemsGroup1.all  = myAllFunction;
itemsGroup2.all  = myAllFunction;
itemsGroup3.all  = myAllFunction;
var row = dc.rowChart("#rowchart");
row.height(170)
   .dimension(itemsDim)
   .group(itemsGroup)
   .ordering(function(d){return -d.value;})
   .renderLabel(true)
       .ordinalColors(["#008600","#80FF80","#FF80FF","#860086"])
   .xAxis().ticks(3);
row.filterHandler(myFilterFunction);
var pie1 = dc.pieChart("#piechart1");
pie1.height(75).width(75)
    .dimension(dates)
    .group(datesGroup);
var pie2 = dc.pieChart("#piechart2");
pie2.height(75).width(75)
    .dimension(states)
    .group(statesGroup);
var bar = dc.barChart("#barchart");
bar.width(500).height(200)
   .dimension(statesDim)
   .group(states_items_group_bread,  'bread')
   .stack(states_items_group_orange, 'orange')
   .stack(states_items_group_apple,  'apple')
   .stack(states_items_group_meat,   'meat')
   .valueAccessor(function(p){ return p.value.count; })
   .renderHorizontalGridLines(true)
   .renderLabel(true)
   .legend(dc.legend().x(100).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(100))
   .gap(10)
   .elasticX(true).elasticY(true)
   .yAxisLabel("count")
   .x(d3.scale.ordinal())
   .xUnits(dc.units.ordinal)
   .margins({top:30,left:50,right:10,bottom:50});
var bar2 = dc.barChart("#barchart2");
bar2.width(500).height(200)
    .dimension(items)
    .group(itemsGroup1,'MA')
    .stack(itemsGroup2,'TN')
    .stack(itemsGroup3,'TX')
    .renderHorizontalGridLines(true)
    .renderLabel(true)
    .legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60))
    .gap(10)
    .yAxisLabel("count")
    .x(d3.scale.ordinal())
    .xUnits(dc.units.ordinal)
    .ordinalColors(["#008600","#80FF80","#FF80FF","#860086"])
    .margins({top:30,left:50,right:10,bottom:50});
bar2.filterHandler(myFilterFunction);
dc.renderAll();
//reduce functions:
function reduceAdd(p,v){
    if (v.items[0] === "") return p;
    v.items.forEach(function(val,idx){
        p[val] = (p[val] || 0) + 1;
    });
    return p;
}
function reduceRemove(p,v){
    if (v.items[0] === "") return p;
    v.items.forEach(function(val,idx){
        p[val] = (p[val] || 0) - 1;
    });
    return p;
}
function reduceInitial(){
    return {
        bread: 0,
        apple: 0,
        orange: 0,
        meat: 0
    };
}
function reduceAdd1(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "MA"){
        v.items.forEach(function(val,idx){
            p.bread  += (val === 'bread'  ? 1 : 0);
            p.apple  += (val === 'apple'  ? 1 : 0);
            p.orange += (val === 'orange' ? 1 : 0);
            p.meat   += (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceRemove1(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "MA"){
        v.items.forEach(function(val, idx){
            p.bread  -= (val === 'bread'  ? 1 : 0);
            p.apple  -= (val === 'apple'  ? 1 : 0);
            p.orange -= (val === 'orange' ? 1 : 0);
            p.meat   -= (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceAdd2(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "TN"){
        v.items.forEach(function(val,idx){
            p.bread  += (val === 'bread'  ? 1 : 0);
            p.apple  += (val === 'apple'  ? 1 : 0);
            p.orange += (val === 'orange' ? 1 : 0);
            p.meat   += (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceRemove2(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "TN"){
        v.items.forEach(function(val,idx){
            p.bread  -= (val === 'bread'  ? 1 : 0);
            p.apple  -= (val === 'apple'  ? 1 : 0);
            p.orange -= (val === 'orange' ? 1 : 0);
            p.meat   -= (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceAdd3(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "TX"){
        v.items.forEach(function(val,idx){
            p.bread  += (val === 'bread'  ? 1 : 0);
            p.apple  += (val === 'apple'  ? 1 : 0);
            p.orange += (val === 'orange' ? 1 : 0);
            p.meat   += (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceRemove3(p,v){
    if (v.items[0] === "") return p;
    if (v.state === "TX"){
        v.items.forEach(function(val,idx){
            p.bread  -= (val === 'bread'  ? 1 : 0);
            p.apple  -= (val === 'apple'  ? 1 : 0);
            p.orange -= (val === 'orange' ? 1 : 0);
            p.meat   -= (val === 'meat'   ? 1 : 0);
        });
    }
    return p;
}
function reduceAdd_apple(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count += (val === 'apple' ? 1 : 0);
    });
    return p;
}
function reduceRemove_apple(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count -= (val === 'apple' ? 1 : 0);
    });
    return p;
}
function reduceAdd_bread(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count += (val === 'bread' ? 1 : 0);
    });
    return p;
}
function reduceRemove_bread(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count -= (val === 'bread' ? 1 : 0);
    });
    return p;
}
function reduceAdd_orange(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count += (val === 'orange' ? 1 : 0);
    });
    return p;
}
function reduceRemove_orange(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count -= (val === 'orange' ? 1 : 0);
    });
    return p;
}
function reduceAdd_meat(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count += (val === 'meat' ? 1 : 0);
    });
    return p;
}
function reduceRemove_meat(p,v){
    if (v.items[0] === "") return p;
    p.state = v.state;
    v.items.forEach(function(val,idx){
        p.count -= (val === 'meat' ? 1 : 0);
    });
    return p;
}
function reduceInitial_items(){
    return {
        count: 0,
        state: ''
    };
}
function myFilterFunction(dimension,filters){
    dimension.filter(null);
    if(filters.length === 0)
        dimension.filter(null);
    else
        dimension.filterFunction(function(d){
            for(var i=0; i<d.length; i++){
                if(filters.indexOf(d[i]) >= 0) return true;
            }
            return false;
        });
    return filters;
}
function myAllFunction(){
    var newObject = [];
    for(var key in this){
        if(this.hasOwnProperty(key) && key != "all"){
            newObject.push({
                key: key,
                value: this[key]
            });
        }
    }
    return newObject;
};

2 回答

  • 1

    您需要做的第一件事就是升级到:

    • dc.js 2.0测试版

    • Crossfilter 1.4.0-beta.06(Crossfilter现居住在这里:https://github.com/crossfilter/crossfilter

    • Reductio(推荐),以便您不要't have to manually build custom groupings - this not strictly necessary, but groupings are the source of a lot of problems, so I'建议使用ReductioUniverse来利用之前的工作 .

    接下来,凭借所有这些新的优点,我们可以简化一件事 . 这是使用这些库的新功能的更新小提琴:https://jsfiddle.net/ff8ox8vq/

    我将在下面的完整代码示例中详细介绍它们 .

    var data = [
        {"key":"KEY-1","state":"MA", "items":["orange", "meat", "bread"], "date":"Y16"},
        {"key":"KEY-2","state":"MA", "items":["apple", "bread"], "date":"Y15"},
        {"key":"KEY-3","state":"TX", "items":["bread"], "date":"Y16"},
        {"key":"KEY-4","state":"TN", "items":["apple", "bread"], "date":"Y16"},
        {"key":"KEY-5","state":"TN", "items":["apple", "orange"], "date":"Y15"},
        {"key":"KEY-6","state":"TN", "items": [], "date":"Y14"}
    ];
    
    var cf = crossfilter(data);
    

    上面没有变化 .

    //dimensions and groups:
    var dates       = cf.dimension(function(d){ return d.date; });
    var datesGroup  = dates.group();
    var states      = cf.dimension(function(d){ return d.state; });
    var statesGroup = states.group()
    

    .reduceCount 是组的默认设置 . 在新组上调用它不会做任何事情 . reduceCount 也不带任何参数(与 reduceSum 不同) . 所以我们摆脱它 .

    var itemsDim    = cf.dimension(function(d){ return d.items; }, true);
    var itemsGroup  = itemsDim.group();
    

    这是它开始变得有趣的地方 . Crossfilter 1.4.0在维度调用上支持"Array dimension"标志 . 如果我们将其设置为 true ,则Crossfilter知道 items 是一个数组,并且它将如何处理它 . 您不再需要覆盖 .all 方法或类似的东西 . 它是内部处理的 .

    var addValueGroup = function(reducer, key) {
        reducer
        .value(key)
        .filter(function(d) { return d.items.indexOf(key) !== -1; })
        .count(true)
    }
    

    用于将特定于项目的计数添加到状态组的实用程序功能 .

    // Reductio nest to break down states by item
    var reducer = reductio().count(true)
    addValueGroup(reducer, "orange")
    addValueGroup(reducer, "meat")
    addValueGroup(reducer, "bread")
    addValueGroup(reducer, "apple")
    
    reducer(statesGroup);
    

    配置 statesGroup 的分组 . Reductio只是构建自定义缩减功能 . 这里发生的是我们维护状态中所有记录的顶级计数,然后我们为每种类型的项创建过滤计数 . 在此运行之后执行 console.log(statesGroup.all()) 以查看结果组的结构 .

    //graphs:
    var row = dc.rowChart("#rowchart");
    row
        .renderLabel(true)
        .height(200)
        .dimension(itemsDim)
        .group(itemsGroup)
        .ordering(function(d){return -d.value;})
        .xAxis().ticks(3);
    
    var pie1 = dc.pieChart("#piechart1");
    pie1
      .height(75)
      .width(75)
      .dimension(dates)
      .group(datesGroup);
    

    没变 .

    var pie2 = dc.pieChart("#piechart2");
    pie2
      .height(75)
      .width(75)
      .dimension(states)
      .group(statesGroup)
      .valueAccessor(function(d) { return d.value.count; });
    

    我们的Reductio reducer在某种程度上改变了组的结构,所以我们需要 valueAccessor .

    var bar = dc.barChart("#barchart");
    bar.width(500).height(200)
       .dimension(states)
       .group(statesGroup, 'orange', sel_stack('orange'))
       .stack(statesGroup, 'meat', sel_stack('meat'))
       .stack(statesGroup, 'bread', sel_stack('bread'))
       .stack(statesGroup, 'apple', sel_stack('apple'))
       .renderHorizontalGridLines(true)
       .renderLabel(true)
       .legend(dc.legend())
       .gap(10)
       .yAxisLabel("count")
       .x(d3.scale.ordinal())
       .xUnits(dc.units.ordinal);
    

    只是没有花哨的自定义过滤功能或任何东西 . dc.js和Crossfilter知道该怎么做 . 不幸的是,dc.js中似乎有一个带有序数堆积条形图的错误,所以你必须在此后正确地渲染渲染颜色条:-(也许Gordon会在这里提示一下 .

    dc.renderAll();
    
    function sel_stack(i) {
        return function(d) {
            return d.value[i] ? d.value[i].count : 0;
        };
    }
    

    由于更新的组结构导致轻微更改,如果您错误输入其中一个项目键,则会有一点安全性 .

  • 0

    我修复了彩色堆栈问题并将问题计算到我希望如何完成计数 . 我正在使用D3.js verison 2.5.5,crossfilter.js版本1.3.11,以及版本2.1.0 dev的dc.js和dc.css . https://jsfiddle.net/jnf84n7c/

    var data = [
        {"key":"KEY-1","state":"MA", "status":["A","R","C"], "items":["orange", "meat", "bread"], "date":"Y16"},
        {"key":"KEY-2","state":"MA", "status":["A","O"], "items":["apple", "bread"], "date":"Y15"},
        {"key":"KEY-3","state":"TX", "status":["O"], "items":["bread"], "date":"Y16"},
        {"key":"KEY-4","state":"TN", "status":["A","R"], "items":["apple", "bread"], "date":"Y16"},
        {"key":"KEY-5","state":"TN", "status":["A","O"], "items":["apple", "orange"], "date":"Y15"},
        {"key":"KEY-6","state":"TN", "status":[], "items": [], "date":"Y14"}
    ];
    
    var cf = crossfilter(data);
    
    //dimensions and groups:
    var dates       = cf.dimension(function(d){ return d.date; });
    var datesGroup  = dates.group();//.reduceCount(function(d){ return d.key; });
    var states      = cf.dimension(function(d){ return d.state; });
    var statesGroup = states.group();//.reduceCount(function(d){ return d.key; });
    var itemsDim    = cf.dimension(function(d){ return d.items; });
    var itemsGroup  = itemsDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value();
    itemsGroup.all  = myAllFunction;
    var states_items_group_apple  = states.group().reduce(reduceAdd_apple,  reduceRemove_apple,  reduceInitial_items);
    var states_items_group_bread  = states.group().reduce(reduceAdd_bread,  reduceRemove_bread,  reduceInitial_items);
    var states_items_group_orange = states.group().reduce(reduceAdd_orange, reduceRemove_orange, reduceInitial_items);
    var states_items_group_meat   = states.group().reduce(reduceAdd_meat,   reduceRemove_meat,   reduceInitial_items);
    var itemsGroup1  = itemsDim.groupAll().reduce(reduceAdd1, reduceRemove1, reduceInitial).value();
    var itemsGroup2  = itemsDim.groupAll().reduce(reduceAdd2, reduceRemove2, reduceInitial).value();
    var itemsGroup3  = itemsDim.groupAll().reduce(reduceAdd3, reduceRemove3, reduceInitial).value();
    itemsGroup1.all  = myAllFunction;
    itemsGroup2.all  = myAllFunction;
    itemsGroup3.all  = myAllFunction;
    var status       = cf.dimension(function(d){ return d.status; });
    var statusGroup1 = status.groupAll().reduce(reduceAdd_group1, reduceRemove_group1, reduceInitial_group).value();
    var statusGroup2 = status.groupAll().reduce(reduceAdd_group2, reduceRemove_group2, reduceInitial_group).value();
    var statusGroup3 = status.groupAll().reduce(reduceAdd_group3, reduceRemove_group3, reduceInitial_group).value();
    var statusGroup4 = status.groupAll().reduce(reduceAdd_group4, reduceRemove_group4, reduceInitial_group).value();
    statusGroup1.all = myAllFunction;
    statusGroup2.all = myAllFunction;
    statusGroup3.all = myAllFunction;
    statusGroup4.all = myAllFunction;
    var statusGroup  = status.groupAll().reduce(reduceAdd_group, reduceRemove_group, reduceInitial_group).value();
    statusGroup.all  = myAllFunction;
    
    //graphs:
    var row = dc.rowChart("#rowchart");
    row.height(170)
       .dimension(itemsDim)
       .group(itemsGroup)
       .ordering(function(d){return -d.value;})
       .renderLabel(true)
           .ordinalColors(["#008600", "#80FF80", "#FF80FF", "#860086"])
       .xAxis().ticks(3);
    row.filterHandler(myFilterFunction);
    
    var pie1 = dc.pieChart("#piechart1");
    pie1.height(75).width(75)
        .dimension(dates)
        .group(datesGroup);
    
    var pie2 = dc.pieChart("#piechart2");
    pie2.height(75).width(75)
        .dimension(states)
        .group(statesGroup);
    
    var pie3 = dc.pieChart("#piechart3");
    pie3.height(75).width(75)
        .dimension(status)
        .group(statusGroup);
    pie3.filterHandler(myFilterFunction);
    
    var bar = dc.barChart("#barchart");
    bar.width(500).height(200)
       .dimension(states)
       .group(states_items_group_bread,  'bread')
       .stack(states_items_group_orange, 'orange')
       .stack(states_items_group_apple,  'apple')
       .stack(states_items_group_meat,   'meat')
       .valueAccessor(function(p){ return p.value.count; })
       .renderHorizontalGridLines(true)
       .renderLabel(true)
       .legend(dc.legend().x(100).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(100))
       .gap(10)
       .elasticX(true).elasticY(true)
       .yAxisLabel("count")
       .x(d3.scale.ordinal())
       .xUnits(dc.units.ordinal)
       .margins({top:30, left:50, right:10, bottom:50});
    //bar.filterHandler(myFilterFunction);
    //bar.on("renderlet", function(_chart){
    //    _chart.selectAll("rect.bar").on("click", _chart.onClick);
    //});
    
    var bar2 = dc.barChart("#barchart2");
    bar2.width(500).height(200)
        .dimension(itemsDim)
        .group(itemsGroup1, 'MA')
        .stack(itemsGroup2, 'TN')
        .stack(itemsGroup3, 'TX')
        .renderHorizontalGridLines(true)
        .renderLabel(true)
        .legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60))
        .gap(10)
        .yAxisLabel("count")
        .x(d3.scale.ordinal())
        .xUnits(dc.units.ordinal)
        .ordinalColors(["#008600", "#80FF80", "#FF80FF", "#860086"])
        .margins({top:30, left:50, right:10, bottom:50});
    bar2.filterHandler(myFilterFunction);
    
    var bar3 = dc.barChart("#barchart3");
    bar3.width(500).height(200)
        .dimension(status)
        .group(statusGroup1, "bread")
        .stack(statusGroup2, "apple")
        .stack(statusGroup3, "orange")
        .stack(statusGroup4, "meat")
        .renderHorizontalGridLines(true)
        .renderLabel(true)
        .legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60))
        .gap(10)
        .yAxisLabel("count")
        .x(d3.scale.ordinal())
        .xUnits(dc.units.ordinal)
    //    .ordinalColors(["#008600", "#80FF80", "#FF80FF", "#860086"])
        .margins({top:30, left:50, right:10, bottom:50});
    bar3.filterHandler(myFilterFunction);
    
    dc.renderAll();  // render graphs
    
    //reduce functions:
    function reduceAdd(p, v) {
        if (v.items[0] === "") return p;    // skip empty values
        v.items.forEach (function(val, idx) {
            p[val] = (p[val] || 0) + 1; //increment counts
        });
        return p;
    }
    function reduceRemove(p, v) {
        if (v.items[0] === "") return p;    // skip empty values
        v.items.forEach (function(val, idx) {
            p[val] = (p[val] || 0) - 1; //decrement counts
        });
        return p;
    }
    function reduceInitial() {
        return {
            bread: 0,
            apple: 0,
            orange: 0,
            meat: 0
        };  
    }
    function reduceAdd1(p, v) {
        if (v.items[0] === "") return p;    // skip empty values
        if (v.state === "MA"){
            v.items.forEach (function(val, idx) {
                p.bread  += (val === 'bread'  ? 1 : 0);
                p.apple  += (val === 'apple'  ? 1 : 0);
                p.orange += (val === 'orange' ? 1 : 0);
                p.meat   += (val === 'meat'   ? 1 : 0);
            });    
        }
        return p;
    }
    function reduceRemove1(p, v) {
        if (v.items[0] === "") return p;    // skip empty values
        if (v.state === "MA"){
            v.items.forEach (function(val, idx) {
                p.bread  -= (val === 'bread'  ? 1 : 0);
                p.apple  -= (val === 'apple'  ? 1 : 0);
                p.orange -= (val === 'orange' ? 1 : 0);
                p.meat   -= (val === 'meat'   ? 1 : 0);
            });    
        }
        return p;
    }
    function reduceAdd2(p, v) {
        if (v.items[0] === "") return p;    // skip empty values
        if (v.state === "TN"){
            v.items.forEach (function(val, idx) {
                p.bread  += (val === 'bread'  ? 1 : 0);
                p.apple  += (val === 'apple'  ? 1 : 0);
                p.orange += (val === 'orange' ? 1 : 0);
                p.meat   += (val === 'meat'   ? 1 : 0);
            });    
        }
        return p;
    }
    function reduceRemove2(p, v) {
        if (v.items[0] === "") return p;    // skip empty values
        if (v.state === "TN"){
            v.items.forEach (function(val, idx) {
                p.bread  -= (val === 'bread'  ? 1 : 0);
                p.apple  -= (val === 'apple'  ? 1 : 0);
                p.orange -= (val === 'orange' ? 1 : 0);
                p.meat   -= (val === 'meat'   ? 1 : 0);
            });    
        }
        return p;
    }
    function reduceAdd3(p, v) {
        if (v.items[0] === "") return p;    // skip empty values
        if (v.state === "TX"){
            v.items.forEach (function(val, idx) {
                p.bread  += (val === 'bread'  ? 1 : 0);
                p.apple  += (val === 'apple'  ? 1 : 0);
                p.orange += (val === 'orange' ? 1 : 0);
                p.meat   += (val === 'meat'   ? 1 : 0);
            });    
        }
        return p;
    }
    function reduceRemove3(p, v) {
        if (v.items[0] === "") return p;    // skip empty values
        if (v.state === "TX"){
            v.items.forEach (function(val, idx) {
                p.bread  -= (val === 'bread'  ? 1 : 0);
                p.apple  -= (val === 'apple'  ? 1 : 0);
                p.orange -= (val === 'orange' ? 1 : 0);
                p.meat   -= (val === 'meat'   ? 1 : 0);
            });    
        }
        return p;
    }
    function reduceAdd_apple(p, v){
        if (v.items[0] === "") return p;    // skip empty values
        p.state = v.state;
        v.items.forEach(function(val, idx){
            p.count += (val === 'apple' ? 1 : 0);
        });
        return p;
    }
    function reduceRemove_apple(p, v){
        if (v.items[0] === "") return p;    // skip empty values
        p.state = v.state;
        v.items.forEach(function(val, idx){
            p.count -= (val === 'apple' ? 1 : 0);
        });
        return p;
    }
    function reduceAdd_bread(p, v){
        if (v.items[0] === "") return p;    // skip empty values
        p.state = v.state;
        v.items.forEach(function(val, idx){
            p.count += (val === 'bread' ? 1 : 0);
        });
        return p;
    }
    function reduceRemove_bread(p, v){
        if (v.items[0] === "") return p;    // skip empty values
        p.state = v.state;
        v.items.forEach(function(val, idx){
            p.count -= (val === 'bread' ? 1 : 0);
        });
        return p;
    }
    function reduceAdd_orange(p, v){
        if (v.items[0] === "") return p;    // skip empty values
        p.state = v.state;
        v.items.forEach(function(val, idx){
            p.count += (val === 'orange' ? 1 : 0);
        });
        return p;
    }
    function reduceRemove_orange(p, v){
        if (v.items[0] === "") return p;    // skip empty values
        p.state = v.state;
        v.items.forEach(function(val, idx){
            p.count -= (val === 'orange' ? 1 : 0);
        });
        return p;
    }
    function reduceAdd_meat(p, v){
        if (v.items[0] === "") return p;    // skip empty values
        p.state = v.state;
        v.items.forEach(function(val, idx){
            p.count += (val === 'meat' ? 1 : 0);
        });
        return p;
    }
    function reduceRemove_meat(p, v){
        if (v.items[0] === "") return p;    // skip empty values
        p.state = v.state;
        v.items.forEach(function(val, idx){
            p.count -= (val === 'meat' ? 1 : 0);
        });
        return p;
    }
    function reduceAdd_group1(p, v) {
        if (v.items[0]  === "") return p;    // skip empty values
        if (v.status[0] === "") return p;    // skip empty values
        v.items.forEach(function(val1, idx1){
            if (val1 === "bread"){
                v.status.forEach (function(val2, idx2) {
                    if (idx1 === idx2) {
                    p.A += (val2 === 'A' ? 1 : 0);
                    p.O += (val2 === 'O' ? 1 : 0);
                    p.C += (val2 === 'C' ? 1 : 0);
                    p.R += (val2 === 'R' ? 1 : 0);
                    }
                });    
            }
        });
        return p;
    }
    function reduceRemove_group1(p, v) {
        if (v.items[0]  === "") return p;    // skip empty values
        if (v.status[0] === "") return p;    // skip empty values
        v.items.forEach(function(val1, idx1){
            if (val1 === "bread"){
                v.status.forEach (function(val2, idx2) {
                    if (idx1 === idx2) {
                    p.A -= (val2 === 'A' ? 1 : 0);
                    p.O -= (val2 === 'O' ? 1 : 0);
                    p.C -= (val2 === 'C' ? 1 : 0);
                    p.R -= (val2 === 'R' ? 1 : 0);
                    }
                });    
            }
        });
        return p;
    }
    function reduceAdd_group2(p, v) {
        if (v.items[0]  === "") return p;    // skip empty values
        if (v.status[0] === "") return p;    // skip empty values
        v.items.forEach(function(val1, idx1){
            if (val1 === "apple"){
                v.status.forEach (function(val2, idx2) {
                    if (idx1 === idx2) {
                    p.A += (val2 === 'A' ? 1 : 0);
                    p.O += (val2 === 'O' ? 1 : 0);
                    p.C += (val2 === 'C' ? 1 : 0);
                    p.R += (val2 === 'R' ? 1 : 0);
                    }
                });    
            }
        });
        return p;
    }
    function reduceRemove_group2(p, v) {
        if (v.items[0]  === "") return p;    // skip empty values
        if (v.status[0] === "") return p;    // skip empty values
        v.items.forEach(function(val1, idx1){
            if (val1 === "apple"){
                v.status.forEach (function(val2, idx2) {
                    if (idx1 === idx2) {
                    p.A -= (val2 === 'A' ? 1 : 0);
                    p.O -= (val2 === 'O' ? 1 : 0);
                    p.C -= (val2 === 'C' ? 1 : 0);
                    p.R -= (val2 === 'R' ? 1 : 0);
                    }
                });    
            }
        });
        return p;
    }
    function reduceAdd_group3(p, v) {
        if (v.items[0]  === "") return p;    // skip empty values
        if (v.status[0] === "") return p;    // skip empty values
        v.items.forEach(function(val1, idx1){
            if (val1 === "orange"){
                v.status.forEach (function(val2, idx2) {
                    if (idx1 === idx2) {
                    p.A += (val2 === 'A' ? 1 : 0);
                    p.O += (val2 === 'O' ? 1 : 0);
                    p.C += (val2 === 'C' ? 1 : 0);
                    p.R += (val2 === 'R' ? 1 : 0);
                    }
                });    
            }
        });
        return p;
    }
    function reduceRemove_group3(p, v) {
        if (v.items[0]  === "") return p;    // skip empty values
        if (v.status[0] === "") return p;    // skip empty values
        v.items.forEach(function(val1, idx1){
            if (val1 === "orange"){
                v.status.forEach (function(val2, idx2) {
                    if (idx1 === idx2){
                    p.A -= (val2 === 'A' ? 1 : 0);
                    p.O -= (val2 === 'O' ? 1 : 0);
                    p.C -= (val2 === 'C' ? 1 : 0);
                    p.R -= (val2 === 'R' ? 1 : 0);
                    }
                });    
            }
        });
        return p;
    }
    function reduceAdd_group4(p, v) {
        if (v.items[0]  === "") return p;    // skip empty values
        if (v.status[0] === "") return p;    // skip empty values
        v.items.forEach(function(val1, idx1){
            if (val1 === "meat"){
                v.status.forEach (function(val2, idx2) {
                    if (idx1 === idx2) {
                    p.A += (val2 === 'A' ? 1 : 0);
                    p.O += (val2 === 'O' ? 1 : 0);
                    p.C += (val2 === 'C' ? 1 : 0);
                    p.R += (val2 === 'R' ? 1 : 0);
                    }
                });    
            }
        });
        return p;
    }
    function reduceRemove_group4(p, v) {
        if (v.items[0]  === "") return p;    // skip empty values
        if (v.status[0] === "") return p;    // skip empty values
        v.items.forEach(function(val1, idx1){
            if (val1 === "meat"){
                v.status.forEach (function(val2, idx2) {
                    if (idx1 === idx2) {
                    p.A -= (val2 === 'A' ? 1 : 0);
                    p.O -= (val2 === 'O' ? 1 : 0);
                    p.C -= (val2 === 'C' ? 1 : 0);
                    p.R -= (val2 === 'R' ? 1 : 0);
                    }
                });    
            }
        });
        return p;
    }
    function reduceAdd_group(p, v) {
        if (v.status[0] === "") return p;    // skip empty values
        v.status.forEach (function(val, idx) {
            p[val] = (p[val] || 0) + 1;
        });
        return p;
    }
    function reduceRemove_group(p, v) {
        if (v.status[0] === "") return p;    // skip empty values
        v.status.forEach (function(val, idx) {
            p[val] = (p[val] || 0) - 1;
        });
        return p;
    }
    function reduceInitial_group() {
        return {
            A: 0,
            O: 0,
            C: 0,
            R: 0
        };  
    }
    function reduceInitial_items(){
        return {
            count: 0,
            state: ''
        };
    }
    
    
    //filter function:
    function myFilterFunction (dimension, filters) {
        dimension.filter(null);   
        if (filters.length === 0)
            dimension.filter(null);
        else
            dimension.filterFunction(function (d) {
                for (var i=0; i < d.length; i++) {
                    if (filters.indexOf(d[i]) >= 0) return true;
                }
                return false;
            });
        return filters; 
    }
    
    //all function:
    function myAllFunction() {
        var newObject = [];
        for (var key in this) {
            if (this.hasOwnProperty(key) && key != "all") {
                newObject.push({
                    key: key,
                    value: this[key]
                });
            }
        }
        return newObject;
    };
    

相关问题