使用 dc.js 堆叠占总数的百分比
Stacking percentages out of total using dc.js
我有一个类似于
的数据
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 的月份维度下显示每个 material 销售额占总销售额的百分比。
第 2 个月 material 的百分比将为 %50。因为第 2 个月的总销售额为 1600,而 A 的销售额为 800。对于 material,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; })
任何想法对我来说都是完美的。谢谢。
统计每个类别的总和和总数
您可以使用 crossfilter 组自定义缩减来计算每个 material 的总数,同时计算总总数:
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视为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 有 an annoying design bug,您必须在第一次调用 .group()
,即使它具有与 .stack()
相同的参数,因此 if(i === 0)
.
存取器计算百分比
const accessor = d => (d.value.byMaterial[material] || 0) / d.value.total * 100;
它读取 byMaterial,如果当月 material 不存在,再次默认 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; });
我有一个类似于
的数据 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 的月份维度下显示每个 material 销售额占总销售额的百分比。
第 2 个月 material 的百分比将为 %50。因为第 2 个月的总销售额为 1600,而 A 的销售额为 800。对于 material,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; })
任何想法对我来说都是完美的。谢谢。
统计每个类别的总和和总数
您可以使用 crossfilter 组自定义缩减来计算每个 material 的总数,同时计算总总数:
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视为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 有 an annoying design bug,您必须在第一次调用 .group()
,即使它具有与 .stack()
相同的参数,因此 if(i === 0)
.
存取器计算百分比
const accessor = d => (d.value.byMaterial[material] || 0) / d.value.total * 100;
它读取 byMaterial,如果当月 material 不存在,再次默认 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; });