plotly / plotly.js

Open-source JavaScript charting library behind Plotly and Dash
https://plotly.com/javascript/
MIT License
16.92k stars 1.86k forks source link

[BUG] layout axis type: 'date' throws built in error on default example #5319

Closed sandro-sikic closed 3 years ago

sandro-sikic commented 3 years ago

https://codepen.io/SandroIT/pen/BaLKQgm

version: "1.58.1"

This issue breaks modebar functionality.

image

archmoj commented 3 years ago

I was not able to replicate. Could you use unminified bundle in the codepen and paste the error again?

sandro-sikic commented 3 years ago

Unminified codepen version

U can try this one as well.

Error triggers when it tries to load data. U can trigger the error manually by panning the graph.

Here's the function that throws the error.

  // set scaling to pixels
    ax.setScale = function(usePrivateRange) {
        var gs = fullLayout._size;

        // make sure we have a domain (pull it in from the axis
        // this one is overlaying if necessary)
        if(ax.overlaying) {
            var ax2 = axisIds.getFromId({ _fullLayout: fullLayout }, ax.overlaying);
            ax.domain = ax2.domain;
        }

        // While transitions are occurring, we get a double-transform
        // issue if we transform the drawn layer *and* use the new axis range to
        // draw the data. This allows us to construct setConvert using the pre-
        // interaction values of the range:
        var rangeAttr = (usePrivateRange && ax._r) ? '_r' : 'range';
        var calendar = ax.calendar;
        ax.cleanRange(rangeAttr);

        var rl0 = ax.r2l(ax[rangeAttr][0], calendar);
        var rl1 = ax.r2l(ax[rangeAttr][1], calendar);

        var isY = axLetter === 'y';
        if(isY) {
            ax._offset = gs.t + (1 - ax.domain[1]) * gs.h;
            ax._length = gs.h * (ax.domain[1] - ax.domain[0]);
            ax._m = ax._length / (rl0 - rl1);
            ax._b = -ax._m * rl1;
        } else {
            ax._offset = gs.l + ax.domain[0] * gs.w;
            ax._length = gs.w * (ax.domain[1] - ax.domain[0]);
            ax._m = ax._length / (rl1 - rl0);
            ax._b = -ax._m * rl0;
        }

        // set of "N" disjoint rangebreaks inside the range
        ax._rangebreaks = [];
        // length of these rangebreaks in value space - negative on reversed axes
        ax._lBreaks = 0;
        // l2p slope (same for all intervals)
        ax._m2 = 0;
        // set of l2p offsets (one for each of the (N+1) piecewise intervals)
        ax._B = [];

        if(ax.rangebreaks) {
            var i, brk;

            ax._rangebreaks = ax.locateBreaks(
                Math.min(rl0, rl1),
                Math.max(rl0, rl1)
            );

            if(ax._rangebreaks.length) {
                for(i = 0; i < ax._rangebreaks.length; i++) {
                    brk = ax._rangebreaks[i];
                    ax._lBreaks += Math.abs(brk.max - brk.min);
                }

                var flip = isY;
                if(rl0 > rl1) flip = !flip;
                if(flip) ax._rangebreaks.reverse();
                var sign = flip ? -1 : 1;

                ax._m2 = sign * ax._length / (Math.abs(rl1 - rl0) - ax._lBreaks);
                ax._B.push(-ax._m2 * (isY ? rl1 : rl0));
                for(i = 0; i < ax._rangebreaks.length; i++) {
                    brk = ax._rangebreaks[i];
                    ax._B.push(
                        ax._B[ax._B.length - 1] -
                        sign * ax._m2 * (brk.max - brk.min)
                    );
                }

                // fill pixel (i.e. 'p') min/max here,
                // to not have to loop through the _rangebreaks twice during `p2l`
                for(i = 0; i < ax._rangebreaks.length; i++) {
                    brk = ax._rangebreaks[i];
                    brk.pmin = l2p(brk.min);
                    brk.pmax = l2p(brk.max);
                }
            }
        }

        if(!isFinite(ax._m) || !isFinite(ax._b) || ax._length < 0) {
            fullLayout._replotting = false;
            throw new Error('Something went wrong with axis scaling');
        }
    };
archmoj commented 3 years ago

Thanks. Could you please test if you get a similar error using previous versions e.g. 1.58.0?

sandro-sikic commented 3 years ago

Version 1.58.0 CodePen

Version 1.57.1 CodePen

I'm clueless, this was working before. Unfortunately I lost a version of the working demo code I had from a month ago.

archmoj commented 3 years ago

Do you get any error in those versions? If so, please set width and height in layout so that we know we are viewing the same graph. Thanks!

sandro-sikic commented 3 years ago

Version 1.56.0 CodePen Version 1.57.1 CodePen Version 1.58.0 CodePen Version latest CodePen Version latest minified CodePen

I've updated the layout code for all the examples. This exception is thrown only when axis type is defined as 'date'. If the error is not thrown on initializing the data, and the graph is drawn, you can trigger it manually by using the pan tool in modbar. Exception is thrown in the javascript console.

Expected behaviour is for Plotly to match the dates with the internal date and generate timeline on the fly as the user is panning around.

Thanks for the help!

sandro-sikic commented 3 years ago

Any updates on this issue?

archmoj commented 3 years ago

Still unable to replicate. What is the last version of plotly.js that does NOT cause an error? Please set width and height in layout so that we know we are viewing the same graph. Thanks!

alexcjohnson commented 3 years ago

@sandro-sikic I'm afraid I also don't see any errors when panning any of the codepens you've posted above, using the latest Chrome, FF, and Safari on Mac. What browser and OS version do you have?

sandro-sikic commented 3 years ago

Thanks everyone for the feedback. The issue was caused by the chrome extension for changing time zones.