3

I am currently working with NVD3 using Angular Directive (angular-nvd3). I have a very simple line chart with very simple data.

The problem I have encountered now is that my data is wrongly aligned with the Axis. Example plunker available here: http://plnkr.co/edit/jWEYt6?p=preview ,

I am using dates on my xAxis, which are parsed using d3 library:

tickFormat: function(d) {return d3.time.format('%d/%m')(new Date(d))}

Description:

I would expect the xAxis labels to be correspondent to the grid.

In the example you can clearly notice that the xAxis is not evenly devided (values: 06/11, 08/11, 11/11, 13/11). So usually 2 days and sometimes 3 days :)

What is worse - the peaks are not matching the grid. Example: 06/11 tick is really not even close to the grid's line where I guess it is supposed to be.

I have also tried this on master's code from repo and it happens there too. There is a link in the HTML head section.

Is there a problem with my data, proper date formatting or something else? Thanks!

Atais
  • 10,857
  • 6
  • 71
  • 111

2 Answers2

6

This bugged me for a while and I could not find an answer here. I even have opened a bug on GitHub: https://github.com/novus/nvd3/issues/1382#issuecomment-160694559 and I was clued in on the answer.


The problem:

The actual issue is hidden because of d3.time.format('%d/%m'). My example data is given in one tick per day manner, and the format was set accordingly. But d3 does not understand that. When drawing the grid it divides the max-min/someValue and the grid ticks does not have to occur on full day (midnight), but on any hour. And because of the formatting I could not see that.

The version showing this misconception is here: http://plnkr.co/edit/2iMHOp?p=preview


Solution:

So now, when I know what I could do, I managed to substitute the ticks by using tickValues parameter in nvd3 / angular wrapper. The version with the solution is here: http://plnkr.co/edit/23n3ll?p=preview


Yet another bug :)

Funny thing is that since the labels are too long to be displayed, I had to rotate them so they could fit. Another bug occurs here (I think). As you can see 2nd and last but one tick label is missing. First I tried using the solution mentioned here: NVD3 Line Chart X Axis Ticks Are Missing using the showMaxMin parameter but it does not work correctly. But if you rotate the labels to ~ -70 degrees the labels are displayed OK.

I guess this is not the end with my NVD3 journey ;)

Community
  • 1
  • 1
Atais
  • 10,857
  • 6
  • 71
  • 111
  • You saved my day with this solution. Now, I have another problem. I was updated your [plnkr](http://plnkr.co/edit/42uzlu4AjnHJpI7o41l3?p=preview) to show you. I removed to tick (In my case I just have no data for those days. Now, there is space between the ticks. How can I avoid it? – Mosh Feu Mar 15 '16 at 13:02
  • I recommend you to prepare your data on the back-end by adding missing days with 0 value. That's what I have done :) – Atais Mar 15 '16 at 13:09
  • That's was my first thought but it's ugly :( It's just make sense that should be a property to avoid it. I will ask a new question for it, if I will get an answer I will post it here.. Thanks anyway.. – Mosh Feu Mar 15 '16 at 13:12
3

Since the problem is, according to Atais:

The actual issue is hidden because of d3.time.format('%d/%m'). My example data is given in one tick per day manner, and the format was set accordingly. But d3 does not understand that. When drawing the grid it divides the max-min/someValue and the grid ticks does not have to occur on full day (midnight), but on any hour. And because of the formatting I could not see that.

I managed to pass the x's values as integer values (ex: 20160211) instead of formatted dates (ex: 2016-02-11 or similars) to nvd3, and then on tickFormatformat them to display properly.

I wrote another plunker with the problem and the commented solution (used momentjs):


Plunker with the simulated error: http://plnkr.co/edit/fXDQ0f?p=preview

Data is provided in format x: milliseconds, y: int, like {x: 1446418800000, y: 20}, and it is being formated with tickFormat:

  xAxis: {
    tickFormat: function(d) {
      return moment(d).format('YYYY-MM-DD');
    }
  }

Plunker with the solution: http://plnkr.co/edit/KpALzo?p=preview

Data is provided in format x: int, y: int, like {x: 20160211, y: 20}, and it is being formated with tickFormat:

  xAxis: {
    tickFormat: function(d) {
      moment(d, 'YYYYMMDD').format('YYYY-MM-DD');
    }
  }

Note that you can do it with time too, just by appending to the 'numeric date'.

As stated from @ajaybc, will not work well with dates from different months, since d3 will interpolate X axis with invalid filling dates (days 32, 33, 34 and so on)

Stef B.
  • 51
  • 6
  • wow its awesome! well this walk-around definitely requires some attention from my side! – Atais Feb 11 '16 at 16:02
  • Whilst this may theoretically answer the question, [it would be preferable](//meta.stackoverflow.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Tobi Nary Feb 11 '16 at 16:06
  • Understood guys, my first time answering here :p Approved your edit @Atais – Stef B. Feb 11 '16 at 17:05
  • @StefEB it is great trick, but works only up to day precision :( so I can use it only in couple of the cases I have. thanks anyway! – Atais Feb 12 '16 at 13:00
  • 2
    @StefB. this wont work when the dates are from different months. D3 will try to interpolate the X values between the values we supply. Leading to it creating invalid date values like '20160241'. I have modified your example fiddle to demonstrate that http://plnkr.co/edit/RPVhc1KYmnuZs2FTqCoO?p=preview – ajaybc Mar 10 '17 at 04:34
  • 1
    @ajaybc Yes, that's true. Already added a caveat note to the answer. Thanks for the insight. – Stef B. Mar 18 '17 at 23:09