我的数据类似于
Month Material Sales
2 A 500
2 A 300
5 A 700
1 B 400
2 B 300
4 C 1200
2 C 500
我想通过dc.rowChart在“月”维度下显示每种物料销售额占总销售额的百分比。
[对于物料的第二个月,百分比为%50。因为在第二个月的总销售额是1600,而A的销售额是800。对于物料B的百分比将为%18,75,因为B在第二个月的销售额为300。等等。
到目前为止,我的表现不符合逻辑。但它不显示任何数据
var monthDim=ndx.dimension(function (d) {return +d.Month;});
var totalGroup = monthDim.group().reduce(
/* callback for when data is added to the current filter results */
(p, v) => {
++p.count;
p.Sales += v.Sales;
return p;
},
/* callback for when data is removed from the current filter results */
(p, v) => {
--p.count;
p.Sales -= v.Sales;
return p;
},
/* initialize p */
() => ({
count: 0,
Sales: 0,
})
);
然后找到总销售额:
var salesTotal= ndx.dimension(function (d) { return d.Sales; });
var salesTotalGroup = salesTotal.groupAll().reduceSum(function (d) { return d.Sales; });
现在,我想将这些组合到条形图上的变量。我知道他们似乎并没有合作。但这就是我想出的。
var chart= dc.rowChart('#salespercentagechart')
.width(400)
.height(350)
.elasticX(true)
.dimension(monthDim)
.group(totalGroup )
.valueAccessor(function(p) { return p.value.Sales / salesTotalGroup;} )
.ordering(function (d) { return -d.key; })
任何想法对我来说都是完美的。谢谢。
您可以使用交叉过滤器组自定义归约来同时计算每种材料的总数与总数:
var totalGroup = monthDim.group().reduce(
/* callback for when data is added to the current filter results */
(p, v) => {
p.byMaterial[v.Material] = (p.byMaterial[v.Material] || 0) + v.Sales;
p.total += v.Sales;
return p;
},
/* callback for when data is removed from the current filter results */
(p, v) => {
p.byMaterial[v.Material] -= v.Sales;
p.total -= v.Sales;
return p;
},
/* initialize p */
() => ({
byMaterial: {},
total: 0,
})
);
这是一次聚合多个堆栈的规范方法1
|| 0
将undefined视为0p.byMaterial[v.Material]
,因此-=
是安全的现在totalGroup.all()
将产生
[
{
"key": 1,
"value": {
"byMaterial": {
"B": 400
},
"total": 400
}
},
{
"key": 2,
"value": {
"byMaterial": {
"A": 800,
"B": 300,
"C": 500
},
"total": 1600
}
},
{
"key": 4,
"value": {
"byMaterial": {
"C": 1200
},
"total": 1200
}
},
{
"key": 5,
"value": {
"byMaterial": {
"A": 700
},
"total": 700
}
}
]
在循环中定义图表堆栈很方便:
var materials = d3.set(data, d => d.Material);
materials.values().sort().forEach((material, i) => {
const accessor = d => (d.value.byMaterial[material] || 0) / d.value.total * 100;
if(i === 0)
chart.group(totalGroup, material, accessor);
else
chart.stack(totalGroup, material, accessor);
});
我们使用d3.set查找d.Material
的所有唯一值,然后对其进行循环。 dc.js具有an annoying design bug,即使它具有与.group()
相同的参数,因此也必须首次调用.stack()
,因此if(i === 0)
。
const accessor = d => (d.value.byMaterial[material] || 0) / d.value.total * 100;
[按物料读取,如果该物料在当月不存在,则再次将undefined
缺省为0,然后除以总数并乘以100得到百分比。
var chart= dc.lineChart('#salespercentagechart')
.width(400)
.height(350)
.renderArea(true)
.elasticX(true)
.dimension(monthDim)
.x(d3.scaleLinear()).elasticX(true)
.legend(dc.legend().x(300).y(50))
//.ordering(function (d) { return -d.key; });