2014-02-28 44 views
1

我有一個使用d3.js開發的焦點和上下文條形圖,它工作得很好,但是當我縮小區域時,我想顯示圖形的分組值。聚焦和上下文圖的數據分組 - d3.js

正如下面的屏幕截圖所示,其中有兩個值爲1的條,但是當我縮小顯示一個月的數據時,它只顯示一個條,其值爲1。

我想將這些數據分組,以便在縮小時顯示兩個數據。任何幫助表示讚賞。 enter image description here

我有兩個文件: 1.基的文件:

defaults: { 
     margin: {top: 10, right: 20, bottom: 100, left: 40}, 
     margin2: {top: 425, right: 20, bottom: 30, left: 300}, 
    }, 
    onRender: function() { 
     var that = this; 
     //Set up graph parameters 
     var margin = this.options.margin; 
     var margin2 = this.options.margin2; 
     this.height = (this.options.height)? this.options.height - margin.top - margin.bottom: 960 - margin.top - margin.bottom, 
     this.width = (this.options.width)? this.options.width - margin.left - margin.right: 500 - margin.left - margin.right, 
     this.height2 = (this.options.height)? this.options.height - margin2.top - margin2.bottom : 500 - margin2.top - margin2.bottom, 
     this.width2 = this.width * .5; 

     //Set up ranges (a scaling factor to map input data to output in pixels) 
     this.scales = { 
      x: this.getXScale(), 
      x2: this.getX2Scale(), 
      y: this.getYScale(), 
      y2: this.getY2Scale() 
     }; 

     //Set up and define graph content 
     //----------axis---------- 
     this.renderAxes(); 

     //Setup groups to organize layout, brush areas and perform clipping 
     //----------groups---------- 
     this.svg = d3.select(this.el).append("svg") 
      .attr("class","FCBChart") 
      .attr("width", this.width + margin.left + margin.right) 
      .attr("height", this.height + margin.top + margin.bottom) 
      .attr("viewBox", "0 0 " + (this.width + margin.left + margin.right) + " " + (this.height + margin.top + margin.bottom)) 
      .attr("preserveAspectRatio", "xMidYMid meet"); 
     this.svg.append("defs").append("clipPath") 
      .attr("id", "clip") 
      .append("rect") 
      .attr("width", this.width + margin.left + margin.right) 
      .attr("height", this.height + margin.top + margin.bottom); 
     var aspect = (this.width + margin.left + margin.right)/(this.height + margin.top + margin.bottom); 
     $(window).on("resize", function() { 
      var targetWidth = $(".FCBChart").parent().width(); 
      $(".FCBChart").attr("width", targetWidth); 
      $(".FCBChart").attr("height", targetWidth/aspect); 
     }); 

     this.focus = this.svg.append("g") 
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
      .attr("class","focusGraph"); 
     // barsGroup is for making FCB graph like Bar graph 
     this.barsGroup = this.focus.append("g") 
      .attr('clip-path', 'url(#clip)'); 

     this.context = this.svg.append("g") 
      .attr("class","contextGraph") 
      .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")"); 

     this.setupBrush(); 
     this.renderData(); 
     return this; 

    } 

2.Actual文件與功能:

initialize : function(option){ 
     this.options = $.extend(true, {}, option,this.defaults); 
    }, 
    events : { 
    }, 

    //Set up ranges (a scaling factor to map input data to output in pixels) 
    getXScale : function(){ 
     return d3.time.scale().range([0, this.width]) 
    }, 
    getX2Scale : function(){ 
     return d3.time.scale().range([0, this.width2]) 
    }, 
    getYScale : function(){ 
     return d3.scale.linear().range([this.height, 0]) 
    }, 
    getY2Scale : function(){ 
     return d3.scale.linear().range([this.height2, 0]) 
    }, 

    //Set up and define graph content 
    //----------axis---------- 
    renderAxes : function(){ 
     var that = this; 
     this.xAxis = d3.svg.axis().scale(this.scales.x).orient("bottom"), 
     this.xAxis2 = d3.svg.axis().scale(this.scales.x2).orient("bottom"), 
     this.yAxis = d3.svg.axis().scale(this.scales.y).orient("left"); 

    //----------area fill---------- 
     this.area = d3.svg.area() 
      .x(function(d) { 
       var that1 = that; 
       return that1.scales.x(d.x); }) 
      .y0(this.height) 
      .y1(function(d) { 
       var that1 = that; 
      return that1.scales.y(d.y); }); 
    }, 

    //----------Setup brush----------------------- 
    setupBrush : function(){ 
     var that = this; 
     this.brush = d3.svg.brush() 
      .x(this.scales.x2) 
      .on("brush", function(){ 
       that.brushed(this,that); 
      }); 
    }, 
    brushed : function(d3This, view) { 
     var that = view; 
     that.scales.x.domain(that.brush.empty() ? that.scales.x2.domain() : that.brush.extent()); 
     //For FCB with bar chart 
     that.focusGraph.attr("x", function(d, i) { return that.scales.x(d.XPoint); }); 
     that.focusGraph.attr("width", 20); 
     that.focus.select(".x.axis").call(that.xAxis); 
    }, 


    renderData : function(){ 
     var that = this; 
     var x = this.scales.x, 
     y = this.scales.y, 
     x2 = this.scales.x2, 
     y2 = this.scales.y2, 
     data = this.options.data; 

     data.forEach(function(d) { 
      d.XPoint = d.x; 
      d.values = +d.y; 
     }); 

     // Scale the range of the data 
     x.domain(d3.extent(data, (function(d) { return d.XPoint; }))); 
     y.domain([0, d3.max(data, (function(d) { return d.values; }))]); 

     // Scale the range of the data in context graph too 
     x2.domain(x.domain()); 
     y2.domain(y.domain()); 

     // Add the area graph to focus and context 

     //To get bar chart in FCB 
     this.focusGraph = this.barsGroup.selectAll("rect") 
      .data(data) 
     .enter().append("rect") 
      .attr("x", function(d, i) { return x(d.XPoint); }) 
      .attr("y", function(d) { return y(d.values); }) 
      .attr("width", 5) 
      .attr("height", function(d) { return that.height - y(d.values); }) 
      .style("fill", "steelblue"); 

     this.context.selectAll("rect") 
      .data(data) 
     .enter().append("rect") 
      .attr("x", function(d, i) { return x2(d.XPoint); }) 
      .attr("y", function(d) { return y2(d.values); }) 
      .attr("width", 5) 
      .attr("height", function(d) { return that.height2 - y2(d.values); }) 
      .style("fill", "steelblue"); 


     //Functions called after all json datasets loaded 
     var x0 = x.copy(); 

     //Axis 
     this.focus.append("g") 
      .attr("class", "x axis") 
      .attr("transform", "translate(0," + this.height + ")") 
      .call(this.xAxis); 

     this.focus.append("g") 
      .attr("class", "y axis") 
      .call(this.yAxis); 

     this.context.append("g") 
      .attr("class", "x axis") 
      .attr("transform", "translate(0," + this.height2 + ")") 
      .call(this.xAxis2); 

     this.context.append("g") 
      .attr("class", "x brush") 
      .attr("clip-path", "url(#clip)") 
      .call(this.brush) 
     .selectAll("rect") 
      .attr("y", 0) 
      .attr("height", this.height2); 

     this.context.append("text") 
      .attr("class","instructions") 
      .attr('x',"345") 
      .attr('y','70') 
      // .attr("transform", "translate(0," + (this.height2 + 25) + ")") 
      .text('*Click and drag above to zoom/pan the data'); 
    }, 

數據,我提供使用的API調用圖,其對於所示圖像如下所示:

enter image description here

正如我們所看到的,2月28日總共有3次計數,但是當我縮小圖表並想分析一週的數據(如下圖所示)時,它仍然顯示我在2月28日計爲1,其中其實它應該顯示3

enter image description here

+0

如果您能向我們展示您的代碼,這將有所幫助。 –

+0

@LarsKotthoff我已經添加了我的代碼,可以幫助您正確理解我的情況。 – shahsank3t

+0

嗯,我沒有看到任何將結合上下文圖表的條形圖。是否有可能有兩個酒吧,但他們如此接近以至於他們看起來像一個? –

回答

1

我的猜測是,發生的事情是,你甚至呈現兩條槓時縮小。它們要麼直接在另一個之上,要麼非常靠近它。你可能想要的是一種叫做binning的東西。 Binning是您根據數據中出現的頻率獲取數據和存儲的位置。

要實現這一點,您可以添加簡單的裝箱功能,並在您每次縮放時調用它。假設您調整規模,以配合您的縮放域,以及您希望將數據分割成20個箱,這將是這個樣子:

var myDomain = zoomedScale.domain(), 
    binSize = (myDomain[1] - myDomain[0])/20, 
    bins = [], 
    binIndex; 

for(var i = 0; i < 20; i++){ 
    bins.push(0); 
} 

for(var i = 0; i < myData.length; i++){ 
    binIndex = Math.floor((myData[i].value - myDomain[0])/binSize); 

    if(binIndex === 20){ 
     binIndex[19] += myData[i].value; 
    } else { 
     bins[binIndex] += myData[i].value; 
    } 
} 

垃圾箱現在將代表落在數據點的總和在每個垃圾箱裏。然後,您可以更新您的圖來繪製箱而不是原始數據。

+0

我已經嘗試了您關於裝箱的建議,但它無法幫助我解決問題。我已經用適當的數據和圖像編輯了我的問題,以便您和其他人更清楚我想要執行的操作。謝謝。 – shahsank3t

+1

對於分箱,您必須根據時間進行分箱。在你的情況下,你可能想要爲每個縮放級別每隔30分鐘進行一次。您需要編寫一個函數來將所有30分鐘內出現的值相加,然後使用該函數生成新的數據數組。 – ckersch