ChiMo
ChiMo

Reputation: 601

plotting on a dygraph y-axis as time?

Is it possible to create a Time format on the y-axis of a Dygraph?

-> formats #s, #m, #h.
The graph needs to display in whole numbers and not something like 2.5h.

enter image description here

I assume this can be done through the dygraph ticker option though I'm not completely sure where to start as the dygraph always seems to like to split its granularity at certain values (time should be split 60s then at 60m).

Can someone point me in the right direction for writing my own Dygraph ticker?

Upvotes: 2

Views: 887

Answers (2)

ChiMo
ChiMo

Reputation: 601

So I finally got around to writing an answer!

The easiest solution I found was to convert the amount (in seconds) to number of minutes or hours to which it then is split into nice intervals.

I found that changing to the higher value looked best at when it was double -> so seconds only changed to minutes when there was time greater than 2 minutes.


The ticker looks as so:

function dygraphTimeTicker(min, max, pixels, opts, dygraph, vals) {
    //Bigger the physical size of the graph - the more ticks we want
    var stepsAim = Math.ceil(pixels / 50);

    var storemax = Number(max);
    var storemin = Number(min);
    var timeRatio, valueSuffix;

    //Display the ticks as seconds, minutes or hours?
    if (storemax <= 120) { // (seconds) max <= 2 Minutes
        valueSuffix = "s";
        timeRatio = 1;
    } else if (storemax <= 7200) { // (minutes) max <= 2 Hours
        valueSuffix = "m";
        timeRatio = 60;
    } else { // (hours)
        valueSuffix = "h";
        timeRatio = 3600;
    }

    var tempmax = storemax + (timeRatio - (storemax % timeRatio));
    var maxTime = tempmax / timeRatio;

    //give us an array of our 'nice' values
    var labelSteps = gaugeSteps(maxTime, stepsAim);

    var labelArray = [];
    for (var j = 0; j < labelSteps.length; j++) {
        labelArray.push({
            v: labelSteps[j] * timeRatio,
            label: labelSteps[j] + valueSuffix
        });
    }

    return labelArray;
}

The dygraphTimeTicker also implements these functions:

//Give us a nice even numbers for our ticks
function calculateEvenStepSize(range, targetSteps) {
    // calculate an initial guess at step size
    var tempStep = range / targetSteps;

    // get the magnitude of the step size
    var mag = Math.floor(Math.log(tempStep) / Math.log(10));
    var magPow = Math.pow(10, mag);

    // calculate most significant digit of the new step size
    var magMsd = Math.round(tempStep / magPow + 0.5);

    // promote the MSD to either 1, 2, or 5
    if (magMsd > 5)
        magMsd = 10;
    else if (magMsd > 2)
        magMsd = 5;
    else if (magMsd > 1)
        magMsd = 2;

    return magMsd * magPow;
};

//Give us the array of values we want displayed as 'major ticks'
function gaugeSteps(max, step) {
    var steps = step || 10;
    var ticks = [];

    //if below steps then we don't want any decimals!
    if (max < steps) {
        for (var i = 0; i <= max; i++) {
            ticks.push(i);
        }
    } else {
        var tickSize = calculateEvenStepSize(max, steps);
        var loopAmount = Math.ceil(max / tickSize);

        for (i = 0; i < loopAmount + 1; i++) {
            ticks.push(i * tickSize);
        }
    }

    return ticks;
}

Initializing:

new Dygraph(document.getElementById("graph"), data, {
    series: { 'Values': { axis: 'y1' } },
    ylabel: "Time",
    graphType: "Date",
    axes: {
        y: {
            ticker: dygraphTimeTicker,
            includeZero: true,
            valueFormatter: function(val, opts, lineName) {
                //This here is your own formatter
                return ValueToTime(val);
            }
        }
    }
});

I hope this helps someone else out there.

Upvotes: 3

danvk
danvk

Reputation: 16905

I assume your y-values are something like number of seconds? You could write an axisLabelFormatter for the y-axis to convert number of seconds to a string like "1h" or "30m".

The default y-axis ticker chooses nice values for whole numbers, e.g. 100, 200, 300, which aren't necessarily nice values for durations. To get that, as you say, you'll need to write your own ticker.

This isn't as hard as it sounds. The best documentation on tickers is here. The numericTicks ticker is the simplest example.

Upvotes: 3

Related Questions