d3.time.scale compatibility #145

Closed
ninjudd opened this Issue May 30, 2013 · 34 comments

Comments

Projects
None yet
@ninjudd

ninjudd commented May 30, 2013

It seems to me that d3.time.scale cannot be used with nvd3.

For example, this seems like it should work to me, but it doesn't:

chart.xAxis.scale(d3.time.scale());

It seems to ignore the tickFormat (add possibly the tickValues) completely.

The reason I want to use d3.time.scale is because it seems to have good handling of automatic time ticks (https://github.com/mbostock/d3/wiki/Time-Scales#wiki-ticks). Specifically, it looks like it automatically aligns tick marks to human friendly intervals:

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.

Is there any way to get nvd3 working with d3 time scales? Is there something I'm missing? I'm happy to help out if someone can point me in the right direction.

@twolfnovus

This comment has been minimized.

Show comment
Hide comment
@twolfnovus

twolfnovus May 30, 2013

Contributor

This should be possible or at least easy to implement with the d3.v3 upgrade, which will be complete very soon.

Contributor

twolfnovus commented May 30, 2013

This should be possible or at least easy to implement with the d3.v3 upgrade, which will be complete very soon.

@ninjudd

This comment has been minimized.

Show comment
Hide comment
@ninjudd

ninjudd May 30, 2013

Great!

I've jumped into hacking something together for my own needs by calling ticks and tickFormat on d3.time.scale() directly and passing the values to axis.tickValues and axis.tickFormat directly (after converting to and from Date objects).

One issue I've run into is that the d3 tick format function doesn't like being passed values that aren't in the list of tick marks returned by ticks. But nvd3 uses tickFormat when you hover over points and for the min/max labels.

I can hack it though by using an alternate time format if the value is not in the list of ticks...

Anyway, looking forward to the d3.v3 upgrade!

ninjudd commented May 30, 2013

Great!

I've jumped into hacking something together for my own needs by calling ticks and tickFormat on d3.time.scale() directly and passing the values to axis.tickValues and axis.tickFormat directly (after converting to and from Date objects).

One issue I've run into is that the d3 tick format function doesn't like being passed values that aren't in the list of tick marks returned by ticks. But nvd3 uses tickFormat when you hover over points and for the min/max labels.

I can hack it though by using an alternate time format if the value is not in the list of ticks...

Anyway, looking forward to the d3.v3 upgrade!

@Avnerus

This comment has been minimized.

Show comment
Hide comment
@Avnerus

Avnerus Jun 18, 2013

Hi,
Now that the d3.v3 upgrade seems to be complete, is it possible to use d3.time.scale? Are there any code samples I can use?
Thanks!

Avnerus commented Jun 18, 2013

Hi,
Now that the d3.v3 upgrade seems to be complete, is it possible to use d3.time.scale? Are there any code samples I can use?
Thanks!

@tslater

This comment has been minimized.

Show comment
Hide comment
@tslater

tslater Aug 1, 2013

Any progress on this issue? I'm interesed as well. The lack of documentation is hard.

tslater commented Aug 1, 2013

Any progress on this issue? I'm interesed as well. The lack of documentation is hard.

@dlamotte

This comment has been minimized.

Show comment
Hide comment
@dlamotte

dlamotte Aug 16, 2013

Think I'm having this issue as well.

chart.xAxis.ticks(d3.time.monday)

Doesn't seem to do anything (not even sure I'm doing it right). I just want to force major ticks to happen on Mondays (or ever other Monday... but whatever is easier).

Think I'm having this issue as well.

chart.xAxis.ticks(d3.time.monday)

Doesn't seem to do anything (not even sure I'm doing it right). I just want to force major ticks to happen on Mondays (or ever other Monday... but whatever is easier).

@tklun

This comment has been minimized.

Show comment
Hide comment
@tklun

tklun Aug 23, 2013

FWIW, I've been able to get the d3.time.scale() working on the line charts. The points in the line charts are actually created with the scatter.js module. The scatter module exposes an xScale that you can use to apply a the d3.time.scale().

chart.lines.scatter.xScale(d3.time.scale());

In the graph I've built, the x values of my line chart were based on dates. When using the default d3.scale.linear() the points on the line chart were not matching up with the lines on the xAxis. Switching to d3.time.scale() fixed it right up.

tklun commented Aug 23, 2013

FWIW, I've been able to get the d3.time.scale() working on the line charts. The points in the line charts are actually created with the scatter.js module. The scatter module exposes an xScale that you can use to apply a the d3.time.scale().

chart.lines.scatter.xScale(d3.time.scale());

In the graph I've built, the x values of my line chart were based on dates. When using the default d3.scale.linear() the points on the line chart were not matching up with the lines on the xAxis. Switching to d3.time.scale() fixed it right up.

@nathansamson

This comment has been minimized.

Show comment
Hide comment
@nathansamson

nathansamson Aug 23, 2013

@tklun I've tried that too on the lineWithFocusChart but there the same trick doesn't work (even not after doing the same on chart.lines2)

It seems to be odd that support for this (time chart on the lineWithFocusChart) since you would expect that a timeseries would be the primary use case for this type of graph.

@tklun I've tried that too on the lineWithFocusChart but there the same trick doesn't work (even not after doing the same on chart.lines2)

It seems to be odd that support for this (time chart on the lineWithFocusChart) since you would expect that a timeseries would be the primary use case for this type of graph.

@Marsup

This comment has been minimized.

Show comment
Hide comment
@Marsup

Marsup Aug 28, 2013

Contributor

I'd also love a human-readable axis with such a scale, no matter the tricks I can't get a correct one.
The linechart is currently overriding the ticks number and there's no way around it.

Contributor

Marsup commented Aug 28, 2013

I'd also love a human-readable axis with such a scale, no matter the tricks I can't get a correct one.
The linechart is currently overriding the ticks number and there's no way around it.

@mb-dev

This comment has been minimized.

Show comment
Hide comment
@mb-dev

mb-dev Nov 8, 2013

any news on this?

mb-dev commented Nov 8, 2013

any news on this?

@mfenner0422

This comment has been minimized.

Show comment
Hide comment
@mfenner0422

mfenner0422 Jan 20, 2014

still waiting on a fix for this

still waiting on a fix for this

@nickretallack

This comment has been minimized.

Show comment
Hide comment
@nickretallack

nickretallack Jan 21, 2014

I gave up on this being fixed and switched to Rickshaw.

I gave up on this being fixed and switched to Rickshaw.

@kmjennison

This comment has been minimized.

Show comment
Hide comment
@kmjennison

kmjennison Jan 23, 2014

Also an issue for me. Any news?

Also an issue for me. Any news?

@twolfnovus

This comment has been minimized.

Show comment
Hide comment
@twolfnovus

twolfnovus Jan 23, 2014

Contributor

My apologies for not replying to this for a long time! We expected this to work with the d3.v3 upgrade, but overlooked a few details in how the line chart is implemented. Your best bet with this is to use the solution presented by @tklun above.

I'll investigate an alternative for the lineWithFocusChart and post what I come up with.

We'd like to fix issues like this quickly, but when it comes down to it, these issues arise because the nvd3 architecture isn't as modular as these types of fixes require. We're shifting our focus from addressing specific issues like this to rethinking the project architecture, allowing for deeper, more intuitive customization by the user.

Contributor

twolfnovus commented Jan 23, 2014

My apologies for not replying to this for a long time! We expected this to work with the d3.v3 upgrade, but overlooked a few details in how the line chart is implemented. Your best bet with this is to use the solution presented by @tklun above.

I'll investigate an alternative for the lineWithFocusChart and post what I come up with.

We'd like to fix issues like this quickly, but when it comes down to it, these issues arise because the nvd3 architecture isn't as modular as these types of fixes require. We're shifting our focus from addressing specific issues like this to rethinking the project architecture, allowing for deeper, more intuitive customization by the user.

@kmjennison

This comment has been minimized.

Show comment
Hide comment
@kmjennison

kmjennison Jan 23, 2014

Thanks for the update!

Thanks for the update!

@jufemaiz

This comment has been minimized.

Show comment
Hide comment
@jufemaiz

jufemaiz Mar 27, 2014

Just wanted to bump this to see where things are at with the rethink.

Cheers!

Just wanted to bump this to see where things are at with the rethink.

Cheers!

@tomtomau

This comment has been minimized.

Show comment
Hide comment
@tomtomau

tomtomau Apr 21, 2014

I managed to get linechart working pretty simply with @tklun's workaround (essentially). You can additionally use:

chart.xScale(d3.time.scale());

This works because xScale is revealed in linechart.

But when working with linewithfocuschart, this won't work - but this does:

chart.lines.xScale(d3.time.scale());
// And then
chart.lines2.xScale(d3.time.scale());

I'm pretty new to this intense style of JS, but as far as I can tell, it's because lines/lines2 (which are instances of nv.models.line) reveal an xScale (which is actually the scale given to the scatter object).

From the looks of it, this works nicely, you'll also want to format the tick, etc. Hope this helps someone.

I managed to get linechart working pretty simply with @tklun's workaround (essentially). You can additionally use:

chart.xScale(d3.time.scale());

This works because xScale is revealed in linechart.

But when working with linewithfocuschart, this won't work - but this does:

chart.lines.xScale(d3.time.scale());
// And then
chart.lines2.xScale(d3.time.scale());

I'm pretty new to this intense style of JS, but as far as I can tell, it's because lines/lines2 (which are instances of nv.models.line) reveal an xScale (which is actually the scale given to the scatter object).

From the looks of it, this works nicely, you'll also want to format the tick, etc. Hope this helps someone.

@ayezutov

This comment has been minimized.

Show comment
Hide comment
@ayezutov

ayezutov Aug 21, 2014

Based on all above comments and the source code for axis I compiled the following function, which lets me format the time scale for a line chart:

function setTimeScale(nvd3Axis, nvd3Scale, argsArray)  {
var scale = d3.time.scale();

nvd3Axis.scale(scale);
nvd3Scale(scale);

if (!!argsArray && !!argsArray.length) {
    var oldTicks = nvd3Axis.axis.ticks;

    nvd3Axis.axis.ticks = function()
        {
            return oldTicks.apply(nvd3Axis.axis, argsArray);
        }
    }
}

And the usage is:

   setTimeScale(chart.xAxis, chart.xScale, [d3.time.day, 2]);

Based on all above comments and the source code for axis I compiled the following function, which lets me format the time scale for a line chart:

function setTimeScale(nvd3Axis, nvd3Scale, argsArray)  {
var scale = d3.time.scale();

nvd3Axis.scale(scale);
nvd3Scale(scale);

if (!!argsArray && !!argsArray.length) {
    var oldTicks = nvd3Axis.axis.ticks;

    nvd3Axis.axis.ticks = function()
        {
            return oldTicks.apply(nvd3Axis.axis, argsArray);
        }
    }
}

And the usage is:

   setTimeScale(chart.xAxis, chart.xScale, [d3.time.day, 2]);
@jufemaiz

This comment has been minimized.

Show comment
Hide comment
@jufemaiz

jufemaiz Aug 22, 2014

A couple of comments:

  1. This doesn't work for linewithfocuschart; and
  2. This breaks linewithfocuschart's focus area.

Still trying to make this happen ><

A couple of comments:

  1. This doesn't work for linewithfocuschart; and
  2. This breaks linewithfocuschart's focus area.

Still trying to make this happen ><

@heliodor

This comment has been minimized.

Show comment
Hide comment
@heliodor

heliodor Mar 3, 2015

Contributor

I posted a pretty complete time series example on JsFiddle: http://jsfiddle.net/3r88bgjw/ Hope it helps.

It shows how to: 1) set the x scale to a time scale so default ticks are round values, 2) format the tooltip, 3) put tick marks on the x axis for usability, 4) use bars instead of line so any gaps are visible, 5) use multi-format so that time labels are short and fit nicely.

Contributor

heliodor commented Mar 3, 2015

I posted a pretty complete time series example on JsFiddle: http://jsfiddle.net/3r88bgjw/ Hope it helps.

It shows how to: 1) set the x scale to a time scale so default ticks are round values, 2) format the tooltip, 3) put tick marks on the x axis for usability, 4) use bars instead of line so any gaps are visible, 5) use multi-format so that time labels are short and fit nicely.

@AlonAm

This comment has been minimized.

Show comment
Hide comment

AlonAm commented Mar 5, 2015

thanks!

@mb-dev

This comment has been minimized.

Show comment
Hide comment

mb-dev commented Mar 6, 2015

Thanks!

@liquidpele liquidpele added the Feature label Mar 6, 2015

@liquidpele

This comment has been minimized.

Show comment
Hide comment
@liquidpele

liquidpele Mar 6, 2015

Member

@robinfhu Short term we should add that jsfiddle code as an example since it shows off a lot... long term we should probably merge in the main changes to historicalBar. Time series makes a lot of sense for that chart, and line chart too.

Member

liquidpele commented Mar 6, 2015

@robinfhu Short term we should add that jsfiddle code as an example since it shows off a lot... long term we should probably merge in the main changes to historicalBar. Time series makes a lot of sense for that chart, and line chart too.

liquidpele added a commit to liquidpele/nvd3 that referenced this issue Mar 9, 2015

@liquidpele

This comment has been minimized.

Show comment
Hide comment
@liquidpele

liquidpele Mar 9, 2015

Member

The jsfiddle example was merged into the project so there is an example there to work from at least, and w'ell try to make using a time series easier using that as a starting point. Closing this story, and if anyone wants to help out send us a pull request :)

Member

liquidpele commented Mar 9, 2015

The jsfiddle example was merged into the project so there is an example there to work from at least, and w'ell try to make using a time series easier using that as a starting point. Closing this story, and if anyone wants to help out send us a pull request :)

@liquidpele liquidpele closed this Mar 9, 2015

@milimetric

This comment has been minimized.

Show comment
Hide comment
@milimetric

milimetric Mar 20, 2015

The bar timeseries chart was not too useful in my case, but adapting code from the other responses I was able to make the lineWithFocusChart work well:

    chart.lines.xScale(d3.time.scale());
    chart.lines2.xScale(d3.time.scale());

    var timeFormat = d3.time.format('%Y-%m-%d');
    chart.xAxis.tickFormat(timeFormat);
    chart.x2Axis.tickFormat(timeFormat);

That's the only code you need in addition to the example from http://nvd3-community.github.io/nvd3/examples/lineWithFocusChart.html

The bar timeseries chart was not too useful in my case, but adapting code from the other responses I was able to make the lineWithFocusChart work well:

    chart.lines.xScale(d3.time.scale());
    chart.lines2.xScale(d3.time.scale());

    var timeFormat = d3.time.format('%Y-%m-%d');
    chart.xAxis.tickFormat(timeFormat);
    chart.x2Axis.tickFormat(timeFormat);

That's the only code you need in addition to the example from http://nvd3-community.github.io/nvd3/examples/lineWithFocusChart.html

@dlu306090

This comment has been minimized.

Show comment
Hide comment
@dlu306090

dlu306090 Apr 6, 2015

Does this handle automatic time ticks though? In the lineWithFocusChart, I can't seem to get those to work, because
var timeFormat = d3.time.format('%Y-%m-%d');
only makes all the dates a specific format. But I want to vary the format based on the length of time selected in the brush area, i.e. if less than a day interval is selected, I want the format in time(hh:mm:ss) rather than dates(mm/dd/yy).

Does this handle automatic time ticks though? In the lineWithFocusChart, I can't seem to get those to work, because
var timeFormat = d3.time.format('%Y-%m-%d');
only makes all the dates a specific format. But I want to vary the format based on the length of time selected in the brush area, i.e. if less than a day interval is selected, I want the format in time(hh:mm:ss) rather than dates(mm/dd/yy).

@heliodor

This comment has been minimized.

Show comment
Hide comment
@heliodor

heliodor Apr 6, 2015

Contributor

dlu306090, you can do that with the jsfiddle I posted earlier. Look at the 'tickMultiFormat' variable to see how it's done. You can see it in action better here: https://jsfiddle.net/kaLt5aqr/

Contributor

heliodor commented Apr 6, 2015

dlu306090, you can do that with the jsfiddle I posted earlier. Look at the 'tickMultiFormat' variable to see how it's done. You can see it in action better here: https://jsfiddle.net/kaLt5aqr/

@dlu306090

This comment has been minimized.

Show comment
Hide comment
@dlu306090

dlu306090 Apr 6, 2015

Hmm..I don't really understand how "resizing the panel to see the various types of time labels" works. What do you mean by resizing the panel? When I do it the chart doesn't itself resize. I just can't see half of it. Since I'm not able to resize the panel, I'm not seeing the different formats of the dates.

Hmm..I don't really understand how "resizing the panel to see the various types of time labels" works. What do you mean by resizing the panel? When I do it the chart doesn't itself resize. I just can't see half of it. Since I'm not able to resize the panel, I'm not seeing the different formats of the dates.

@jufemaiz

This comment has been minimized.

Show comment
Hide comment
@jufemaiz

jufemaiz Apr 7, 2015

@dlu306090 you'll need to hit "run" again after resizing as the jsfiddle instance hasn't bound resize events to rerender.

jufemaiz commented Apr 7, 2015

@dlu306090 you'll need to hit "run" again after resizing as the jsfiddle instance hasn't bound resize events to rerender.

@dlu306090

This comment has been minimized.

Show comment
Hide comment
@dlu306090

dlu306090 Apr 7, 2015

Ah, it works. Fantastic, thanks so much! So I think I've finally got the hang of this weird d3 date axis thing. I suppose this wasn't really what I was looking for though. I have an array of dates and values, and these values are being collected at very specific times, such as 03/24/15 03:34:01pm. I know that with tickMultiFormat you can get d3 to format starts of hours, starts of days, etc, certain ways, but what if I just want to base my formats on how large the range of days selected in the lineWithFocusChart is? Because currently, since all my data is so precise, everything is just defaulting to the rule "seconds" format. I'd like to be able to see when I zoom out just month names maybe, and then when I zoom in, to see days and hours, even though none of my dates (the x-values) are exactly the beginning of a month or a year. Is this functionality possible with d3?

Ah, it works. Fantastic, thanks so much! So I think I've finally got the hang of this weird d3 date axis thing. I suppose this wasn't really what I was looking for though. I have an array of dates and values, and these values are being collected at very specific times, such as 03/24/15 03:34:01pm. I know that with tickMultiFormat you can get d3 to format starts of hours, starts of days, etc, certain ways, but what if I just want to base my formats on how large the range of days selected in the lineWithFocusChart is? Because currently, since all my data is so precise, everything is just defaulting to the rule "seconds" format. I'd like to be able to see when I zoom out just month names maybe, and then when I zoom in, to see days and hours, even though none of my dates (the x-values) are exactly the beginning of a month or a year. Is this functionality possible with d3?

@heliodor

This comment has been minimized.

Show comment
Hide comment
@heliodor

heliodor Apr 7, 2015

Contributor

The way to do that is to:

  1. Create a time scale as a variable.
  2. Pass that scale to the axis.
  3. Call tickFormat() with your own formatting function.
  4. In that formatting function, get the current time span using scale.domain() and return whatever label you deem appropriate based on that time span.
Contributor

heliodor commented Apr 7, 2015

The way to do that is to:

  1. Create a time scale as a variable.
  2. Pass that scale to the axis.
  3. Call tickFormat() with your own formatting function.
  4. In that formatting function, get the current time span using scale.domain() and return whatever label you deem appropriate based on that time span.
@Serveurperso

This comment has been minimized.

Show comment
Hide comment
@Serveurperso

Serveurperso May 5, 2015

One day lost just for 2 line of undocumented strange behavior to get a readable time axis on my linechart:( Also there is a problem, there is no legend popup (useInteractiveGuideline true or false) with .tickFormat(timeFormat).

        chart.lines.xScale(d3.time.scale());
        var timeFormat = d3.time.format('%H:%M:%S');
        chart.xAxis
            .showMaxMin(false)
            .tickFormat(timeFormat)
        ;

One day lost just for 2 line of undocumented strange behavior to get a readable time axis on my linechart:( Also there is a problem, there is no legend popup (useInteractiveGuideline true or false) with .tickFormat(timeFormat).

        chart.lines.xScale(d3.time.scale());
        var timeFormat = d3.time.format('%H:%M:%S');
        chart.xAxis
            .showMaxMin(false)
            .tickFormat(timeFormat)
        ;
@joshjordan

This comment has been minimized.

Show comment
Hide comment
@joshjordan

joshjordan May 5, 2015

Contributor

We would welcome a pull request to improve documentation.

On Mon, May 4, 2015, 8:13 PM Pascal notifications@github.com wrote:

One day lost just for 2 undocumented strange behavior to get a readable
time axis....

    chart.lines.xScale(d3.time.scale());
    var timeFormat = d3.time.format('%H:%M:%S');
    chart.xAxis
        .showMaxMin(false)
        .tickFormat(timeFormat)
    ;


Reply to this email directly or view it on GitHub
#145 (comment).

Contributor

joshjordan commented May 5, 2015

We would welcome a pull request to improve documentation.

On Mon, May 4, 2015, 8:13 PM Pascal notifications@github.com wrote:

One day lost just for 2 undocumented strange behavior to get a readable
time axis....

    chart.lines.xScale(d3.time.scale());
    var timeFormat = d3.time.format('%H:%M:%S');
    chart.xAxis
        .showMaxMin(false)
        .tickFormat(timeFormat)
    ;


Reply to this email directly or view it on GitHub
#145 (comment).

@Serveurperso

This comment has been minimized.

Show comment
Hide comment
@Serveurperso

Serveurperso May 5, 2015

Hello, I can't document this because there is a regression/bug, it disable the bubble pop-up with values

Hello, I can't document this because there is a regression/bug, it disable the bubble pop-up with values

@Serveurperso

This comment has been minimized.

Show comment
Hide comment
@Serveurperso

Serveurperso May 5, 2015

I solved my problem, now I can make a cool sample for documentation...
Tooltip is now OK and xScale is nice:)

        chart.lines.xScale(d3.time.scale());
        chart.xAxis
            .showMaxMin(false)
            .tickFormat(function(d) {
                return d3.time.format('%H:%M:%S')(new Date(d))
            });
        ;

I solved my problem, now I can make a cool sample for documentation...
Tooltip is now OK and xScale is nice:)

        chart.lines.xScale(d3.time.scale());
        chart.xAxis
            .showMaxMin(false)
            .tickFormat(function(d) {
                return d3.time.format('%H:%M:%S')(new Date(d))
            });
        ;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment