nvd3.js d3.time.scale on x axis

5,071 views
Skip to first unread message

random3...@googlemail.com

unread,
Jan 23, 2013, 7:37:27 AM1/23/13
to d3...@googlegroups.com
I really want to be able to set the x axis of a nvd3.js multiBarChart to use d3.time.scale but I don't know how, I asked on SO (http://stackoverflow.com/questions/14461107/how-to-set-the-domain-and-scale-on-an-axis-on-a-nvd3-js-multibarchart) but no replies yet.

The example on SO only has a single set of bars, this image (http://dl.dropbox.com/u/45079992/Screenshots/uyf8c9p6hih5.png) shows what happens with multiple bars (the years on the x axis go ...11, 12, 13, 01, 04), both datasets are in chronological order however they don't necessarily contain the same years.

I could write functions to find the earliest year from all the series and then pad the datasets with the missing data but it would be ugly, I'm reasonably sure this is possible, if it's definitely not possible I'll create a feature request as this has to be a common scenario.
If someone can guide me I can have a look at making a patch myself if necessary (I'm cerberos in the d3.js irc channel).

Many thanks

 



uyf8c9p6hih5.png
Message has been deleted

pax roman

unread,
Jan 24, 2013, 7:05:09 AM1/24/13
to d3...@googlegroups.com
See GitHub :)

random3...@googlemail.com

unread,
Jan 24, 2013, 7:28:10 AM1/24/13
to d3...@googlegroups.com
Is there something specific I should see on Github?


As far as I can tell something like this should work (but doesn't)

    nv.addGraph(function() {
        var chart = nv.models.multiBarChart();
   
        x = d3.time.scale()
            .domain([min_date, max_date]); // javascript Date() objects

        chart.xAxis
            .scale(x)
            .axisLabel('Year')
            .tickFormat(function(d) { return d3.time.format('%y')(d); });
        ...

Or even something like this

            nv.addGraph(function() {
                var chart = nv.models.multiBarChart();

                var xAxis = nv.models.axis()
                xAxis
                    .axisLabel('Year')
                    .tickFormat(function(d) { console.log(d); return d3.time.format('%y')(d); })
                    .scale(
                        d3.time.scale().
                            domain([min_year, max_year])
                    );

                chart.xAxis = xAxis
                ...



On Thursday, January 24, 2013 12:05:09 PM UTC, pax roman wrote:
See GitHub :)

pax roman

unread,
Jan 24, 2013, 8:45:51 AM1/24/13
to d3...@googlegroups.com
I explained how I did it for the line charts... and what to modify for it to work on the multiBarChart...
Might have not been visible an hour ago...but it should be visible now

random3...@googlemail.com

unread,
Jan 24, 2013, 8:57:11 AM1/24/13
to d3...@googlegroups.com
I'm looking at google groups, I can see there's a deleted message above your message that says 'see github'. Where should I look on github?

Thanks

pax roman

unread,
Jan 24, 2013, 9:37:17 AM1/24/13
to d3...@googlegroups.com

You can do this in 2 ways:

A) You either rewrite the axis component of nvd3 to use d3.time.scale() / make another axis component for this use case...

Or the easiest way:

B) You use the custom values for the axis. First of all you use the + operator ( +(date) ) to have the values in ms. There is a tickValues function in d3 that allows you to pass custom values for the ticks.. To force the X scale you have the forceX() method from the scatter (I assume you already know about this) and you write a simple function that takes custom values for ticks.... So if you force your scale to have values between Jan 1 2002 and Dec 31 2012 and then decide to have 4 ticks you can use either ticks directly or tickValues...

So it goes like this (add something similar to the multiBarChart.js file):


  lines.forceX(minValue, maxValue) //where minValue and maxValue are the values
  //converted to ms already after you did +(date)

  //then you just rewrite the ticks - if you want a custom number of ticks you can do it like this

  //numberOfTicks is a method I added to the axis component (axis.js) to give the number of ticks the user would like to have

  //x.domain() now contains the forced values instead of the values you initially used..
  var maxTicks = xAxis.numberOfTicks()-1, xMin = x.domain()[0], xMax = x.domain()[1], 
      xDiff = (xMax - xMin)/maxTicks, tickInterval = [];

  tickInterval[0] = xMin;

  for(i=1; i<maxTicks; i++){
    var current = xMin + i*xDiff;
    tickInterval[i] = current;
  }

  tickInterval[maxTicks] = xMax;

  //tickInterval already contains the values you want to pass to the tickValues function
  xAxis.tickValues(tickInterval);

Hope this helps... I know it's hack but it worked in my case :) And of course if you already formatted the date to be displayed as year you will get the values for the years when displaying the ticks :)

This is how I did it for lines. For multiBarChart you will need to add an extra step: you need to deal with the reduceTicks functionality (set it to false, delete that part of the code, do whatever you like with it...) 

pax roman

unread,
Jan 24, 2013, 9:42:40 AM1/24/13
to d3...@googlegroups.com
that was it.... I hope it's clear...
Sorry for the deleted post problem... I wanted to delete it initially because I realized it wasn't what you needed,
then rewrote the answer and marked undelete....apparently stackoverflow undelete does not work...

Reply all
Reply to author
Forward
0 new messages