1

I have many charts being generated dynamically. For some charts, the dates are near each other, so, axis labels are getting repeated

Example:

enter image description here

Date format used:

d3.time.format("%d-%b-%y")

Is there an in-built way to avoid duplication of labels? Or is there a good generic procedure which can avoid such duplication? Note that my charts have zooming feature also and the incoming data is dynamic, so I can't put in hardcoded values of "ticks" or "tickValues". Generating ticks or tickValues dynamically, could be the way to go.

coolscitist
  • 3,317
  • 8
  • 42
  • 59
  • 1
    Use a [multi-scale time format](http://bl.ocks.org/mbostock/4149176). – Lars Kotthoff Nov 06 '14 at 09:28
  • I am not sure if I am allowed to show dates in that fashion. Do you think it would be a good idea to do a post processing step and delete all duplicate ticks after chart has been drawn and after chart has been zoomed? – coolscitist Nov 06 '14 at 13:14
  • 1
    The other option would be to set the ticks manually with `.tickValues()`. Then no postprocessing is needed. – Lars Kotthoff Nov 06 '14 at 13:16
  • Yes, but since the data is dynamic and highly variant: ranging from 2 day interval for entire chart vs several years of interval, I will need a generic algorithm. May be a custom time scale, with domain as dates and range as chart dimensions and dividing chart dimension into equal parts with specified no. of ticks and then getting date values, and then rejecting duplicates and then specifying them as tickValues? – coolscitist Nov 06 '14 at 13:20
  • All of this is going to be much more difficult than simply compiling a list of tick values that contains no duplicates. – Lars Kotthoff Nov 06 '14 at 13:24
  • Ok, but I would still need nice intervals between ticks. Is there a better way to calculate tick values dynamically then? – coolscitist Nov 06 '14 at 13:25
  • 1
    You could simply use the scale's `.tick()` function to get ticks and then remove duplicates. – Lars Kotthoff Nov 06 '14 at 13:29
  • So, I fixed it using your solution. Firstly, used scale.ticks(userSpecifiedTicks) to get actual ticks, then got formatted ticks using specified formatter and then removed duplicates and then specified them as scale.tickValues(nonDuplicateTickValues) – coolscitist Nov 09 '14 at 06:11

2 Answers2

1

Thank you @Lars Kotthoff for helping out. This is the basic solution:

var ticks = scale.ticks(userSpecifiedTicks);
var nonDuplicateTickValues = [];

var tickAlreadyExists = function(tickValIn)
{
    for(var i=0;i<nonDuplicateTickValues.length;i++)
    {
        var t = nonDuplicateTickValues[i];
        var formattedTickValIn = formatter(tickValIn);
        var formattedTickVal = formatter(t);
        if(formattedTickValIn == formattedTickVal)
            {return true;}

    }
    return false;
};

var removeDuplicateTicks = function()
{
    for(var i=0;i<ticks.length;i++)
    { 
        var tickVal = ticks[i];
        if(!tickAlreadyExists(tickVal))
        {
            nonDuplicateTickValues.push(tickVal);
        }
    }
};

scale.tickValues(nonDuplicateTickValues);

Here, formatter could be any function like:

var formatter = function(d){
    var format = d3.time.format("%d-%b-%y");
    return format(d);
}
coolscitist
  • 3,317
  • 8
  • 42
  • 59
1

You can also use these methods to get distinct values from an array.

  1. d3.set().values()

Input: _.map(d3.set([1,2,3,3,4,5,5]).values(), function(d) { return +d; });

Output: [1, 2, 3, 4, 5]

Without _.map(array, function) you would get an array of strings as output, so modify as need be.

  1. onlyUnique(value, index, self) { return self.indexOf(value) === index; }

Input: [1,2,3,3,4,5,5].filter(onlyUnique);

Output: [1, 2, 3, 4, 5]

RhinoDevel
  • 712
  • 1
  • 12
  • 25
Shae Wang
  • 11
  • 1