Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force a specific amount of y axis ticks in d3 charts?

I have a d3 (version 3.5) multi-line chart, and I'm trying to have 5 ticks on the y-axis.

This is the code for the y-axis generation, with the number of ticks:

enter image description here

The problem is that any ticks value I put, between 3 to 6, gives the same following result (which has fewer ticks than what I want):

enter image description here

And when I put a value of 7 ticks, it gives the following result (which is too many ticks than what I want):

enter image description here

How do I force the chart to have an exact number of ticks on the y-axis?

Thanks.

like image 816
Guy Avatar asked Jul 24 '18 11:07

Guy


People also ask

How does d3 ticks work?

The ticks function can take any number but it will modify that number to make sure the axis is a multiple of 2, 5, or 10. For example, if the domain is 0-100 and you want 4 ticks (0, 33.33, 66.66, 100) it will round up to 6 to give you "pretty" numbers (0, 20, 40, 60, 80, 100).

What are ticks d3?

ticks passes the arguments you specify to scale. ticks whenever the axis is rendered. The meaning of the arguments thus depends on the class of scale. For linear and power scales, pass axis. ticks the desired tick count.


2 Answers

According to the documentation (bolding mine):

A stateless method that returns approximately count representative values from the scale's input domain. If count is not specified, it defaults to 10. The returned tick values are uniformly spaced, have human-readable values (such as multiples of powers of 10), and are guaranteed to be within the extent of the input domain. Ticks are often used to display reference lines, or tick marks, in conjunction with the visualized data. The specified count is only a hint; the scale may return more or fewer values depending on the input domain.

The reason d3 won't honor your tick count is because you'd end up with unevenly spaced ticks or non-nice, non-human readable values.

If you really want 5 ticks, you'll need to specify them yourself using the tickValues method. One way I've done this in the past is to use the d3 range method. Say my input domain is from 20 to 170 as it looks in your first graph, then:

var step = 5,
    min = 20,
    max = 170,
    stepValue = (max - min) / (step - 1),
    tickValues = d3.range(min, max + stepValue, stepValue);
    
console.log(tickValues);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.13/d3.min.js"></script>
like image 121
Mark Avatar answered Oct 23 '22 12:10

Mark


This is the full solution, thanks to @Mark.

In order to have human readable values in the y-axis, I rounded the tick step to the closest 5.

// y axis
    const ticksAmount = 5;
    const tickStep = (maxValue - minValue) / (ticksAmount);
    const step = Math.ceil(tickStep / 5) * 5;
    const yAxis = d3.svg.axis()
        .scale(yScale)
        .orient('left')
        .ticks(ticksAmount)
        .tickValues(d3.range(minValue, maxValue + step, step))
        .tickFormat(d3.format('d'))
        .innerTickSize(-width)
        .outerTickSize(0)
        .tickPadding(5);

And the result:

enter image description here

like image 43
Guy Avatar answered Oct 23 '22 12:10

Guy