2016-04-30 22 views
9

Rysowanie wykresu wielostopniowego za pomocą nvd3. Mój problem polega na tym, że paski się nakładają. Na wykresie na osi y znajduje się po lewej stronie, a druga oś Y po prawej stronie.NVD3 Wiele osiach Barchart nakładających się pasków na rysunku

<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="utf-8"> 
    <link href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.3/nv.d3.css" rel="stylesheet" type="text/css"> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.2/d3.min.js" charset="utf-8"></script> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.3/nv.d3.js"></script> 
    <style> 
     text { 
      font: 12px sans-serif; 
     } 
     svg { 
      display: block; 
     } 
     html, body, #chart1, svg { 
      margin: 0px; 
      padding: 0px; 
      height: 100%; 
      width: 100%; 
     } 
    </style> 
</head> 
<body class='with-3d-shadow with-transitions'> 

<div id="chart1" > 
    <svg> </svg> 
</div> 

<script> 

    // var testdata = stream_layers(9,10+Math.random()*100,.1).map(function(data, i) { 
    //  return { 
    //   key: 'Stream' + i, 
    //   values: data.map(function(a){a.y = a.y * (i <= 100 ? 100 : 1); return a}) 
    //  }; 
    // }); 
    var testdata=[{"key":"stream1", "values": [ 
    { 
     "x": 0, 
     "y": 44 
    }, 
    { 
     "x": 1, 
     "y": 10 
    }, 
    { 
     "x": 2, 
     "y": 29 
    }, 
    { 
     "x": 3, 
     "y": 88 
    }, 
    { 
     "x": 4, 
     "y": 25 
    }, 
    { 
     "x": 5, 
     "y": 32 
    }, 
    { 
     "x": 6, 
     "y": 100 
    }, 
    { 
     "x": 7, 
     "y": 52 
    }, 
    { 
     "x": 8, 
     "y": 15 
    }, 
    { 
     "x": 9, 
     "y": 78 
    }, 
    { 
     "x": 10, 
     "y": 42 
    }, 
    { 
     "x": 11, 
     "y": 108 
    }, 
    { 
     "x": 12, 
     "y": 17 
    }, 
    { 
     "x": 13, 
     "y": 23 
    }, 
    { 
     "x": 14, 
     "y": 182 
    }, 
    { 
     "x": 15, 
     "y": 9 
    }, 
    { 
     "x": 16, 
     "y": 25 
    }, 
    { 
     "x": 17, 
     "y": 90 
    }, 
    { 
     "x": 18, 
     "y": 32 
    }, 
    { 
     "x": 19, 
     "y": 138 
    }, 
    { 
     "x": 20, 
     "y": 189 
    }, 
    { 
     "x": 21, 
     "y": 3 
    }, 
    { 
     "x": 22, 
     "y": 16 
    }, 
    { 
     "x": 23, 
     "y": 66 
    }, 
    { 
     "x": 24, 
     "y": 46 
    }, 
    { 
     "x": 25, 
     "y": 27 
    }, 
    { 
     "x": 26, 
     "y": 185 
    }, 
    { 
     "x": 27, 
     "y": 13 
    }, 
    { 
     "x": 28, 
     "y": 12 
    }, 
    { 
     "x": 29, 
     "y": 71 
    }, 
    { 
     "x": 30, 
     "y": 191 
    } 
    ]}, 
    {"key":"stream2","values":[ 
    { 
     "x": 0, 
     "y": 1.1 
    }, 
    { 
     "x": 1, 
     "y": 0.5 
    }, 
    { 
     "x": 2, 
     "y": 2.1 
    }, 
    { 
     "x": 3, 
     "y": 1.5 
    }, 
    { 
     "x": 4, 
     "y": 1.7 
    }, 
    { 
     "x": 5, 
     "y": 2.1 
    }, 
    { 
     "x": 6, 
     "y": 0.75 
    }, 
    { 
     "x": 7, 
     "y": 1.75 
    }, 
    { 
     "x": 8, 
     "y": 1 
    }, 
    { 
     "x": 9, 
     "y": 2.3 
    }, 
    { 
     "x": 10, 
     "y": 2 
    }, 
    { 
     "x": 11, 
     "y": 0.5 
    }, 
    { 
     "x": 12, 
     "y": 1.6 
    }, 
    { 
     "x": 13, 
     "y": 1.8 
    }, 
    { 
     "x": 14, 
     "y": 2.35 
    }, 
    { 
     "x": 15, 
     "y": 2.4 
    }, 
    { 
     "x": 16, 
     "y": 1.8 
    }, 
    { 
     "x": 17, 
     "y": 1 
    }, 
    { 
     "x": 18, 
     "y": 1.25 
    }, 
    { 
     "x": 19, 
     "y": 1.85 
    }, 
    { 
     "x": 20, 
     "y": 0.65 
    }, 
    { 
     "x": 21, 
     "y": 0.75 
    }, 
    { 
     "x": 22, 
     "y": 1.25 
    }, 
    { 
     "x": 23, 
     "y": 2.25 
    }, 
    { 
     "x": 24, 
     "y": 0.5 
    }, 
    { 
     "x": 25, 
     "y": 1.85 
    }, 
    { 
     "x": 26, 
     "y": 1.75 
    }, 
    { 
     "x": 27, 
     "y": 1.15 
    }, 
    { 
     "x": 28, 
     "y": 1.9 
    }, 
    { 
     "x": 29, 
     "y": 2.4 
    }, 
    { 
     "x": 30, 
     "y": 1.5 
    } 
    ]}]; 
    testdata[0].type = "bar"; 
    testdata[0].yAxis = 1; 
    testdata[1].type = "bar"; 
    testdata[1].yAxis = 2; 
    console.log(testdata); 

    nv.addGraph(function() { 
     var chart = nv.models.multiChart() 
      .margin({top: 30, right: 60, bottom: 50, left: 70}) 
      .color(d3.scale.category10().range()) 
      .height(450) 
      .width(1200) 
      .color(d3.scale.category10().range()) 
      .useInteractiveGuideline(true) 
      .interpolate('linear'); 

     chart.xAxis.tickFormat(d3.format(',f')); 
     chart.yAxis1.tickFormat(d3.format(',.1f')); 
     chart.yAxis2.tickFormat(d3.format(',.1f')); 

     d3.select('#chart1 svg') 
      .datum(testdata) 
      .transition().duration(500).call(chart); 

     return chart; 
    }); 

</script> 
</body> 
</html> 

Plunkr setup embeded na ten temat można znaleźć here.

Dwa zestawy danych do narysowania wykresu wielobarwnego Ale paski zachodzą na siebie. My Out umieścić zrzut ekranu jest tutaj.

Screenshot of Barchart with two y-axes and different data range.

jedyną rzeczą do zrobienia jest, aby dostosować szerokość i położenie prętów. te są wybierane przez klasę

d3.selectAll ('.bars1Wrap .nv-groups .nv-series-0 rect') 

Kiedy przełączyć oś do

testdata[1].yAxis = 1; 

Działa idealnie. Graph with one y-axis. But the Ranging is lost.

Ale problemem jest zakres utraconych danych. Potrzebuję innego zakresu dla dwóch zbiorów danych.

starałem się dopasować szerokość prętów po rysunku wykres

jak

var g3 = d3.selectAll ('.bars1Wrap .nv-groups .nv-series-0 rect') 
          .attr("width", function(d){ return d/2;}); 

ale nie sukces ... Każda pomoc mile widziane.

Odpowiedz

2

Zdecydowanie, nvd3 jest buggy na multiChart, po wybraniu typu "pasek" dla dwóch zestawów danych wizualizacji, które muszą być wyświetlane.

co mówię, jest to, że zamiast tego

testdata[0].type = "bar"; 
testdata[0].yAxis = 1; 
testdata[1].type = "bar"; 
testdata[1].yAxis = 2; 

gdyby było

testdata[0].type = "line"; 
testdata[0].yAxis = 1; 
testdata[1].type = "bar"; 
testdata[1].yAxis = 2; 

To działa dobrze.

Tak więc, aby dwa wykresy słupkowe nie były zapakowane. Konieczne jest wykonanie pewnych modyfikacji po wyjęciu z pudełka, wywołanie tej funkcji powoduje, że wykres słupkowy funkcji jest renderowany.

function resetBarSize(d1){ 
     //get the width of the bar, and make it half 
     var w2 = d3.select(".bars2Wrap .nv-bar").attr("width")/2; 
     if (!d1){ 
     //initial load d1 will be undefined 
     //in that case make all the bars half 
     d3.selectAll(".bars1Wrap .nv-bar").style("width", w2); 
     d3.selectAll(".bars2Wrap .nv-bar").style("width", w2); 
     //translate the last bar so that there is no overlapping 
     d3.selectAll(".bars2Wrap .nv-bar")[0].forEach(function(d){ 
      var t = d3.transform(d3.select(d).attr("transform")), 
      x = t.translate[0] + w2, 
      y = t.translate[1]; 
      d3.select(d).attr("transform", "translate(" + x +"," + y + ")"); 
     })   
     }else if (d1.yAxis ==2 && d1.disabled){ 
     //in this case axis 2 is disabled or not visible so make bar1 width double. 
     d3.selectAll(".bars1Wrap .nv-bar").style("width", w2 *2); 
     }else if (d1.yAxis ==1 && d1.disabled){ 
     //in this case axis 1 is disabled or not visible so make bar1 width double. 
     d3.selectAll(".bars2Wrap .nv-bar").style("width", w2 *2); 
     } else { 
     //in this case axis both axis is present. Make all the bars half and translate bar 2 so that they don't overlap. 

     d3.selectAll(".bars1Wrap .nv-bar").style("width", w2); 
     d3.selectAll(".bars2Wrap .nv-bar").style("width", w2); 
     d3.selectAll(".bars2Wrap .nv-bar")[0].forEach(function(d){ 
      var t = d3.transform(d3.select(d).attr("transform")), 
      x = t.translate[0] + w2, 
      y = t.translate[1]; 
      d3.select(d).attr("transform", "translate(" + x +"," + y + ")"); 
     }) 
     } 
     return; 
    } 

Teraz wywołaj tę funkcję po renderowaniu wykresu.

nv.dispatch.on('render_end', function(newState) { 
    resetBarSize(); 
    chart.legend.dispatch.on('legendClick', function(newState) { 
     chart.update(); 
     setTimeout(function(){resetBarSize(newState)}); 
}); 

kod roboczych here

+0

Z góry dzięki za świetne rozwiązanie. Jeszcze jeden problem, który znalazłem na kodzie, że jeśli wyłączę jedną legendę, pasek musi osiągnąć pełną szerokość. Również w mojej sytuacji nie mogę wywołać drugiej funkcji po narysowaniu wykresu. W każdym razie zmodyfikuję kod nvd3, żeby to zrobić. Dziękuję, że poprowadziłeś mnie w kierunku znalezienia ostatecznego rozwiązania. Mam nadzieję, że ta odpowiedź przyda się również innym. –

+1

Proszę sprawdzić poprawioną odpowiedź, mój kod sprawia, że ​​pasek jest pełny, kiedy legenda jest wyłączona. – Cyril