2016-01-04 23 views
2

我正在this infographic建立多尺度,嵌套,有序條形圖與D3

這在D3證明困難的交互式版本。將有多個順序尺度:

  • 一個Y的比例爲每個國家
  • 一個Y的比例在每個國家每個時期
  • One X的規模

每個時期都會有兩個值(可視化爲兩個不同顏色的條)。主要問題是並非所有國家都會有三個階段;數據並不完全一致。這就是說,第一個Y量表的某些部分會有不同的高度。我不知道如何照顧這個。

假設我有這樣的數據:

CountryName Period ValueA ValueB 
Argentina 2004-2008 12 5 
Argentina 2004-2013 10 5 
Argentina 2008-2013 8 4 
Bolivia 2002-2008 4 2 
Bolivia 2002-2013 6 18 
Brazil 2003-2008 9 2 
Brazil 2003-2013 2 19 
Brazil 2008-2013 1 3 

,而且我用d3.nest()函數:

d3.nest() 
    .key(function(d) { return d.CountryName; }) 
    .key(function(d) { return d.Period; }) 
    .map(data); 

現在我有我想要的表單中的數據,但請注意,有一些數據缺失 - 在這種情況下,玻利維亞只有兩個階段的數據。我爲此創建了一個JSFiddle,但正如您所看到的那樣,它有一些問題。酒吧的高度應該始終如一。我想使用yScale.rangeBand(),但問題是有些國家會有三個階段,其中一些只有兩個階段。我還需要找到一種方法來顯示國家名稱和期間左邊的酒吧

如果有人有更好的方法來解決這個問題,請讓我知道。我一直在爲此掙扎幾天。從JSFiddle中可以看到,我只有一個yScale,但我確定最好使用兩個給定的情況 - 我不知道如何實現這一點。

任何和所有的幫助,非常感謝

回答

1

你可能並不真的需要嵌套。 這是一個特殊情況的條形圖,所以您需要自己製作座標軸。

我已經在代碼中添加註釋你跟着

var outerWidth = 1000; 
 
    var outerHeight = 500; 
 
    var margin = { 
 
     left: 100, 
 
     top: 0, 
 
     right: 100, 
 
     bottom: 90 
 
    }; 
 
    var barPadding = 0.6; 
 
    var barPaddingOuter = 0.3; 
 
    var innerWidth = outerWidth - margin.left - margin.right; 
 
    var innerHeight = outerHeight - margin.top - margin.bottom; 
 
    //make your svg 
 
    var svg = d3.select("body").append("svg") 
 
     .attr("width", outerWidth) 
 
     .attr("height", outerHeight); 
 
    var g = svg.append("g") 
 
     .attr("transform", "translate(" + margin.left + "," + margin.top + 30 + ")"); 
 
    //the axis is on the right 
 
    var xAxisG = g.append("g") 
 
     .attr("class", "x axis") 
 
     .attr("transform", "translate(0," + 10 + ")") 
 

 
    //the y axis is common for all 
 
    var yAxisG = g.append("g") 
 
     .attr("class", "y axis"); 
 

 
    var xScale = d3.scale.linear().range([0, innerWidth]); 
 
    var yScale = d3.scale.ordinal().rangeRoundBands([0, innerHeight], barPadding, barPaddingOuter); 
 

 
    var yAxis = d3.svg.axis().scale(yScale).orient("left") 
 
     .outerTickSize(0); 
 

 
    function render(data) { 
 
     var xAxis = d3.svg.axis().scale(xScale).orient("top") 
 
     //.tickValues([-5, -4, -3, 0, 3, 5, 10, 15, 20, 25]) 
 
     .outerTickSize(0) 
 
     .innerTickSize(-1 * outerHeight); 
 

 
     xScale.domain([0, 30]); 
 

 
     //this will make the y axis labels. 
 
     var country = ""; 
 
     data.forEach(function(d) { 
 
     if (d.CountryName == country) { 
 
      d.label = d.Period 
 
     } else { 
 
      d.label = d.Period 
 
      d.heading = d.CountryName; 
 
     } 
 
     country = d.CountryName; 
 
     }); 
 
     var labels = data.map(function(d) { 
 
     return d.label 
 
     }); 
 
     //set the domain for all y labels, 
 
     yScale.domain(labels); 
 
     //makes the x Axis 
 
     xAxisG.call(xAxis); 
 
     //makes the y Axis 
 
     yAxisG.call(yAxis); 
 
     //make the bar chart for valueB 
 
     var bars = g.selectAll(".ValueA").data(data); 
 
     bars.enter().append("rect") 
 
     .attr("height", yScale.rangeBand()/2); 
 
     bars 
 
     .attr("x", function(d) { 
 
      return xScale(0) 
 
     }) 
 
     .attr("y", function(d) { 
 
      return yScale(d.label); 
 
     }) 
 
     .attr("width", function(d) { 
 
      console.log(d.ValueA) 
 
      return xScale(d.ValueA); 
 
     }) 
 
     .style("fill", "red") 
 
     .attr("class", "ValueA"); 
 
     //make the bar chart for valueB 
 
     var bars = g.selectAll(".ValueB").data(data); 
 
     bars.enter().append("rect") 
 
     .attr("height", yScale.rangeBand()/2); 
 
     bars 
 
     .attr("x", function(d) { 
 
      return xScale(0) 
 
     }) 
 
     .attr("y", function(d) { 
 
      return yScale.rangeBand()/2 + yScale(d.label); 
 
     }) 
 
     .attr("width", function(d) { 
 
      return xScale(d.ValueB); 
 
     }) 
 
     .style("fill", "blue") 
 
     .attr("class", "ValueA"); 
 
     //make grid lines 
 
     var lines = g.selectAll(".xLine").data(data.filter(function(d){return !(d.heading == undefined) })); 
 
     lines.enter().append("line") 
 
     lines 
 
     .attr("x1", 0) 
 
     .attr("y1", function(d) { 
 
      return (yScale(d.label) - yScale.rangeBand()) 
 
     }) 
 
     .attr("x2", innerWidth) 
 
     .attr("y2", function(d) { 
 
      return (yScale(d.label) - yScale.rangeBand()) 
 
     }) 
 
     .style("stroke", "blue") 
 
     .attr("class", "xLine") 
 
     .style("display", function(s) { 
 
      if((yScale(s.label) - yScale.rangeBand()) < 0){ 
 
      return "none";//not show grids when y comes negative 
 
      } 
 
     }); 
 
     
 
     //make heading 
 
     var headings = g.selectAll(".heading").data(data.filter(function(d){return !(d.heading == undefined) })); 
 
     headings.enter().append("text") 
 
     .text(function(d){return d.heading}) 
 
     .attr("x", -100) 
 
     .attr("y", function(d) { 
 
      return (yScale(d.label) - yScale.rangeBand()) +30 
 
     }) 
 

 
    } 
 

 
    function type(d) { 
 
     d.ValueA = +d.ValueA; 
 
     d.ValueB = +d.ValueB; 
 
     console.log(d) 
 
     return d; 
 
    } d3.csv("https://gist.githubusercontent.com/cyrilcherian/e2dff83329af684cde78/raw/f85ce83497553c360d2af5d5dcf269390c44022f/cities.csv", type, render);
.tick line { 
 
     opacity: 0.2; 
 
    } 
 
    
 
    .xLine { 
 
     opacity: 0.2; 
 
    } 
 
    
 
    .axis text { 
 
     font-size: 10px; 
 
    } 
 
    
 
    .axis .label {} 
 
    
 
    .axis path, 
 
    .axis line { 
 
     fill: none; 
 
     stroke: #000; 
 
     shape-rendering: crispEdges; 
 
    } 
 
    
 
    .y.axis path, 
 
    .y.axis line { 
 
     stroke: none; 
 
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

希望這有助於!

+0

感謝您的支持!它絕對有幫助。我有一些問題,但我注意到圖表沒有顯示每個數據的正確值。例如,2004 - 2008年的阿根廷應該有12個和5個,但是它會在你的片段中呈現爲17和10個。看起來寬度是5個單位的差距? 另外,我不理解這個匿名功能: '.style( 「顯示」 時,(多個)功能{ 如果((yScale(s.label) - yScale.rangeBand())<0){ 返回「none」; //當y變爲負數時不顯示網格 } 爲什麼使用函數調用而不是函數(d)? 您能否看一下? –

+1

我已經修復了5個單位移位,這就是databar @ 17來到12的原因。 您可以這樣寫:'style(「display」,function(s){}'或'style(「display」,function(d ){}'它只是參數名稱被改變而不是'd'我正在使's' ..簡單.. :) 函數style(「display」,function(s){如果((yScale(s.label) - yScale.rangeBand())<0){return「none」; //當y變爲負數時不顯示網格}'將隱藏阿根廷的水平網格。並自己看看會發生什麼,以及這條線有什麼影響 我已更新我的小提琴abov。 – Cyril

+0

當有多個標籤相同時,這似乎不起作用當我使用具有兩個不同國家但是在同一時期,它在同一個Y中放了兩個小節位置... –