D3 Tips and Tricks v4

Sunday, 28 August 2016

Changing the number of ticks on an axis in d3.js v4

The following post is a section of the book 'D3 Tips and Tricks v4.x'.  The entire book can be downloaded in pdf format for free from Leanpub or you can read it online here.
Since this post is a snapshot in time. I recommend that you download a copy of the book which is updated frequently to improve and expand the content.
---------------------------------------
As referenced in the post where we initially developed our simple graph, the axes of that graph had no styling or configuration changes made to them at all. One of the results of this is that the font size, type, number of ticks and the way that the values are represented is very much at the default settings.

Changing the number of ticks on an axis

Now we shall address the other problem that cropped up when we changed the size of the text. We have overlapping values on the x axis.
Overlapping axis values
If I was to be brutally honest, I think that the number of values (ticks) on the graph is a bit too many. The format of the values (especially on the x axis) is too wide and this type of overlap was bound to happen eventually.
Good news. D3 has got us covered.
The axis component includes a function to specify the number of ticks on an axis. All we need to do is add in the function and the number of ticks like so;
  // Add the X Axis
  svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x)
              .ticks(5));
With the end result looking like this;
Nicely spaced axis values
We can see that D3 has picked tick values that seem nice and logical. There’s one that starts on the 1st of April that’s just labelled ‘April’ and they go at a nice interval of one week for the subsequent ticks. Nice.
Hopefully you just did a quick count across the bottom of the previous graph and went “Yep, five ticks. Spot on”. Well done if you did, but there’s a little bit of a sneaky trick up D3’s sleeve with the number of ticks on a graph axis.
For instance, here’s what the graph looks like when the .ticks(5) value is changed to .ticks(4).
Five ticks on the x axis
Eh? Hang on. Isn’t that some kind of mistake? There are still five ticks. Yep, sure is! But wait… we can keep dropping the ticks value till we get to two and it will still be the same. At .ticks(2) though, we finally see a change.
Two ticks on the x axis
How about that? At first glance that just doesn’t seem right, then you have a bit of a think about it and you go “Hmm… When there were 5 ticks, they were separated by a week each, and that stayed that way till we got to a point where it could show a separation of a month”.
D3 is making a command decision for you as to how your ticks should be best displayed. This is great for simple graphs and indeed for the vast majority of graphs. Like all things related to D3, if you really need to do something bespoke, it will let you if you understand enough code.
The following is the list of time intervals that D3 will consider when setting automatic ticks on a time based axis;
  • 1, 5, 15 and 30-second.
  • 1, 5, 15 and 30-minute.
  • 1, 3, 6 and 12-hour.
  • 1 and 2-day.
  • 1-week.
  • 1 and 3-month.
  • 1-year.
And yes. If you increase the number of ticks, you need to wait till you get to 10 before they change to an axis with interval of two days. And yes, the overlap is still there;
Still overlapping axis values
If we do a quick count we should also notice that we have 19 ticks!
The question should be asked. Can we specify our own intervals? Great question! Yes we can.
What we need to do is to use another D3 trick and specify an exact interval using the d3 time component. In our particular situation all we need to do is specify an interval inside the .ticks function. Specifically for an interval of 4 days for example we would use something like;
  // Add the X Axis
  svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x)
              .ticks(d3.timeDay.every(4)));
Here we use the timeDay unit of ‘days’ and specify an interval of 4 days.
The graph will subsequently appear as follows;
Axis ticks at 4 day intervals
Intervals have a number of standard units (including UTC time) such as;
  • d3.timeMillisecond : Milliseconds
  • d3.timeSecond : Seconds
  • d3.timeMinute : Minutes
  • d3.timeHour : Hours
  • d3.timeDay : Days
  • d3.timeWeek : This is an alias for d3.timeSunday for a week
  • d3.timeSunday : A week starting on Sunday
  • d3.timeMonday : A week starting on Monday
  • d3.timeTuesday : A week starting on Tuesday
  • d3.timeWednesday : A week starting on Wednesday
  • d3.timeThursday : A week starting on Thursday
  • d3.timeFriday : A week starting on Friday
  • d3.timeSaturday : A week starting on Saturday
  • d3.timeMonth : Months starting on the 1st of the month
  • d3.timeYear : Years Starting on the 1st day of the year
But what if we really wanted that two day separation of ticks without the overlap? Check it out in the next post...

The post above (and heaps of other stuff) is in the book 'D3 Tips and Tricks v4.x' that can be downloaded for free (or donate to encourage further development :-)).

No comments:

Post a Comment