d3 v4:使用带有直方图数据的堆栈?

时间:2017-03-03 15:49:22

标签: javascript arrays d3.js

我有一堆数据是六个类别中的一个,每个数据都有一个与之相关的时间。我需要使用直方图将这些数据分成月份箱,这很容易,但我还需要堆叠每个类别。我一直在寻找一个堆叠的直方图示例,但我能找到的唯一一个来自d3 v3,它的堆叠API显然非常不同。现在,我在调用stack()之后陷入困境,我得到了无意义的数据,我无法用它来生成堆积条形图。

                var data = this.data;
                var margin = {top: 20, right: 20, bottom: 30, left: 50},
                    width = this.width - margin.left - margin.right,
                    height = this.height - margin.top - margin.bottom;


                data.forEach(function(d) {
                    d.date = d3.isoParse(d.createdDate);
                });

                // set the ranges
                var x = d3.scaleTime()
                    .domain(d3.extent(data, function(d) { return d.date; }))
                    .rangeRound([0, width]);
                var y = d3.scaleLinear()
                    .range([height, 0]);
                var colours = d3.scaleOrdinal(d3.schemeCategory10);

                var svg = d3.select(this.$.chart);
                var svg2 = svg.select("#canvas");

                var histogram = d3.histogram()
                    .value(function(d) { return d.date; })
                    .domain(x.domain())
                    .thresholds(x.ticks(d3.timeMonth));

                var dataGroupedByType = d3.nest()
                    .key(function(d) {
                        return d.type;
                    })
                    .object(data, d3.map);

                var histDataByType = [];
                for (var key in dataGroupedByType) {
                    var histData = histogram(dataGroupedByType[key]);
                    histDataByType.push({type: key, values: histData});
                }

                var stack = d3.stack()
                    .keys(["A","B","C","D","E","F"])
                    .value( function(d, key) {
                        return d.values;
                    });

                var stackedHistData = stack(histDataByType);

dataGroupedByType是一个具有六个键控对象(A到F)的对象,每个对象都包含一个数据对象数组。然后我创建histDataByType,这会产生一个包含6个对象的数组,每个对象都有一个type属性(A到F)和一个values数组,它们的长度始终相同(91在我的情况下,因为我的数据跨越91个月)。在该数组中是另一个包含bin数据(如果存在)以及x0x1值的数组。此时,binning已经完成,我只需要堆叠所有内容并获取y0y1值。

所以,我打电话给stack,但它给了我垃圾; stackedHistData是一个6的数组,每个数组都有一个等于0的0属性,一个等于' NaN'的属性,以及一个具有91长数组的data属性,索引和密钥(A到F)。我甚至没有看到堆栈调用要生成的y0y1值。如何与这种直方图数据一起使用?

1 个答案:

答案 0 :(得分:0)

最终想出来了。我基本上试图模拟数据结构found here

首先,我从数据中获取了密钥并解析了时间。

var keys = [];
data.forEach(function(d) {
    d.date = d3.isoParse(d.relevantDate);
    keys.push(d.type);
});

keys = _.uniq(keys);

这里我使用lodash库来识别我的数组键。下一步是像通常对直方图那样制作垃圾箱:

var histogram = d3.histogram()
    .value(function(d) { return d.date; })
    .domain(x.domain())
    .thresholds(x.ticks(d3.timeMonth));

var bins = histogram(data);
y.domain([0, d3.max(bins, function(d) { return d.length; })]);

域名也可以在这里声明。现在来了有趣的部分:

var stackData = [];
for (var bin in bins) {
    //console.log(bins[bin].x0, bins[bin].x1)
    var pushableObject = {};
    // add the time boundaries.
    pushableObject.x0 = bins[bin].x0;
    pushableObject.x1 = bins[bin].x1;
    // for each bin, split the data into the different keys.
    bins[bin].forEach(function(d) {
        //console.log(d);
        if (!pushableObject[d.type]) { pushableObject[d.type] = [d]}
        else pushableObject[d.type].push(d);
    })
    // if any of the keys didn't get represented in this bin, give them empty arrays for the stack function.
    keys.forEach( function(key) {
        if (!pushableObject[key]) {
            pushableObject[key] = [];
        }
    })

    stackData.push(pushableObject);
}

我创建一个空的stackData var,然后遍历这些bin。对于每个bin,我使用x0和x1填充对象,因为绘制图表需要这些对象。然后,我在bin上执行foreach循环,循环遍历存储在其中的每个数据项。存储对象在此循环中为每种类型(也称为密钥)获取一个数组。然后是一个备份循环,以捕获此bin中未表示的任何类型,以便stack函数可以正常运行。说到这里,它是:

var realStack = d3.stack()
    .keys(keys)
    .value(function(d, key) {
        return d[key].length;
    });

现在我们已经正确地按摩了所有数据,这很简单。它只需要获取数据桶的长度而不是数据本身。然后只需在附加rects时使用该堆栈函数并将其传递给stackData变量,所有这些都可以解决。