1
votes

I have been searching for a while about how to handle the X axis in a stacked bar chart (since dataset is a little different from a single bar chart).

Basically, I have data for a 24hr period in 15 minute intervals. However, I only want to display the x-axis in 2hr ticks.

Existing Fiddle: [https://jsfiddle.net/lucksp/crwb4v5u/][1]

It currently prints all the intervals.

I have tried various scale options with time but something doesn't translate with the way I have this setup.

var xScale = d3.scale.ordinal()
  .domain(dataset[0].map(function(d) {
    return d.x;
  }))
  .rangeRoundBands([0, width - margin.left]);

var xAxis = d3.svg.axis()
  .scale(xScale)
  .orient('bottom')
  .tickSize(0)
  .ticks(12)
  .tickFormat(function(d) {
    return d;
  });
var rect = groups.selectAll('rect')
  .data(function(d) {
    return d;
  })
  .enter()
  .append('rect')
  .attr('class', function(d, i) {
    return 'stacks ' + d.type;
  })
  .classed('stacks', true)
  .attr('id', function(d, i) {
    return d.type + '_' + i;
  })
  .attr('x', function(d) {
    return xScale(d.x);
  })
  .attr('y', function(d) {
    return yScale(d.y0 + d.y);
  })
  .attr('height', function(d) {
    return yScale(d.y0) - yScale(d.y0 + d.y);
  })
  .attr('width', xScale.rangeBand());

  [1]: https://jsfiddle.net/lucksp/crwb4v5u/

I know it's user error, but after looking at this for the last 2 days, I am resorting to asking this question now. Thanks!

1
I think part of the issue is D3 is not aware the "hour" in your data is time. You can have d3 parse the value into a date object, then have d3 take care of the xAxis ticks. Here's an example. Notice the use of parse and d3.time.scale() - Karl Galvez
@KarlGalvez I was definitely trying to use the time.scale & parse methods, but could not get it to work. I'll try again tho. - Phil Lucks

1 Answers

0
votes

You are currently trying to use .ticks which will only work if the scale you're using has an inbuilt ticks function. Your ordinal scale in this case does not. It will by default use all values in the domain.

To go around it, we can manually set the ticks using xAxis.tickValues(["custom tick values that match domain vals"]). Check the snippet below.

var data = [{"hour":"0:00","inProgress":3,"inQueue":0},{"hour":"0:15","inProgress":5,"inQueue":3},{"hour":"0:30","inProgress":1,"inQueue":1},{"hour":"0:45","inProgress":1,"inQueue":0},{"hour":"1:00","inProgress":2,"inQueue":0},{"hour":"1:15","inProgress":8,"inQueue":2},{"hour":"1:30","inProgress":5,"inQueue":3},{"hour":"1:45","inProgress":5,"inQueue":1},{"hour":"2:00","inProgress":6,"inQueue":0},{"hour":"2:15","inProgress":6,"inQueue":0},{"hour":"2:30","inProgress":7,"inQueue":0},{"hour":"2:45","inProgress":7,"inQueue":0},{"hour":"3:00","inProgress":8,"inQueue":0},{"hour":"3:15","inProgress":8,"inQueue":0},{"hour":"3:30","inProgress":9,"inQueue":1},{"hour":"3:45","inProgress":9,"inQueue":4},{"hour":"4:00","inProgress":10,"inQueue":6},{"hour":"4:15","inProgress":10,"inQueue":2},{"hour":"4:30","inProgress":10,"inQueue":1},{"hour":"4:45","inProgress":11,"inQueue":0},{"hour":"5:00","inProgress":11,"inQueue":0},{"hour":"5:15","inProgress":12,"inQueue":0},{"hour":"5:30","inProgress":12,"inQueue":0},{"hour":"5:45","inProgress":13,"inQueue":0},{"hour":"6:00","inProgress":13,"inQueue":0},{"hour":"6:15","inProgress":14,"inQueue":0},{"hour":"6:30","inProgress":14,"inQueue":0},{"hour":"6:45","inProgress":15,"inQueue":0},{"hour":"7:00","inProgress":15,"inQueue":3},{"hour":"7:15","inProgress":15,"inQueue":1},{"hour":"7:30","inProgress":16,"inQueue":0},{"hour":"7:45","inProgress":16,"inQueue":0},{"hour":"8:00","inProgress":17,"inQueue":2},{"hour":"8:15","inProgress":17,"inQueue":3},{"hour":"8:30","inProgress":18,"inQueue":1},{"hour":"8:45","inProgress":18,"inQueue":0},{"hour":"9:00","inProgress":19,"inQueue":0},{"hour":"9:15","inProgress":19,"inQueue":0},{"hour":"9:30","inProgress":20,"inQueue":0},{"hour":"9:45","inProgress":20,"inQueue":0},{"hour":"10:00","inProgress":20,"inQueue":0},{"hour":"10:15","inProgress":21,"inQueue":1},{"hour":"10:30","inProgress":21,"inQueue":4},{"hour":"10:45","inProgress":22,"inQueue":6},{"hour":"11:00","inProgress":22,"inQueue":2},{"hour":"11:15","inProgress":23,"inQueue":1},{"hour":"11:30","inProgress":23,"inQueue":0},{"hour":"11:45","inProgress":3,"inQueue":0},{"hour":"12:00","inProgress":5,"inQueue":0},{"hour":"12:15","inProgress":1,"inQueue":0},{"hour":"12:30","inProgress":1,"inQueue":0},{"hour":"12:45","inProgress":2,"inQueue":0},{"hour":"13:00","inProgress":8,"inQueue":0},{"hour":"13:15","inProgress":5,"inQueue":0},{"hour":"13:30","inProgress":5,"inQueue":0},{"hour":"13:45","inProgress":6,"inQueue":3},{"hour":"14:00","inProgress":6,"inQueue":1},{"hour":"14:15","inProgress":7,"inQueue":0},{"hour":"14:30","inProgress":7,"inQueue":0},{"hour":"14:45","inProgress":8,"inQueue":2},{"hour":"15:00","inProgress":8,"inQueue":3},{"hour":"15:15","inProgress":9,"inQueue":1},{"hour":"15:30","inProgress":9,"inQueue":0},{"hour":"15:45","inProgress":10,"inQueue":0},{"hour":"16:00","inProgress":10,"inQueue":0},{"hour":"16:15","inProgress":10,"inQueue":0},{"hour":"16:30","inProgress":11,"inQueue":0},{"hour":"16:45","inProgress":11,"inQueue":0},{"hour":"17:00","inProgress":12,"inQueue":1},{"hour":"17:15","inProgress":12,"inQueue":4},{"hour":"17:30","inProgress":13,"inQueue":6},{"hour":"17:45","inProgress":13,"inQueue":2},{"hour":"18:00","inProgress":14,"inQueue":1},{"hour":"18:15","inProgress":14,"inQueue":0},{"hour":"18:30","inProgress":15,"inQueue":0},{"hour":"18:45","inProgress":15,"inQueue":0},{"hour":"19:00","inProgress":15,"inQueue":0},{"hour":"19:15","inProgress":16,"inQueue":0},{"hour":"19:30","inProgress":16,"inQueue":0},{"hour":"19:45","inProgress":17,"inQueue":0},{"hour":"20:00","inProgress":17,"inQueue":0},{"hour":"20:15","inProgress":18,"inQueue":0},{"hour":"20:30","inProgress":18,"inQueue":3},{"hour":"20:45","inProgress":19,"inQueue":1},{"hour":"21:00","inProgress":19,"inQueue":0},{"hour":"21:15","inProgress":20,"inQueue":0},{"hour":"21:30","inProgress":20,"inQueue":2},{"hour":"21:45","inProgress":20,"inQueue":3},{"hour":"22:00","inProgress":21,"inQueue":1},{"hour":"22:15","inProgress":21,"inQueue":0},{"hour":"22:30","inProgress":22,"inQueue":0},{"hour":"22:45","inProgress":22,"inQueue":0},{"hour":"23:00","inProgress":23,"inQueue":0},{"hour":"23:15","inProgress":23,"inQueue":0},{"hour":"23:30","inProgress":1,"inQueue":0},{"hour":"23:45","inProgress":2,"inQueue":1}];

var margin = {top: 20, right: 50, bottom: 30, left: 20},
    width = 500,
    height = 300;

// Transpose the data into layers
var dataset = d3.layout.stack()(['inProgress', 'inQueue'].map(function(types) {
  return data.map(function(d) {
    return {
      x: d.hour,
      y: +d[types],
      type: types
    };
  });
}));

var svg = d3.select('svg'),
    margin = {top: 40, right: 10, bottom: 20, left: 10},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom,
    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

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

var yScale = 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 = ['#56a8f8', '#c34434'];

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

var xAxis = d3.svg.axis()
  .scale(xScale)
  .orient('bottom')
  .tickSize(0)
  .ticks(12) // this 
  .tickFormat(function(d) {
    return d; // and this will not work with an ordinal scale
  });
    
  
xAxis.tickValues(["0:00", "2:00", "4:00", "6:00", "8:00", "10:00", "12:00", "14:00", "16:00", "18:00", "20:00", "22:00"]);

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.bar-stacks')
  .data(dataset)
  .enter().append('g')
  .attr('class', function(d, i) {
    return 'bar-stacks ' + d[i].type;
  })
  .classed('bar-stacks', true)
  .style('fill', function(d, i) {
    return colors[i];
  });

var rect = groups.selectAll('rect')
  .data(function(d) {
    return d;
  })
  .enter()
  .append('rect')
  .attr('class', function(d, i) {
    return 'stacks ' + d.type;
  })
  .classed('stacks', true)
  .attr('id', function(d, i) {
    return d.type + '_' + i;
  })
  .attr('x', function(d) {
    return xScale(d.x);
  })
  .attr('y', function(d) {
    return yScale(d.y0 + d.y);
  })
  .attr('height', function(d) {
    return yScale(d.y0) - yScale(d.y0 + d.y);
  })
  .attr('width', xScale.rangeBand());
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div>
<svg width="600" height="300"></svg>
</div>