Jacob Johnson
Jacob Johnson

Reputation: 581

D3 - Having trouble updating stacked bar chart

I have a real simple horizontally stacked bar chart with 3 bars that are all on the same scale (i.e. each 0 to 100 with the stacked bars consisting of numbers that make up 100).

When trying to update my data nothing appears to happen. I've not been able to figure out how to update the data and it's been driving me crazy.

Relevant Code:

<body>
  <div id='updateTest'>
    Update Data
  </div>
  <div id='chart'></div>


  <script>
    $( document ).ready(function() {
        $( "#updateTest" ).click(function() {
            updateData();
            console.log(allData[count]);
        });
    });

    var institution;



    // Set up the SVG data
    var allData = ["data.csv","data2.csv","data3.csv"];
    var count = 0;

    var margin = {top: 20, right: 20, bottom: 145, left: 115},
        width = 960 - margin.left - margin.right,
        height = 300 - margin.top - margin.bottom;

    var y = d3.scale.ordinal()
        .rangeRoundBands([height, 0], .1);

    var x = d3.scale.linear()
        .rangeRound([0, width]);

    var color = d3.scale.ordinal()
        .range(["#98abc5", "#8a89a6", "#7b6888"]);

    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left");

    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .tickFormat(d3.format(".2s"));

    var svg = d3.select("#chart").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

    // Bind initial shown data to the SVG
    d3.csv(allData[count], function(error, data) {
      if (error) throw error;

      color.domain(d3.keys(data[0]).filter(function(key) {
        return key !== "Institution";
      }));

      data.forEach(function(d) {
        var y0 = 0;
        d.ages = color.domain().map(function(name) {
          return {name: name, y0: y0, y1: y0 += +d[name]};
        });
        d.total = d.ages[d.ages.length - 1].y1;
      });

      data.sort(function(a, b) { return b.total - a.total; });

      y.domain(data.map(function(d) { return d.Institution; }));
      x.domain([0, d3.max(data, function(d) { return d.total; })]);

      svg.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + height + ")")
          .call(xAxis);

      svg.append("g")
          .attr("class", "y axis")
          .call(yAxis)
        .append("text")
          .attr("transform", "rotate(-90)")
          .attr("x", -32)
          .attr("y", -112)
          .attr("dy", ".71em")
          .style("text-anchor", "end")
          .text("Institution");

      institution = svg.selectAll(".institution")
          .data(data)
        .enter().append("g")
          .attr("class", "g")
          .attr("transform", function(d) {
            return "translate(0," + y(d.Institution) + ")"; });

      institution.selectAll("rect")
          .data(function(d) { return d.ages; })
        .enter().append("rect")
          .attr("height", y.rangeBand())
          .attr("x", function(d) { return x(d.y0); })
          .attr("width", function(d) { return x(d.y1) - x(d.y0); })
          .style("fill", function(d) { return color(d.name); });

      var legend = svg.selectAll(".legend")
          .data(color.domain().slice().reverse())
        .enter().append("g")
          .attr("class", "legend")
          .attr("transform", function(d, i) {
            return "translate(0," + i * 28 + ")"; });

      legend.append("rect")
        .attr("x", -20)
        .attr("y", 190)
        .attr("width", 25)
        .attr("height", 25)
        .style("fill", color);

      legend.append("text")
        .attr("x", 10)
        .attr("y", 203)
        .attr("dy", ".35em")
        .style("text-anchor", "left")
        .text(function(d) { return d; });
    });

        /* updateData()
         * Rebinds the SVG to a new dataset
         */
    function updateData() {
        // Iterate through the data
      var newData;
      if (count === allData.length - 1)
          count = 0;
      else
          count++;
      newData = allData[count];


      // Get the data again
        d3.csv(allData[count], function(error, data) {
        data.forEach(function(d) {
                d.close = +d.close;
            });

            // Make the changes
        institution.selectAll("rect")
            .data(function(d) { return d.ages; })
            .enter().append("rect")
              .attr("height", y.rangeBand())
              .attr("x", function(d) { return x(d.y0); })
              .attr("width", function(d) { return x(d.y1) - x(d.y0); })
              .style("fill", function(d) { return color(d.name); });
        });
    }

  </script>
</body>

My CSV files:

data.csv

Institution,CurrentlyOweBehind,CurrentlyOweNotBehind,Paid
For-profit,15,35,50
Nonprofit,11,48,41
Public,26,16,58

data2.csv

Institution,CurrentlyOweBehind,CurrentlyOweNotBehind,Paid
For-profit,23,33,44
Nonprofit,28,12,60
Public,12,8,80

data3.csv

Institution,CurrentlyOweBehind,CurrentlyOweNotBehind,Paid
For-profit,61,22,17
Nonprofit,7,43,50
Public,41,19,40

The main bit is in the updateData() function. I am able to create the chart and display data but I do not understand transitioning the data...

I'm getting no errors in the console and it's properly cycling the data.

Upvotes: 0

Views: 187

Answers (1)

rby
rby

Reputation: 786

The problems is with d.ages in the update function. You basically need the same setup that you have for the initial plot. So I added the following in the d3.csv block of your update function:

 data.forEach(function(d) {
    var y0 = 0;
    d.ages = color.domain().map(function(name) {
      return {name: name, y0: y0, y1: y0 += +d[name]};
    });
    d.total = d.ages[d.ages.length - 1].y1;
  });

  institution = svg.selectAll(".institution")
      .data(data);

The class name for institution was set to g for some reason, and I changed that to institution. Also, you do not need .enter().append("rect") at this point. Finally I added a transition and duration.

I have created a plunk, with all your csv files included: http://plnkr.co/edit/CYFNWZKuiLo9gFps49e9?p=preview

Hope this helps.

Upvotes: 1

Related Questions