我有一个数据,类似于
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在月份维度下显示每种材料销售额占总销售额的百分比。
在第2个月的时候,A材料的销售额占总销售额的百分比是%50。因为第2个月的总销售额是1600,而A的销售额是800。对于材料B,百分比将是%18,75,因为B的销售额在第2个月是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
p.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有以下功能 烦人的设计缺陷 你要叫 .group()
第一次,尽管它的参数与 .stack()
因此 if(i === 0)
.
const accessor = d => (d.value.byMaterial[material] || 0) / d.value.total * 100;
改为byMaterial,同样是默认的。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; });