Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

d3.scale.log tickFormat returns empty labels with ticks() length too large #655

Closed
benjchristensen opened this issue May 27, 2012 · 11 comments
Milestone

Comments

@benjchristensen
Copy link

The following code returns empty labels when the desiredTickCount/ticks().length < 0.1.

  scale.tickFormat = function(n, format) {
    if (arguments.length < 2) format = d3_scale_logFormat;
    if (arguments.length < 1) return format;
    var k = n / scale.ticks().length,
        f = log === d3_scale_logn ? (e = -1e-12, Math.floor) : (e = 1e-12, Math.ceil),
        e;
    return function(d) {
        // the following line breaks when k (desiredTickCount/ticks().length) is < 0.1 as it always will return ""
      return d / pow(f(log(d) + e)) < k ? format(d) : "";
    };
  };

Changing the code to explicitly check for == 0.1 seems to fix it in the use cases I've got, but I am sure there are scenarios I'm missing that necessitated the use of the k variable.

  scale.tickFormat = function(n, format) {
    if (arguments.length < 2) format = d3_scale_logFormat;
    if (arguments.length < 1) return format;
    var k = n / scale.ticks().length,
        f = log === d3_scale_logn ? (e = -1e-12, Math.floor) : (e = 1e-12, Math.ceil),
        e;
    return function(d) {
      //return d / pow(f(log(d) + e)) < k ? format(d) : "";
      return d / pow(f(log(d) + e)) == 0.1 ? format(d) : "";
    };
  };

The other way to work around it is to configure the desiredTickCount to be higher, but that doesn't work well for dynamic charts. For example, if 6 is generally the appropriate desiredTickCount but then a certain dataset requires 10 for the log scale to display it's awkward to determine that and would be preferable for the above scale.tickFormat function to correctly handle it.

@mbostock
Copy link
Member

Can you provide an example of what you're trying to do?

@benjchristensen
Copy link
Author

I have posted the code at https://gist.github.com/2817050 which can be viewed at http://bl.ocks.org/2817050

Note how when using log scale the tick values are all blank. You can flip to linear and power to see values show up for those.

Basically what I'm trying to do is allow the display of any set of metrics for various timelines and allow switching between linear, power and log scales and resizing the graphs to fit whatever browser window they have. The example I've provided only has a single axis on the left but I'm working on some dual-axis use cases as well.

The data ranges can be from 0 to 4 or 0 to 10s of millions so the max value of the axes are calculated using d3.max whenever the data is loaded. It all has been working very well with the exception of this small glitch for log scale tick labels.

Line 286 of line-graph.js can be modified from this:

        yAxisLeft = d3.svg.axis().scale(y).ticks(6, tickFormatForLogScale).orient("left");

to the following to make the log ticks show up:

        yAxisLeft = d3.svg.axis().scale(y).ticks(10, tickFormatForLogScale).orient("left");

That is not an ideal thing to have to change though, as it then requires different values depending on what data is being passed in, what scale (log/linear/power) is being used and the vertical size of the chart.

I have chosen to set the desired tick count to fit the vertical size I'm targeting and expected each of the axes to generate ticks accordingly and it was working well until one of my graphs didn't work with its dataset. After debugging I found it was because the data values caused a large number of ticks to be calculated which resulted in the conditional logic from my first comment preventing any tick labels to be created.

Also, if my use of the d3.js library or my javascript isn't correct, please let me know as I don't consider myself an expert at Javascript (and if that's the source of this issue I apologize for wasting your time).

Thank you for taking the time to look at this for me.

@benjchristensen
Copy link
Author

Thank you for the fix and the library.

@benjchristensen
Copy link
Author

I've tried using the d3.v2.js and d3.v2.min.js from the branch where this fix was committed and they do not appear to resolve the problem.

https://github.com/mbostock/d3/blob/fix-log-ticks/d3.v2.js

I updated the example gist to use this source and demonstrate it is still not resolved.

http://bl.ocks.org/2817050

@mbostock
Copy link
Member

mbostock commented Jun 5, 2012

As best I can tell, you're using your own tick format for that example anyway—you're not using the log scale's tickFormat, so my fix doesn't change anything in your code.

@mbostock
Copy link
Member

mbostock commented Jun 5, 2012

Ah, wait, sorry. I misread. That's the inner format that's passed through the log scale's format. This seems to reproduce the problem if you want to debug it:

var y = d3.scale.log().domain([1e-1, 1e7]);
y.ticks(6).map(y.tickFormat(6));

@mbostock mbostock reopened this Jun 5, 2012
@benjchristensen
Copy link
Author

Here is a version using default tick formatting and https://github.com/mbostock/d3/blob/fix-log-ticks/d3.v2.js and ticks do not show up:

http://bl.ocks.org/2876258 Issue 655 Example Without Custom Formatting

Here is a fork of my example that includes my patched version of d3.js that makes the ticks show:

http://bl.ocks.org/2876215 Issue 655 Example (Patch)

Here is the same example with default tick formatting using my patched d3.js file so ticks show up:

http://bl.ocks.org/2876239 Issue 655 Example (Patch) Without Custom Formatting

In the patched examples, line 2825 of d3.v2.patched.js is the location of the patch that makes the ticks correctly show.

@benjchristensen
Copy link
Author

I'm looking at the code example you sent ... my previous comment was sent before I saw your second comment.

The examples I provide do however show the functionality without custom formatting being involved.

@benjchristensen
Copy link
Author

Yes, that code replicates it. Debugging now and will post what I find.

Thanks

@benjchristensen
Copy link
Author

I think the only change that needs to occur is this:

return d / pow(f(log(d) + e)) < k ? format(d) : "";

to

return d / pow(f(log(d) + e)) <= k ? format(d) : "";

Your previous change made it so the smallest value of k is 0.1, but the tick value (d / pow(f(log(d) + e))) ends up being 0.1 and thus never less than 0.1 in scenarios where k is 0.1

Thus, it just needs to be <= as opposed to just < k.

I've posted my test and with the fixed version at http://bl.ocks.org/2876507

The diff can be seen here: https://github.com/benjchristensen/d3/commit/8dcd8fe8d5ce128468774f8db06b73482b45e25a#d3.v2.js

I'm not sure what other files I should be changing so I'm not doing a pull request as your previous commit seemed to have also touched unit tests and triggered a build of the minified version.

@benjchristensen
Copy link
Author

Thanks Mike.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants