Q:

How to make ordinal tick labels adjust automatically in D3

As you can see in the example, the tick labels on an ordinal axis (scale) become crowded and illegible as the domain grows. How can I make them adjust automatically as they would on a linear axis? 
(I suppose I could use a linear scale instead, but this question and the answer from Mike Bostock himself suggest that the ordinal scale is more appropriate for this type of data. After all, the domain is discrete and I'm making a modified bar chart, where a convenient padding setting is useful.)

var x0 = d3.scaleBand()
  .domain(d3.range(1,6))
  .range([0,200]);

var x = d3.scaleBand()
  .domain(d3.range(1,51))
  .range([0,200]);

var xLinear = d3.scaleLinear()
  .domain([1,50])
  .range([0,200]);

d3.select('svg').append('g')
  .attr('transform', 'translate(10,10)')
  .call(d3.axisBottom(x0));

d3.select('svg').append('g')
  .attr('transform', 'translate(10,50)')
  .call(d3.axisBottom(x));

d3.select('svg').append('g')
  .attr('transform', 'translate(10,100)')
  .call(d3.axisBottom(xLinear));
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width='300' height='150'></svg>

A:

This solution takes advantage of the very smart built-in function d3.ticks(), which deals with edge cases so we don't have to.

var dataSmall = d3.range(1,8),
    dataLarge = d3.range(1, 51);

var xS = d3.scaleBand()
  .domain(dataSmall)
  .rangeRound([0,200]);

var xL = d3.scaleBand()
  .domain(dataLarge)
  .rangeRound([0,200]);

function makeAxis(scale) {
  var n=5, 
      data = scale.domain(),
      dataLength = data.length;
  
  return d3.axisBottom(scale).tickValues( 
    dataLength > n ? d3.ticks(data[0], data[dataLength-1], n) : data);
}

d3.select('svg').append('g')
  .attr('transform', 'translate(10,10)')
  .call(makeAxis(xS));

d3.select('svg').append('g')
  .attr('transform', 'translate(10,50)')
  .call(makeAxis(xL));
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width='300' height='150'></svg>

