2017-06-02 24 views
3

我正在試圖製作一個如下所示的圖表:Example Bar ChartJavaScript D3.js v4 - 如何使用D3.Stack與從AJAX調用SharePoint 2013創建的D3.Nest嵌套數組創建堆疊條形圖

我有一個D3.nest數據結構,看起來像這樣:

{"key":"Area 1","values":[ 
    {"key":"5. Validation Complete","value":12.5}, 
    {"key":"Deferred","value":1}, 
    {"key":"3. Identify & Validate Proposed Solutions","value":5}, 
    {"key":"1. Define & Describe the Problem or Opportunity","value":0}]}, 
{"key":"Area 2","values":[ 
    {"key":"5. Validation Complete","value":41.2}, 
    {"key":"4. Implement the Solutions","value":86.6}, 
    {"key":"3. Identify & Validate Proposed Solutions","value":6}, 
    {"key":"2. Identify Root Causes","value":4}, 
    {"key":"1. Define & Describe the Problem or Opportunity","value":9}]}, 
{"key":"Area 3","values":[ 
    {"key":"5. Validation Complete","value":40}, 
    {"key":"4. Implement the Solutions","value":49.2}, 
    {"key":"3. Identify & Validate Proposed Solutions","value":10.4}]}, 
{"key":"Area 4","values":[ 
    {"key":"Deferred","value":0.25}, 
    {"key":"4. Implement the Solutions","value":28}, 
    {"key":"3. Identify & Validate Proposed Solutions","value":84.9}, 
    {"key":"2. Identify Root Causes","value":0}]} 

我zKeys的結構爲:

Array Image

我沒有成功嘗試Bostock's Stacked Bar Chart Example和此SO post

這裏是我的代碼:

var svg = d3.select("svg"), 
    margin = {top: 20, right: 20, bottom: 30, left: 40}, 
    width = +svg.attr("width") - margin.left - margin.right, 
    height = +svg.attr("height") - margin.top - margin.bottom; 

var x = d3.scaleBand().rangeRound([0, width]).padding(0.1); 
var y = d3.scaleLinear().rangeRound([height, 0]); 
var z = d3.scaleOrdinal().range(["#F8A11E", "#E51F36", "#582C85", "#1C92D0", "#017165", "#7F7F7F"]);  

var g = svg.append("g") 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

var sharepointStatusArray = getListData("Points List","ID,Title,Color_Code"); 
var data=getListData("Points%20List","$select=Area,StatusID,Points,Status/Title&$expand=Status"); 

var zKeys = []; 

sharepointStatusArray.forEach(function(d) 
{ 
    zKeys.push(d.Title); 
}); 

var nestData = d3.nest() 
    .key(function(d) { return d.Area; }) 
    .key(function(d) { return d.Status.Title; }) 
    .rollup(function(v) { return d3.sum(v, function(d) { return d.Points; }); }) 
    .entries(data); 

    nestData.sort(function(a,b) {return b.total - a.total;}); 
    x.domain(nestData.map(function(d) { return d.key; })); 
    y.domain([0, d3.max(nestData, function(d){return d3.sum(d.values, function(d){return d.value})})+20]).nice(); 
    z.domain(zKeys) 

    g.append("g") 
    .selectAll(".serie") 
    .data(d3.stack().keys(zKeys)(nestData)) 
    .enter().append("g") 
     .attr("class","serie") 
     .selectAll("rect") 
     .data(function(d) { return d; }) 
     .enter().append("rect") 
      .attr("class", "bar") 
      .attr("fill", function(d) { return z(d.key);}) 
      .attr("x", function(d) {return x(d.data.key);})   
      .attr("y", function(d) {return y(d[1]);}) 
      .attr("height", function(d) { return y(d[0]) - y(d[1]); }) 
      .attr("width", x.bandwidth()); 

    g.append("g") 
    .attr("class", "axis axis--x") 
    .attr("transform", "translate(0," + height + ")") 
    .call(d3.axisBottom(x)); 

    g.append("g") 
     .attr("class", "axis") 
     .call(d3.axisLeft(y).ticks(null, "s")) 
    .append("text") 
     .attr("x", 2) 
     .attr("y", y(y.ticks().pop()) + 0.5) 
     .attr("dy", "0.32em") 
     .attr("fill", "#000") 
     .attr("font-weight", "bold") 
     .attr("text-anchor", "start") 
     .text("Hours"); 


    //Creating legend for colors 
     var legend = g.append("g") 
     .attr("font-family", "sans-serif") 
     .attr("font-size", 10) 
     .attr("text-anchor", "end") 
    .selectAll("g") 
    .data(zKeys.slice()) 
    .enter().append("g") 
     .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); 

    legend.append("rect") 
     .attr("x", width - 19) 
     .attr("width", 19) 
     .attr("height", 19) 
     .attr("fill", z); 

    legend.append("text") 
     .attr("x", width - 24) 
     .attr("y", 9.5) 
     .attr("dy", "0.32em") 
     .text(function(d) { return d; }); 

我不能讓堆積條形圖根據實例繪製。幾乎每個例子都使用d3.csv,而不是d3.nest,所以我對這些例子如何轉化爲具有輸出數組的d3.nest場景感到迷茫。

任何人都可以幫我嗎?謝謝。

回答

3

我最終找到了自己的問題的答案。 我發現的一件事情是,我發現處理d3.stack()的所有信息都表明發送給函數的數據需要2D(2維)。這是d3.nest()輸出很好的東西。結果不準確。 我應該從一開始就這樣做,但我調試了示例Mike Bostock’s Stacked Bar Chart,並發現每個人在其示例中使用的d3.csv()的輸出實際上都會輸出一維數組,每個元素都包含數據的鍵/值對顯示在每個矩形中。 Screenshot of the data output from Mike's example

我可能做了一個非常迂迴的做法,但這裏是我做了什麼來解決我沒有正確的數據結構爲d3.stack()的問題。

1)我保持d3.nest的使用()輸出,因爲它允許我單個值總結爲單個鍵/值對這樣的每個元素:

Nested Data

2)I然後消毒,使用下面的代碼數據輸出得到它看起來像d3.csv()在所有實施例的輸出(添加鍵/值默認缺失數據和壓扁的結構:

//BEGIN data cleanup for d3.stack 
//Add default values for missing data points to make each array formatted the same 
    nestData = nestData.map(function(keyObj) { 
     return { 
      key: keyObj.key, 
      values: zKeys.map(function(k) { 
        value = keyObj.values.filter(function(v) { return v.key == k; })[0]; 
        return value || ({key: k, value: 0}); 
       }) 
     }; 
    }); 

//Loop through the nested array and create a new array element that converts each individual nested element into a key/value pair in a single object. 
var flatData = []; 
nestData.forEach(function(d) { 
    var obj = { Area: d.key } 
     d.values.forEach(function(f) { 
      obj[f.key] = f.value; 
     }); 
    flatData.push(obj); 
    }); 
//END data cleanup for d3.stack 

的數據現在看起來像這樣: Flattened Structure

3)數據消毒後,我就能夠從Mike的例子中使用的代碼開箱像這樣:

x.domain(flatData.map(function(d) { return d.Area; })); 
    y.domain([0, d3.max(nestData, function(d){return d3.sum(d.values, function(d){return d.value})})+20]); 
    z.domain(zKeys) 

var g = svg.append("g") 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

    g.append("g") 
    .selectAll("g") 
    .data(d3.stack().keys(zKeys)(flatData)) 
    .enter().append("g") 
     .attr("fill", function(d) { return z(d.key); }) 
    .selectAll("rect") 
    .data(function(d) { return d; }) 
    .enter().append("rect") 
     .attr("x", function(d) { return x(d.data.Area); }) 
     .attr("y", function(d) { return y(d[1]); }) 
     .attr("height", function(d) { return y(d[0]) - y(d[1]); }) 
     .attr("width", x.bandwidth());