2017-03-03 28 views
0

我有一堆數據是六個類別之一,每個數據片段都有一個與之相關的時間。我需要使用直方圖將這些數據分類到每月分檔中,這很容易,但我也需要將每個分類進行堆疊。我一直在尋找一個堆疊直方圖的例子,但我能找到的唯一的例子是d3 v3,這在堆疊API中顯然是非常不同的。現在我被卡在stack()後,我得到無意義的數據,我不能用它來生成堆積條形圖。d3 v4:使用堆棧和直方圖數據?

   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值。在這一點上,分箱已完成,我所需要的是將所有數據堆疊起來,並獲得y0y1的值。

所以,我打電話stack,但它給了我垃圾; stackedHistData是一個6的數組,每個數組都有一個0屬性,它等於0,一個屬性等於'NaN',而data屬性具有這個91長的數組,索引和鍵(A到F)。我甚至沒有看到由堆棧調用產生的y0y1值。這種直方圖數據如何使用?

回答

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,我用x0和x1填充一個對象,因爲繪製圖表將需要這些對象。然後,我在bin上循環一個foreach,它循環存儲在每個數據項中。存儲對象在此循環中爲每個類型(aka鍵)獲取一個數組。然後有一個備份循環,以捕獲任何未在此倉中表示的類型,以便stack函數可以正常運行。說到這裏,它是這樣的:

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

這很簡單,現在我們已經正確地處理了所有的數據。它只需要獲取數據桶的長度而不是數據本身。然後,在追加rects並將其傳遞給變量stackData時,只需使用該堆棧函數即可。