Search code examples
dygraphs

Have two y-axis in Dygraphs with aligned zero


When using dygraphs to display two series (with axis y and y2), how would one go about the two y axes having a common zero?

E.g. for

1,-1,0
2,1,2

dygraph currently would put the first y-axis from -1 to 1, and the second from 0 to 2. As both values are supposed to denote changes (delta), it is very confusing this way.

As a side-note, I am setting the valueRange to [null, null] for both axes (some part of the data set has quite large values, others quite small - when zooming in I want to be able to better see the local differences). I am also using a custom plotter (multiColumnBarPlotter with adjustments to deal with negative values).


Solution

  • I've solved this (for now?) by adjusting the y axis ranges relative to each other, so the ratio of the positive to the negative part of each axis is identical. The following code seems to work fine for my use case.

    function zoom(minDate, maxDate) {
            minFirst = g.yAxisRanges()[0][0]
            maxFirst = g.yAxisRanges()[0][1] || 1
    
            minSecond = g.yAxisRanges()[1][0]
            maxSecond = g.yAxisRanges()[1][1] || 1
    
            if (minFirst >= 0 && minSecond >= 0) {
                    // setting both to zero will align zero at bottom
                    minFirst = secondFirst = 0;
            } else {
                    // calculate ratio ( negative part : positive part )
                    var ratioFirst  = - minFirst  / maxFirst
                    var ratioSecond = - minSecond / maxSecond
    
                    if (minFirst >= 0 || ratioFirst < ratioSecond) {
                            minFirst = - maxFirst * ratioSecond
                    } else {
                            minSecond = - maxSecond * ratioFirst
                    }
            }
    
            g.updateOptions({
                    axes: {  
                            y:  { valueRange: [minFirst,  maxFirst]  },
                            y2: { valueRange: [minSecond, maxSecond] }
                    }
            });
    }
    
    function resetY() {
            g.updateOptions({
                    valueRange: null,
                    axes: {
                            y:  { valueRange: [null, null] },
                            y2: { valueRange: [null, null] }
                    }
            });
    }
    
    g.updateOptions({
        zoomCallback: function(minDate, maxDate, yRanges) {
            resetY();
            g.ready(function() {
                zoom(minDate, maxDate)
            })
        }
    })