Javascript d3/dc.js-如何创建一个堆叠条形图,同时告诉crossfilter将数组中的元素作为单独的记录处理?

Javascript d3/dc.js-如何创建一个堆叠条形图,同时告诉crossfilter将数组中的元素作为单独的记录处理?,javascript,d3.js,dc.js,ruby-on-rails-2,crossfilter,Javascript,D3.js,Dc.js,Ruby On Rails 2,Crossfilter,新建:我在解决方案中发布的小提琴有效()。然而,当我试图在我的项目中实施这些策略时,我遇到了一些问题。当我点击一个不是第一个图形的图形时,我会收到一条错误消息 未捕获类型错误:a.group.all不是函数(错误位于dc.min.js中) 你知道为什么它可以在小提琴上使用,但在我的RubyonRails应用程序中却不能使用吗 新代码 var data = [ {"key":"KEY-1","state":"MA","status":["A","R","C"],"items":["oran

新建:我在解决方案中发布的小提琴有效()。然而,当我试图在我的项目中实施这些策略时,我遇到了一些问题。当我点击一个不是第一个图形的图形时,我会收到一条错误消息

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

你知道为什么它可以在小提琴上使用,但在我的RubyonRails应用程序中却不能使用吗

新代码

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;
};
var数据=[
{“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=交叉过滤器(数据);
var dates=cf.dimension(函数(d){return d.date;});
var datesGroup=dates.group();
var states=cf.dimension(函数(d){返回d.state;});
var statesGroup=states.group();
var itemsDim=cf.dimension(函数(d){返回d.items;});
var itemsGroup=itemsDim.groupAll().reduce(reducead、reduceRemove、reduceInitial).value();
itemsGroup.all=myAllFunction;
变量states\u items\u group\u apple=states.group().reduce(reducead\u apple,reduceRemove\u apple,reduceInitial\u items);
变量states\u items\u group\u bread=states.group().reduce(reducead\u bread、reduceRemove\u bread、reduceInitial\u items);
变量states\u items\u group\u orange=states.group().reduce(reducead\u orange、reduceRemove\u orange、reduceInitial\u items);
变量states\u items\u group\u meat=states.group().reduce(reduceAdd\u meat,reduceRemove\u meat,reduceInitial\u items);
var itemsGroup1=itemsDim.groupAll().reduce(reducead1,reduceRemove1,reduceInitial).value();
var itemsGroup2=itemsDim.groupAll().reduce(reducead2,reduceRemove2,reduceInitial).value();
var itemsGroup3=itemsDim.groupAll().reduce(reducead3,reduceRemove3,reduceInitial).value();
itemsGroup1.all=myAllFunction;
itemsGroup2.all=myAllFunction;
itemsGroup3.all=myAllFunction;
var status=cf.dimension(函数(d){返回d.status;});
var statusGroup1=status.groupAll().reduce(reduceAdd_group1,reduceRemove_group1,reduceInitial_group1).value();
var statusGroup2=status.groupAll().reduce(reduceAdd_group2,reduceRemove_group2,reduceInitial_group2).value();
var statusGroup3=status.groupAll().reduce(reduceAdd_group3,reduceRemove_group3,reduceInitial_group3).value();
var statusGroup4=status.groupAll().reduce(reduceAdd_group4,reduceRemove_group4,reduceInitial_group4),value();
statusGroup1.all=myAllFunction;
statusGroup2.all=myAllFunction;
statusGroup3.all=myAllFunction;
statusGroup4.all=myAllFunction;
var statusGroup=status.groupAll().reduce(reduceAdd_组、reduceRemove_组、reduceInitial_组).value();
statusGroup.all=myAllFunction;
var row=dc.行图(“行图”);
行高(170)
.维度(itemsDim)
.group(项目组)
.ordering(函数(d){return-d.value;})
.renderLabel(真)
.普通颜色([“#008600”、“#80FF80”、“#FF80FF”、“#860086”])
.xAxis().ticks(3);
row.filterHandler(myFilterFunction);
var pie1=dc.pieChart(“pieChart 1”);
图1.高度(75).宽度(75)
.维度(日期)
.组(日期组);
var pie2=dc.pieChart(“piechart2”);
pie2.高度(75).宽度(75)
.维度(状态)
.组(statesGroup);
var pie3=dc.pieChart(“piechart3”);
pie3.高度(75).宽度(75)
.维度(状态)
.组(状态组);
pie3.filterHandler(myFilterFunction);
var bar=直流条形图(“条形图”);
棒材.宽度(500).高度(200)
.维度(状态)
.group(州\项目\组\面包,'bread')
.stack(状态\项\组\橙色,'orange')
.stack(声明\u项\u组\u苹果,'apple')
.stack(表示\u项\u组\u肉,'meat')
.valueAccessor(函数(p){return p.value.count;})
.renderHorizontalGridLines(真)
.renderLabel(真)
.legend(dc.legend().x(100).y(0).水平(1).项目高度(13).间隙(6).legendWidth(400).项目宽度(100))
.差距(10)
.elasticX(正确)。elasticY(正确)
.yAxisLabel(“计数”)
.x(d3.scale.ordinal())
.xUnits(dc.units.序数)
.页边距({顶部:30,左侧:50,右侧:10,底部:50});
var bar2=直流条形图(“条形图2”);
杆2.宽度(500).高度(200)
.维度(itemsDim)
.group(itemsGroup1,'MA')
.stack(项组2,'TN')
.stack(itemsGroup3,'TX')
.renderHorizontalGridLines(真)
.renderLabel(真)
.legend(dc.legend().x(60).y(0).水平(1).项目高度(13).间隙(6).legendWidth(400).项目宽度(60))
.差距(10)
.yAxisLabel(“计数”)
.x(d3.scale.ordinal())
.xUnits(dc.units.序数)
.普通颜色([“#008600”、“#80FF80”、“#FF80FF”、“#860086”])
.页边距({顶部:30,左侧:50,右侧:10,底部:50});
bar2.filterHandler(myFilterFunction);
var bar3=直流条形图(“条形图3”);
杆3.宽度(500).高度(200)
.维度(状态)
.组(状态组1,“面包”)
.stack(状态组2,“苹果”)
.堆栈(状态组3,“橙色”)
.stack(状态组4,“肉”)
.renderHorizontalGridLines(真)
.renderLabel(真)
.legend(dc.legend().x(60).y(0).水平(1).项目高度(13).间隙(6).legendWidth(400).项目宽度(60))
.差距(10)
.yAxisLabel(“计数”)
.x(d3.scale.ordinal())
.xUnits(dc.units.序数)
.页边距({顶部:30,左侧:50,右侧:10,底部:50});
bar3.filterHandler(myFilterFunction);
dc.renderAll();
函数还原D(p,v){
如果(v.items[0]=“”)返回p;
v、 items.forEach(函数(val、idx){
p[val]=(p[val]| 0)+1;
});
返回p;
}
功能减速机移动(p,v){
如果(v.items[0]=“”)返回p;
v、 items.forEach(函数(val、idx){
p[val]=(p[val]| 0)-1;
});
重新
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;
};
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()
var itemsDim    = cf.dimension(function(d){ return d.items; }, true);
var itemsGroup  = itemsDim.group();
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);
//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; });
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.renderAll();

function sel_stack(i) {
    return function(d) {
        return d.value[i] ? d.value[i].count : 0;
    };
}
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;
};