2017-02-28 7 views
0

Ich habe die folgenden Daten in einer csv Datei BarData.csv genannt:Balkendiagramm Konto von negativen Werten nehmen

Fruit,dt,amount 
Apple,12/28/2016,-1256 
Apple,12/29/2016,-500 
Apple,12/30/2016,3694 
Apple,12/31/2016,5586 
Apple,1/1/2017,4558 
Apple,1/2/2017,6696 
Apple,1/3/2017,7757 
Apple,1/4/2017,8528 
Apple,1/5/2017,5543 
Apple,1/6/2017,3363 
Apple,1/7/2017,5464 
Pear,12/25/2017,250 
Pear,12/26/2017,669 
Pear,12/27/2017,441 
Pear,12/28/2017,159 
Pear,12/29/2017,357 
Pear,12/30/2017,775 
Pear,12/31/2017,669 

Die folgenden html, css und javascript ist in einer .html Datei:

<!DOCTYPE html> 
<html> 

<head> 
    <meta http-equiv="Content-type" content="text/html; charset=utf-8"> 
    <title>BAR SINGLE FUNCTION</title> 
    <script src="http://d3js.org/d3.v3.js"></script> 
    <style type="text/css"> 
    #radioDiv { 
     top: 45px; 
     font-family: verdana; 
     font-size: 8px; 
     width: 455px; 
    } 

    #TOPbarChart { 
     position: absolute; 
     top: 50px; 
     left: 30px; 
     width: 750px; 
     height: 195px; 
    } 

    .axis--y path, 
    .axis--x path { 
     display: none; 
    } 

    .axis--x line, 
    .axis--y line { 
     stroke: black; 
     fill: none; 
     stroke-width: 2px 
    } 

    .yAxis text, 
    .xAxis text { 
     font: 7pt Verdana; 
     stroke: none; 
     fill: black; 
    } 

    .title, 
    .titleX { 
     font-family: Verdana; 
     font-size: 10px; 
    } 
    </style> 
</head> 

<body> 
    <div id="radioDiv"> 
     <label> 
      <input id="radioFrt" type="radio" name="frt" value="Apple" class="radioB" checked> APPLE 
     </label> 
     <label> 
      <input type="radio" name="frt" value="Pear" class="radioB"> PEAR 
     </label> 
    </div> 
    <div id="TOPbarChart"></div> 
    <script type="text/javascript"> 
    var currentFruit = "Apple"; 
    var currentColr = "#00a5b6"; 

    var barDataCSV_Dly = "BarData.csv"; 

    // 
    // 
    // radio button 
    document.getElementById("radioFrt").checked = true; 
    d3.selectAll('input[name="frt"]').on("change", function change() { 
     currentFruit = this.value; 
     TOPbarChart(currentFruit, currentColr); 
    }); 

    //FORMATS 
    var parseDate = d3.time.format("%m/%d/%Y").parse; 



    // 
    // BASIC SIZING 
    // 
    function barChartBasics() { 
     var margin = { 
       top: 25, 
       right: 35, 
       bottom: 25, 
       left: 70 
      }, 
      width = 550 - margin.left - margin.right, 
      height = 155 - margin.top - margin.bottom, 
      colorBar = d3.scale.category20(), 
      barPaddingFine = 1, 
      barPaddingThick = 2; 
     return { 
      margin: margin, 
      width: width, 
      height: height, 
      colorBar: colorBar, 
      barPaddingFine: barPaddingFine, 
      barPaddingThick: barPaddingThick 
     }; 
    } 


    // create svg element 
    var basics = barChartBasics(); 
    var svg = d3.select("#TOPbarChart") 
     .append("svg") 
     .attr({ 
      "width": basics.width + basics.margin.left + basics.margin.right, 
      "height": basics.height + basics.margin.top + basics.margin.bottom, 
      id: "svgTOPbarChart" 
     }); 

    // create svg group 
    var plot = svg 
     .append("g") 
     .attr({ 
      "transform": "translate(" + basics.margin.left + "," + basics.margin.top + ")", 
      id: "svgPlotTOPbarChart" 
     }); 

    var axisPadding = 2; 
    var leftAxisGroup = svg 
     .append('g') 
     .attr({ 
      transform: 'translate(' + (basics.margin.left - axisPadding) + ',' + (basics.margin.top) + ')', 
      'class': "yAxis axis--y", 
      id: "yAxisGTOPbarChart" 
     }); 

    var bottomAxisGroup = svg 
     .append('g') 
     .attr({ 
      'class': "xAxis axis--x", 
      id: "xAxisGTOPbarChart" 
     }); 

    var titleTxt = svg.append("text") 
     .attr({ 
      x: basics.margin.left + 12, 
      y: 20, 
      'class': "title", 
      'text-anchor': "start" 
     }) 

    // create scales with ranges 
    var xScale = d3.time.scale().range([0, basics.width]); 
    var yScale = d3.scale.linear().range([basics.height, 0]); 




    function TOPbarChart(
     frt, colorChosen) { 

     // get the data 
     d3.csv(barDataCSV_Dly, function(rows) { 

      TOPbarData = rows.map(function(d) { 
       return { 
        "Fruit": d.Fruit, 
        "dt": parseDate(d.dt), 
        "amount": +d.amount 
       }; 
      }).filter(function(row) { 
       if (row['Fruit'] == frt) { 
        return true; 
       } 
      }); 


      // create domains for the scales 
      xScale.domain(d3.extent(TOPbarData, function(d) { 
       return d.dt; 
      })); 
      var amounts = TOPbarData.map(function(d) { 
       return d.amount; 
      }); 
      var yMax = d3.max(amounts); 
      var yMin = d3.min(amounts); 
      var yMinFinal = 0; 
      if (yMin < 0) { 
       yMinFinal = yMin; 
      } 
      yScale.domain([yMinFinal, yMax]); 


      // introduce the bars 
      // var plot = d3.select("#svgPlotTOPbarChart") 
      var sel = plot.selectAll("rect") 
       .data(TOPbarData); 

      sel.enter() 
       .append("rect") 
       .attr({ 
        x: function(d, i) { 
         return xScale(d.dt); 
        }, 
        y: function(d) { 
         return yScale(d.amount); 
        }, 
        width: (basics.width/TOPbarData.length - basics.barPaddingFine), 
        height: function(d) { 
         return basics.height - yScale(d.amount); 
        }, 
        fill: colorChosen, 
        'class': "bar" 
       }); 

      // this little function will create a small ripple affect during transition 
      var dlyRipple = function(d, i) { 
       return i * 100; 
      }; 
      sel 
       .transition() 
       .duration(dlyRipple) //1000 
       .attr({ 
        x: function(d, i) { 
         return xScale(d.dt); 
        }, 
        y: function(d) { 
         return yScale(d.amount); 
        }, 
        width: (basics.width/TOPbarData.length - basics.barPaddingFine), 
        height: function(d) { 
         return basics.height - yScale(d.amount); 
        }, 
        fill: colorChosen 
       }); 

      sel.exit().remove(); 


      // add/transition y axis - with ticks and tick markers 
      var axisY = d3.svg.axis() 
       .orient('left') 
       .scale(yScale) 
       .tickFormat(d3.format("s")) // use abbreviations, e.g. 5M for 5 Million 
       .outerTickSize(0); 
      leftAxisGroup.transition().duration(1000).call(axisY); 

      // add/transition x axis - with ticks and tick markers 
      var axisX = d3.svg.axis() 
       .orient('bottom') 
       .scale(xScale); 

      bottomAxisGroup 
       .attr({ 
        transform: 'translate(' + (basics.margin.left + ((basics.width/TOPbarData.length)/2)) + ',' + (basics.margin.top + basics.height) + ')', 
       }) 
       .transition().duration(1000).call(axisX.ticks(5)); 


      titleTxt.text("Daily: last " + TOPbarData.length + " days"); 
      // console.log(TOPbarData.length) 

     }); 
    } 

    // 
    // 
    // 
    // 
    TOPbarChart(currentFruit, currentColr); 
    // 
    // 
    // 
    // 
    </script> 
</body> 

</html> 

Wenn alle Daten positiv sind, ist alles in Ordnung - aber wenn einige der Daten negativ sind, können wir das Ergebnis in dieser Demoversion sehen:

http://plnkr.co/edit/1hudJYkRq2MnuIlwxXZi?p=preview

Wie ändere ich den Code, so dass: - die negativen Balken angezeigt werden? - die Basis der positiven Balken bewegt sich vertikal nach oben, wenn negative Zahlen enthalten sind? - die vertikale Bewegung ist auch im Übergang enthalten?

Oben ist mehr als 1 Frage, aber Hilfe auf jedem würde geschätzt werden.

Antwort

1

Der Schlüssel ist, mit den y und height Attributen der Balken zu spielen, um sie richtig zu positionieren.

Für y, ändern Sie auf:

y: function(d) { 
      return yScale(Math.max(0, d.amount)); 
     }, 

Und für die height, ändern Sie es zu:

height: function(d) { 
       return Math.abs(yScale(d.amount) - yScale(0)); 
      }, 

Sie können dann die negativen Balken stylen sie eine andere Farbe zu machen.

Überprüfen Sie die aktualisierte Plunkr - http://plnkr.co/edit/q7dQsPW0PiPuwFTy8gLN?p=preview

Edit:

Für den farbgebenden Teil, können Sie es mit einem 1-Liner erreichen, wenn Sie Linien reduzieren wollen und mehr Einfachheit wollen.

Statt:

fill: function(d) { 
       var col = colorChosen 
       if (d.amount < 0) { 
        col = "#FF0000"; 
       } 
       return col; 
      }, 
    }); 

können Sie tun:

fill: function(d) { 
         return d.amount < 0 ? "#FF0000" : colorChosen; 
        }, 
+0

(upped) ich nur auf einen Beitrag von Bostock riskierte, die auch mich als sich in die gleiche Richtung weisen wurde - dieses Beispiel ist horizontale Balken: http://stackoverflow.com/questions/10127402/bar-chart-with-negative-values#10127733 – whytheq

+0

@whytheq groß! und ja, es kann sowohl horizontal als auch vertikal erreicht werden, hängt davon ab, welche man besser zu Ihren Bedürfnissen passt. – sparta93

+0

netter: Ich hatte selbst an der Farboptimierung - wahrscheinlich könnte es eleganter getan haben? : http://pnnr.co/edit/hO8AF23YTBY9tvkXtB0W?p=preview – whytheq

Verwandte Themen