score:1

I'm gonna answer just the question in the title ("how is the number of ticks on an axis defined?"), not the one you made at the end ("What If I want to space the ticks more evenly, for example, I want to see a tick on every 12 or 6 hours?"), which is not related and quite simple to fix (and, besides that, it's certainly a duplicate).

Your question demands a detective work. Our journey starts, of course, at `d3.axisBottom()`. If you look at the source code, you'll see that the number of ticks in the enter selection...

``````tick = selection.selectAll(".tick").data(values, scale).order()
``````

...depends on `values`, which is:

``````var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues
``````

What this line tells us is that, if `tickValues` is null (no `tickValues` used), the code should use `scale.ticks` for scales that have a `ticks` method (continuous), our just the scale's domain for ordinal scales.

That leads us to the continuous scales. There, using a linear scale (which is the one you're using), we can see at the source code that `scale.ticks` returns this:

``````scale.ticks = function(count) {
var d = domain();
return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
};
``````

However, since `ticks` is imported from d3.array, we have to go there for seeing how the ticks are calculated. Also, since we didn't pass anything as `count`, `count` defaults to `10`.

So, finally, we arrive at this:

``````start = Math.ceil(start / step);
stop = Math.floor(stop / step);
ticks = new Array(n = Math.ceil(stop - start + 1));
while (++i < n) ticks[i] = (start + i) * step;
``````

Or this:

``````start = Math.floor(start * step);
stop = Math.ceil(stop * step);
ticks = new Array(n = Math.ceil(start - stop + 1));
while (++i < n) ticks[i] = (start - i) / step;
``````

Depending on the value of `steps`. If you look at the `tickIncrement` function below, you can see that `steps` can only be `1`, `2`, `5` or `10` (and their negatives).

And that's all you need to know the length of the array in the variable `ticks` above. Depending on the start and stop values (i.e., depending on the domain), sometimes we have more than 10 ticks (16 in your case), sometimes we have less than 10, even if the default count is 10. Have a look here:

``````const s = d3.scaleLinear();

console.log(s.domain([1,12]).ticks().length);
console.log(s.domain([100,240]).ticks().length);
console.log(s.domain([10,10]).ticks().length);
console.log(s.domain([2,10]).ticks().length);
console.log(s.domain([1,4]).ticks().length);``````
``<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>``

The last example, as you can see, gives us 16 ticks.