使用dc.js将百分比从总数中叠加出来。

问题描述 投票:1回答:1

我有一个数据,类似于

enter image description here

 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; })

任何想法对我来说都是完美的。谢谢。

dc.js crossfilter
1个回答
1
投票

计算每个类别和总数的总和

你可以使用交叉滤镜组自定义缩减,在计算总体总量的同时计算每个材料的总量。

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.Materialdc.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; });

screenshot of stacked area/line chart

小提琴演示.

© www.soinside.com 2019 - 2024. All rights reserved.