d3 v4:将堆栈与直方图数据一起使用? [英] d3 v4: Using stack with histogram data?

查看:39
本文介绍了d3 v4:将堆栈与直方图数据一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a bunch of data that is one of six categories, each piece of data has a time associated with it. I need to use a histogram to bin these data into monthly bins, which is easy, but I also need to stack each category. I've been looking for a stacked histogram example but the only ones I can find are from d3 v3, which is apparently very different in its stacking API. Right now I'm stuck in that after calling stack() I get nonsensical data back, which I can't use to generate a stacked bar chart.

                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数据(如果存在)以及 x0 x1 值的数组.至此,分箱已经完成,我所需要做的就是堆叠所有内容并获取 y0 y1 值.

dataGroupedByType is an object with six keyed objects (A through F), which each contain an array of data objects. Then I make histDataByType which results in an array of 6 objects, each of which have a type property (A through F) and a values array, which is always the same length (91 in my case, since my data spans 91 months). Within that array is another array with bin data (if any exists), and the x0 and x1 values. At this point, the binning has been done, all I need is to stack everything and get the y0 and y1 values.

所以,我叫 stack ,但这给了我很多垃圾. stackedHistData 是一个6的数组,每个数组都有一个等于0的0属性,一个等于'NaN'的1属性以及一个具有91个长字符的 data 属性数组,索引和键(A到F).我什至没有看到应该由堆栈调用生成的 y0 y1 值.这种直方图数据如何使用?

So, I call stack, but it gives me garbage out; stackedHistData is an array of 6, each array has a 0 property which equals 0, a 1 property that equals 'NaN', and a data property that has that 91-long array, the index, and the key (A through F). I'm not even seeing the y0 and y1 values that are meant to be generated by the stack call. How is it meant to be used with this kind of histogram data?

推荐答案

最终弄清楚了这一点.我基本上是尝试模拟数据结构在此处找到.

Figured this out eventually. I basically attempted to emulate the data structure found here.

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

Firstly I acquired the keys from the data as well as parsing the times.

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

keys = _.uniq(keys);

在这里,我正在使用lodash库来唯一化我的键数组.下一步是像通常对直方图所做的那样制作垃圾箱:

Here I'm using the lodash library to unique-ify my array of keys. The next step is to make the bins as you would normally do for a histogram:

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

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

The domain can be declared here too. Now comes the fun part:

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变量,并循环通过垃圾箱.对于每个bin,我将使用x0和x1填充一个对象,因为绘制图表需要这些对象.然后,我在容器上执行一个 foreach 循环,该循环遍历存储在其中的每个数据项.在此循环中,存储对象为每种类型(即键)获取一个数组.然后有一个备份循环,可以捕获此bin中未表示的任何类型,以便 stack 函数可以正常运行.谈到这一点,这里是:

I make an empty stackData var, and loop through the bins. For each bin I populate an object with x0 and x1, since those are going to be needed for drawing the chart. Then, I do a foreach loop on the bin which loops over each data item stored within. The storage object gets one array per type (aka key) in this loop. Then there's a backup loop afterwards to catch any types that weren't represented in this bin, so that the stack function can function correctly. Speaking of that, here it is:

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

现在非常简单,我们已经正确处理了所有数据.它只需要获取数据桶的长度,而不是数据本身的长度即可.然后只需在追加rect时使用该堆栈函数并将其传递给 stackData 变量,所有变量都可以解决.

It's pretty simple now that we have all the data massaged properly. It just needs to get the length of the data buckets instead of the data itself. Then just use that stack function when appending rects and pass it the stackData variable, and all will work out.

这篇关于d3 v4:将堆栈与直方图数据一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆