Search code examples
javascriptd3.jsappendbar-chartstacked-chart

Appending Stacked Bar and Another Bar Chart in D3


I want to append the stacked bar chart as well as another bar chart with different dimensions so that all three are visible, but appended bar chart is not visible even if it is used with different dimension. Working fiddle

CODE.HTML

     <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <title>Simple STACKBAR</title>
        <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
        <style type="text/css">
        svg {
          font: 10px sans-serif;
          shape-rendering: crispEdges;
        }

        .axis path,
        .axis line {
          fill: none;
          stroke: #000;
        }

        path.domain {
          stroke: none;
        }

        .y .tick line {
          stroke: #ddd;
        }

         .bar1 {
          fill: steelblue;
          opacity: 0.5;
        }

         .bar1:hover {
          fill: brown;
        }

        </style>

      </head>
      <body>
      <script type="text/javascript">

      // Setup svg using Bostock's margin convention

      var margin = {top: 20, right: 160, bottom: 35, left: 30};

      var width = 960 - margin.left - margin.right,
          height = 500 - margin.top - margin.bottom;

      var svg = d3.select("body")
        .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 + ")");


      /* Data in strings like it would be if imported from a csv */

      var data = [
        { year: "Technical/Analytical", redDelicious: "10", mcintosh: "15", oranges: "19" },
        { year: "Problem Solving", redDelicious: "12", mcintosh: "18", oranges: "19" },
        { year: "Communication", redDelicious: "05", mcintosh: "20", oranges: "28" },
        { year: "Specialization", redDelicious: "08", mcintosh: "15", oranges: "16" },

      ];

      //var parse = d3.time.format("%Y").parse;


      // Transpose the data into layers
      var dataset = d3.layout.stack()(["redDelicious", "mcintosh"].map(function(skillset) {
        return data.map(function(d) {
          return {x: d.year, y: +d[skillset]};
        });
      }));


      // Set x, y and colors
      var x = d3.scale.ordinal()
        .domain(dataset[0].map(function(d) { return d.x; }))
        .rangeRoundBands([10, width-10], 0.02);

      var y = d3.scale.linear()
        .domain([0, d3.max(dataset, function(d) {  return d3.max(d, function(d) { return d.y0 + d.y; });  })])
        .range([height, 0]);

      var colors = ["#b33040", "#d9d574"];


      // Define and draw axes
      var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left")
        .ticks(5)
        .tickSize(-width, 0, 0)
        .tickFormat( function(d) { return d } );

      var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom");
      //  .tickFormat(d3.time.format("%Y"));

      svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

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



      // Create groups for each series, rects for each segment 
      var groups = svg.selectAll("g.cost")
        .data(dataset)
        .enter().append("g")
        .attr("class", "cost")
        .style("fill", function(d, i) { return colors[i]; });

      var rect = groups.selectAll("rect")
        .data(function(d) { return d; })
        .enter()
        .append("rect")
        .attr("x", function(d) { return x(d.x); })
        .attr("y", function(d) { return y(d.y0 + d.y); })
        .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); })
        .attr("width", x.rangeBand());

           groups.append("rect")
              .attr("class", "bar1")
              .attr("x", function(d) {
                return x(d.year) + 20; // center it
              })
              .attr("width", x.rangeBand() - 40) // make it slimmer
              .attr("y", function(d) {
                return y(d.oranges);
              })
              .attr("height", function(d) {
                return height - y(d.oranges);
              });

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

Solution

  • Step1

    Make the data set for orange bar using map as shown below:

    var orangeData = data.map(function(d) {
            return {
              year: d.year,
              oranges: +d.oranges
            }
          });
    

    Step2

    Make the stacked bar chart slimmer and place it side of the x tick.

     var rect = groups.selectAll("rect")
            .data(function(d) {
              return d;
            })
            .enter()
            .append("rect")
            .attr("x", function(d) {
              return x(d.x) + x.rangeBand() / 4;//places stack left of the x tick
            })
            .attr("y", function(d) {
              return y(d.y0 + d.y);
            })
            .attr("height", function(d) {
              return y(d.y0) - y(d.y0 + d.y);
            })
            .attr("width", x.rangeBand() / 4);//make the stack bar thin by 4 times.
    

    Step 3

    Make the bar chart.

    svg.selectAll(".bar1").data(orangeData).enter().append("g")
            .attr("class", "bar1").append("rect")
            .attr("x", function(d) {
              return x(d.year) + x.rangeBand() / 2; // place it right if the x tick
            })
            .attr("width", x.rangeBand()/4) // make it as slim as stacked bar chart
            .attr("y", function(d) {
              return y(d.oranges);
            })
            .attr("height", function(d) {
              return height - y(d.oranges);
            });
    

    working code here