2016-01-04 2 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 ("дисплей", функция (s) { если ((yScale (s.label) - yScale.rangeBand()) <0) { возвращение «нет»; // не показывать сетки, когда у приходит отрицательный } ' Почему она называется с функцией (ы) вместо функции (г) Можете ли вы пожалуйста, смотрите? –

+1

Я установил 5-секундную смену, из-за которой база данных @ 17 приходит 12. Вы можете написать это: 'style (" display ", function (s) {}' или 'style (" display ", function (d) {} 'его просто имя параметра, которое изменяется вместо' d' я делаю его '..simple .. :) Цель функции' style ("display", function (s) { if ((yScale (s.label) - yScale.rangeBand()) <0) {return "none"; // не показывать сетки, когда y приходит отрицательный} '- это скрыть горизонтальную сетку для argentina coz, она наступает отрицательная. line и увидеть его для себя, что происходит и что делает эта строка. Я обновил свою скрипку abov. – Cyril

+0

Это не работает, когда есть несколько ярлыков, которые являются одинаковыми. Когда я использую данные, которые имеют две разные страны но с тем же периодом, он ставит два стержня в одном Y position ... –

Смежные вопросы