diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js
index 9aa3f9712ce..838968e2ca5 100644
--- a/src/plot_api/plot_api.js
+++ b/src/plot_api/plot_api.js
@@ -2008,12 +2008,12 @@ function _relayout(gd, aobj) {
             else flags.plot = true;
         }
         else {
-            if((fullLayout._has('gl2d') || fullLayout._has('regl')) &&
+            if((fullLayout._has('scatter-like') && fullLayout._has('regl')) &&
                 (ai === 'dragmode' &&
                 (vi === 'lasso' || vi === 'select') &&
                 !(vOld === 'lasso' || vOld === 'select'))
             ) {
-                flags.calc = true;
+                flags.plot = true;
             }
             else if(valObject) editTypes.update(flags, valObject);
             else flags.calc = true;
diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js
index 01f892f748f..34e49b56959 100644
--- a/src/plots/cartesian/axes.js
+++ b/src/plots/cartesian/axes.js
@@ -423,6 +423,13 @@ axes.saveShowSpikeInitial = function(gd, overwrite) {
     return hasOneAxisChanged;
 };
 
+axes.doesAxisNeedAutoRange = function(ax) {
+    return (
+        ax.autorange ||
+        !!Lib.nestedProperty(ax, 'rangeslider.autorange').get()
+    );
+};
+
 // axes.expand: if autoranging, include new data in the outer limits
 // for this axis
 // data is an array of numbers (ie already run through ax.d2c)
@@ -436,12 +443,7 @@ axes.saveShowSpikeInitial = function(gd, overwrite) {
 //      tozero: (boolean) make sure to include zero if axis is linear,
 //          and make it a tight bound if possible
 axes.expand = function(ax, data, options) {
-    var needsAutorange = (
-        ax.autorange ||
-        !!Lib.nestedProperty(ax, 'rangeslider.autorange').get()
-    );
-
-    if(!needsAutorange || !data) return;
+    if(!axes.doesAxisNeedAutoRange(ax) || !data) return;
 
     if(!ax._min) ax._min = [];
     if(!ax._max) ax._max = [];
diff --git a/src/traces/scatter/calc.js b/src/traces/scatter/calc.js
index d3c6d2e4360..547c4a49603 100644
--- a/src/traces/scatter/calc.js
+++ b/src/traces/scatter/calc.js
@@ -25,6 +25,31 @@ function calc(gd, trace) {
     var x = xa.makeCalcdata(trace, 'x');
     var y = ya.makeCalcdata(trace, 'y');
     var serieslen = trace._length;
+    var cd = new Array(serieslen);
+
+    var ppad = calcMarkerSize(trace, serieslen);
+    calcAxisExpansion(gd, trace, xa, ya, x, y, ppad);
+
+    for(var i = 0; i < serieslen; i++) {
+        cd[i] = (isNumeric(x[i]) && isNumeric(y[i])) ?
+            {x: x[i], y: y[i]} :
+            {x: BADNUM, y: BADNUM};
+
+        if(trace.ids) {
+            cd[i].id = String(trace.ids[i]);
+        }
+    }
+
+    arraysToCalcdata(cd, trace);
+    calcColorscale(trace);
+    calcSelection(cd, trace);
+
+    gd.firstscatter = false;
+    return cd;
+}
+
+function calcAxisExpansion(gd, trace, xa, ya, x, y, ppad) {
+    var serieslen = trace._length;
 
     // cancel minimum tick spacings (only applies to bars and boxes)
     xa._minDtick = 0;
@@ -35,8 +60,9 @@ function calc(gd, trace) {
     var xOptions = {padded: true};
     var yOptions = {padded: true};
 
-    var ppad = calcMarkerSize(trace, serieslen);
-    if(ppad) xOptions.ppad = yOptions.ppad = ppad;
+    if(ppad) {
+        xOptions.ppad = yOptions.ppad = ppad;
+    }
 
     // TODO: text size
 
@@ -72,24 +98,6 @@ function calc(gd, trace) {
 
     Axes.expand(xa, x, xOptions);
     Axes.expand(ya, y, yOptions);
-
-    // create the "calculated data" to plot
-    var cd = new Array(serieslen);
-    for(var i = 0; i < serieslen; i++) {
-        cd[i] = (isNumeric(x[i]) && isNumeric(y[i])) ?
-            {x: x[i], y: y[i]} : {x: BADNUM, y: BADNUM};
-
-        if(trace.ids) {
-            cd[i].id = String(trace.ids[i]);
-        }
-    }
-
-    arraysToCalcdata(cd, trace);
-    calcColorscale(trace);
-    calcSelection(cd, trace);
-
-    gd.firstscatter = false;
-    return cd;
 }
 
 function calcMarkerSize(trace, serieslen) {
@@ -131,5 +139,6 @@ function calcMarkerSize(trace, serieslen) {
 
 module.exports = {
     calc: calc,
-    calcMarkerSize: calcMarkerSize
+    calcMarkerSize: calcMarkerSize,
+    calcAxisExpansion: calcAxisExpansion
 };
diff --git a/src/traces/scattergl/index.js b/src/traces/scattergl/index.js
index dc8921aa753..80af61197b3 100644
--- a/src/traces/scattergl/index.js
+++ b/src/traces/scattergl/index.js
@@ -8,29 +8,32 @@
 
 'use strict';
 
-var Lib = require('../../lib');
-var getTraceColor = require('../scatter/get_trace_color');
-var ErrorBars = require('../../components/errorbars');
-var extend = require('object-assign');
-var Axes = require('../../plots/cartesian/axes');
-var kdtree = require('kdgrass');
-var subTypes = require('../scatter/subtypes');
-var calcColorscales = require('../scatter/colorscale_calc');
-var Drawing = require('../../components/drawing');
-var makeBubbleSizeFn = require('../scatter/make_bubble_size_func');
-var DASHES = require('../../constants/gl2d_dashes');
-var formatColor = require('../../lib/gl_format_color');
-var linkTraces = require('../scatter/link_traces');
+var createRegl = require('regl');
 var createScatter = require('regl-scatter2d');
 var createLine = require('regl-line2d');
 var createError = require('regl-error2d');
+var kdtree = require('kdgrass');
 var rgba = require('color-normalize');
 var svgSdf = require('svg-path-sdf');
-var createRegl = require('regl');
 var arrayRange = require('array-range');
+
+var Lib = require('../../lib');
+var Axes = require('../../plots/cartesian/axes');
+var Drawing = require('../../components/drawing');
+var ErrorBars = require('../../components/errorbars');
+var formatColor = require('../../lib/gl_format_color');
+
+var subTypes = require('../scatter/subtypes');
+var calcMarkerSize = require('../scatter/calc').calcMarkerSize;
+var calcAxisExpansion = require('../scatter/calc').calcAxisExpansion;
+var calcColorscales = require('../scatter/colorscale_calc');
+var makeBubbleSizeFn = require('../scatter/make_bubble_size_func');
+var linkTraces = require('../scatter/link_traces');
+var getTraceColor = require('../scatter/get_trace_color');
 var fillHoverText = require('../scatter/fill_hover_text');
-var isNumeric = require('fast-isnumeric');
 
+var DASHES = require('../../constants/gl2d_dashes');
+var BADNUM = require('../../constants/numerical').BADNUM;
 var SYMBOL_SDF_SIZE = 200;
 var SYMBOL_SIZE = 20;
 var SYMBOL_STROKE = SYMBOL_SIZE / 20;
@@ -38,123 +41,77 @@ var SYMBOL_SDF = {};
 var SYMBOL_SVG_CIRCLE = Drawing.symbolFuncs[0](SYMBOL_SIZE * 0.05);
 var TOO_MANY_POINTS = 1e5;
 var DOT_RE = /-dot/;
-
-function calc(container, trace) {
-    var layout = container._fullLayout;
-    var positions;
+var OPEN_RE = /-open/;
+
+function calc(gd, trace) {
+    var fullLayout = gd._fullLayout;
+    var xa = Axes.getFromId(gd, trace.xaxis);
+    var ya = Axes.getFromId(gd, trace.yaxis);
+    var subplot = fullLayout._plots[trace.xaxis + trace.yaxis];
+    var count = trace._length;
+    var count2 = count * 2;
     var stash = {};
-    var xaxis = Axes.getFromId(container, trace.xaxis);
-    var yaxis = Axes.getFromId(container, trace.yaxis);
+    var i, xx, yy;
 
-    var subplot = layout._plots[trace.xaxis + trace.yaxis];
+    var x = xa.makeCalcdata(trace, 'x');
+    var y = ya.makeCalcdata(trace, 'y');
 
-    var x = xaxis.type === 'linear' ? trace.x : xaxis.makeCalcdata(trace, 'x');
-    var y = yaxis.type === 'linear' ? trace.y : yaxis.makeCalcdata(trace, 'y');
-
-    var count = trace._length, i, xx, yy;
+    // we need hi-precision for scatter2d,
+    // regl-scatter2d uses NaNs for bad/missing values
+    var positions = new Array(count2);
+    for(i = 0; i < count; i++) {
+        xx = x[i];
+        yy = y[i];
+        positions[i * 2] = xx === BADNUM ? NaN : xx;
+        positions[i * 2 + 1] = yy === BADNUM ? NaN : yy;
+    }
 
-    if(!x) {
-        x = Array(count);
-        for(i = 0; i < count; i++) {
-            x[i] = i;
+    if(xa.type === 'log') {
+        for(i = 0; i < count2; i += 2) {
+            positions[i] = xa.c2l(positions[i]);
         }
     }
-    if(!y) {
-        y = Array(count);
-        for(i = 0; i < count; i++) {
-            y[i] = i;
+    if(ya.type === 'log') {
+        for(i = 1; i < count2; i += 2) {
+            positions[i] = ya.c2l(positions[i]);
         }
     }
 
-    // get log converted positions
-    var rawx = (xaxis.type === 'log' || x.length > count) ? x.slice(0, count) : x;
-    var rawy = (yaxis.type === 'log' || y.length > count) ? y.slice(0, count) : y;
-
-    var convertX = (xaxis.type === 'log') ? xaxis.d2l : parseFloat;
-    var convertY = (yaxis.type === 'log') ? yaxis.d2l : parseFloat;
-
-    // we need hi-precision for scatter2d
-    positions = new Array(count * 2);
-
-    for(i = 0; i < count; i++) {
-        x[i] = convertX(x[i]);
-        y[i] = convertY(y[i]);
-
-        // if no x defined, we are creating simple int sequence (API)
-        // we use parseFloat because it gives NaN (we need that for empty values to avoid drawing lines) and it is incredibly fast
-        xx = isNumeric(x[i]) ? +x[i] : NaN;
-        yy = isNumeric(y[i]) ? +y[i] : NaN;
-
-        positions[i * 2] = xx;
-        positions[i * 2 + 1] = yy;
-    }
-
     // we don't build a tree for log axes since it takes long to convert log2px
     // and it is also
-    if(xaxis.type !== 'log' && yaxis.type !== 'log') {
+    if(xa.type !== 'log' && ya.type !== 'log') {
         // FIXME: delegate this to webworker
         stash.tree = kdtree(positions, 512);
-    }
-    else {
-        var ids = stash.ids = Array(count);
+    } else {
+        var ids = stash.ids = new Array(count);
         for(i = 0; i < count; i++) {
             ids[i] = i;
         }
     }
 
+    // create scene options and scene
     calcColorscales(trace);
-
-    var options = sceneOptions(container, subplot, trace, positions);
-
-    // expanding axes is separate from options
-    if(!options.markers) {
-        Axes.expand(xaxis, rawx, { padded: true });
-        Axes.expand(yaxis, rawy, { padded: true });
-    }
-    else if(Lib.isArrayOrTypedArray(options.markers.sizes)) {
-        var sizes = options.markers.sizes;
-        Axes.expand(xaxis, rawx, { padded: true, ppad: sizes });
-        Axes.expand(yaxis, rawy, { padded: true, ppad: sizes });
-    }
-    else {
-        var xbounds = [Infinity, -Infinity], ybounds = [Infinity, -Infinity];
-        var size = options.markers.size;
-
-        // axes bounds
-        for(i = 0; i < count; i++) {
-            xx = x[i], yy = y[i];
-            if(xbounds[0] > xx) xbounds[0] = xx;
-            if(xbounds[1] < xx) xbounds[1] = xx;
-            if(ybounds[0] > yy) ybounds[0] = yy;
-            if(ybounds[1] < yy) ybounds[1] = yy;
-        }
-
-        // FIXME: is there a better way to separate expansion?
-        if(count < TOO_MANY_POINTS) {
-            Axes.expand(xaxis, rawx, { padded: true, ppad: size });
-            Axes.expand(yaxis, rawy, { padded: true, ppad: size });
-        }
-        // update axes fast for big number of points
-        else {
-            if(xaxis._min) {
-                xaxis._min.push({ val: xbounds[0], pad: size });
-            }
-            if(xaxis._max) {
-                xaxis._max.push({ val: xbounds[1], pad: size });
-            }
-
-            if(yaxis._min) {
-                yaxis._min.push({ val: ybounds[0], pad: size });
-            }
-            if(yaxis._max) {
-                yaxis._max.push({ val: ybounds[1], pad: size });
-            }
+    var options = sceneOptions(gd, subplot, trace, positions);
+    var markerOptions = options.marker;
+    var scene = sceneUpdate(gd, subplot);
+    var ppad;
+
+    // Re-use SVG scatter axis expansion routine except
+    // for graph with very large number of points where it
+    // performs poorly.
+    // In big data case, fake Axes.expand outputs with data bounds,
+    // and an average size for array marker.size inputs.
+    if(count < TOO_MANY_POINTS) {
+        ppad = calcMarkerSize(trace, count);
+        calcAxisExpansion(gd, trace, xa, ya, x, y, ppad);
+    } else {
+        if(markerOptions) {
+            ppad = 2 * (markerOptions.sizeAvg || Math.max(markerOptions.size, 3));
         }
+        fastAxisExpand(xa, x, ppad);
+        fastAxisExpand(ya, y, ppad);
     }
 
-    // create scene
-    var scene = sceneUpdate(container, subplot);
-
     // set flags to create scene renderers
     if(options.fill && !scene.fill2d) scene.fill2d = true;
     if(options.marker && !scene.scatter2d) scene.scatter2d = true;
@@ -176,22 +133,43 @@ function calc(container, trace) {
     stash.index = scene.count - 1;
     stash.x = x;
     stash.y = y;
-    stash.rawx = rawx;
-    stash.rawy = rawy;
     stash.positions = positions;
     stash.count = count;
 
+    gd.firstscatter = false;
     return [{x: false, y: false, t: stash, trace: trace}];
 }
 
+// Approximate Axes.expand results with speed
+function fastAxisExpand(ax, vals, ppad) {
+    if(!Axes.doesAxisNeedAutoRange(ax) || !vals) return;
+
+    var b0 = Infinity;
+    var b1 = -Infinity;
+
+    for(var i = 0; i < vals.length; i += 2) {
+        var v = vals[i];
+        if(v < b0) b0 = v;
+        if(v > b1) b1 = v;
+    }
+
+    if(ax._min) ax._min = [];
+    ax._min.push({val: b0, pad: ppad});
+
+    if(ax._max) ax._max = [];
+    ax._max.push({val: b1, pad: ppad});
+}
+
 // create scene options
-function sceneOptions(container, subplot, trace, positions) {
-    var layout = container._fullLayout;
+function sceneOptions(gd, subplot, trace, positions) {
+    var fullLayout = gd._fullLayout;
     var count = positions.length / 2;
     var markerOpts = trace.marker;
-    var i, ptrX = 0, ptrY = 0;
-    var xaxis = Axes.getFromId(container, trace.xaxis);
-    var yaxis = Axes.getFromId(container, trace.yaxis);
+    var xaxis = Axes.getFromId(gd, trace.xaxis);
+    var yaxis = Axes.getFromId(gd, trace.yaxis);
+    var ptrX = 0;
+    var ptrY = 0;
+    var i;
 
     var hasLines, hasErrorX, hasErrorY, hasError, hasMarkers, hasFill;
 
@@ -201,8 +179,7 @@ function sceneOptions(container, subplot, trace, positions) {
         hasErrorY = false;
         hasMarkers = false;
         hasFill = false;
-    }
-    else {
+    } else {
         hasLines = subTypes.hasLines(trace) && positions.length > 1;
         hasErrorX = trace.error_x && trace.error_x.visible === true;
         hasErrorY = trace.error_y && trace.error_y.visible === true;
@@ -211,11 +188,13 @@ function sceneOptions(container, subplot, trace, positions) {
         hasFill = !!trace.fill && trace.fill !== 'none';
     }
 
-    var lineOptions, markerOptions, errorXOptions, errorYOptions, fillOptions, selectedOptions, unselectedOptions;
+    var lineOptions, markerOptions, fillOptions;
+    var errorXOptions, errorYOptions;
+    var selectedOptions, unselectedOptions;
     var linePositions;
 
     // get error values
-    var errorVals = hasError ? ErrorBars.calcFromTrace(trace, layout) : null;
+    var errorVals = hasError ? ErrorBars.calcFromTrace(trace, fullLayout) : null;
 
     if(hasErrorX) {
         errorXOptions = {};
@@ -337,7 +316,9 @@ function sceneOptions(container, subplot, trace, positions) {
                 break;
             }
         }
-        lineOptions.join = (hasNaN || linePositions.length > TOO_MANY_POINTS) ? 'rect' : hasMarkers ? 'rect' : 'round';
+
+        lineOptions.join = (hasNaN || linePositions.length > TOO_MANY_POINTS) ? 'rect' :
+            hasMarkers ? 'rect' : 'round';
 
         // fill gaps
         if(hasNaN && trace.connectgaps) {
@@ -368,7 +349,6 @@ function sceneOptions(container, subplot, trace, positions) {
         markerOptions = makeMarkerOptions(markerOpts);
         selectedOptions = makeSelectedOptions(trace.selected, markerOpts);
         unselectedOptions = makeSelectedOptions(trace.unselected, markerOpts);
-
         markerOptions.positions = positions;
     }
 
@@ -378,7 +358,7 @@ function sceneOptions(container, subplot, trace, positions) {
         if(!selected) return options;
 
         if(selected.marker && selected.marker.symbol) {
-            options = makeMarkerOptions(extend({}, markerOpts, selected.marker));
+            options = makeMarkerOptions(Lib.extendFlat({}, markerOpts, selected.marker));
         }
 
         // shortcut simple selection logic
@@ -393,17 +373,21 @@ function sceneOptions(container, subplot, trace, positions) {
     }
 
     function makeMarkerOptions(markerOpts) {
-        var markerOptions = {}, i;
+        var markerOptions = {};
+        var i;
 
-        // get basic symbol info
-        var multiMarker = Array.isArray(markerOpts.symbol);
-        var isOpen, symbol;
-        if(!multiMarker) {
-            isOpen = /-open/.test(markerOpts.symbol);
-        }
+        var multiSymbol = Array.isArray(markerOpts.symbol);
+        var multiColor = Lib.isArrayOrTypedArray(markerOpts.color);
+        var multiLineColor = Lib.isArrayOrTypedArray(markerOpts.line.color);
+        var multiOpacity = Lib.isArrayOrTypedArray(markerOpts.opacity);
+        var multiSize = Lib.isArrayOrTypedArray(markerOpts.size);
+        var multiLineWidth = Lib.isArrayOrTypedArray(markerOpts.line.width);
+
+        var isOpen;
+        if(!multiSymbol) isOpen = OPEN_RE.test(markerOpts.symbol);
 
         // prepare colors
-        if(multiMarker || Array.isArray(markerOpts.color) || Array.isArray(markerOpts.line.color) || Array.isArray(markerOpts.line) || Array.isArray(markerOpts.opacity)) {
+        if(multiSymbol || multiColor || multiLineColor || multiOpacity) {
             markerOptions.colors = new Array(count);
             markerOptions.borderColors = new Array(count);
             var colors = formatColor(markerOpts, markerOpts.opacity, count);
@@ -428,9 +412,9 @@ function sceneOptions(container, subplot, trace, positions) {
             markerOptions.borderColors = borderColors;
 
             for(i = 0; i < count; i++) {
-                if(multiMarker) {
-                    symbol = markerOpts.symbol[i];
-                    isOpen = /-open/.test(symbol);
+                if(multiSymbol) {
+                    var symbol = markerOpts.symbol[i];
+                    isOpen = OPEN_RE.test(symbol);
                 }
                 if(isOpen) {
                     borderColors[i] = colors[i].slice();
@@ -446,8 +430,7 @@ function sceneOptions(container, subplot, trace, positions) {
                 markerOptions.color = rgba(markerOpts.color, 'uint8');
                 markerOptions.color[3] = 0;
                 markerOptions.borderColor = rgba(markerOpts.color, 'uint8');
-            }
-            else {
+            } else {
                 markerOptions.color = rgba(markerOpts.color, 'uint8');
                 markerOptions.borderColor = rgba(markerOpts.line.color, 'uint8');
             }
@@ -455,53 +438,54 @@ function sceneOptions(container, subplot, trace, positions) {
             markerOptions.opacity = trace.opacity * markerOpts.opacity;
         }
 
-        // prepare markers
-        if(Array.isArray(markerOpts.symbol)) {
+        // prepare symbols
+        if(multiSymbol) {
             markerOptions.markers = new Array(count);
-            for(i = 0; i < count; ++i) {
+            for(i = 0; i < count; i++) {
                 markerOptions.markers[i] = getSymbolSdf(markerOpts.symbol[i]);
             }
-        }
-        else {
+        } else {
             markerOptions.marker = getSymbolSdf(markerOpts.symbol);
         }
 
-        // prepare sizes and expand axes
-        var multiSize = markerOpts && (Array.isArray(markerOpts.size) || Array.isArray(markerOpts.line.width));
+        // prepare sizes
         var markerSizeFunc = makeBubbleSizeFn(trace);
-        var size, sizes;
+        var s;
 
-        if(multiSize) {
-            sizes = markerOptions.sizes = new Array(count);
+        if(multiSize || multiLineWidth) {
+            var sizes = markerOptions.sizes = new Array(count);
             var borderSizes = markerOptions.borderSizes = new Array(count);
+            var sizeTotal = 0;
+            var sizeAvg;
 
-            if(Array.isArray(markerOpts.size)) {
-                for(i = 0; i < count; ++i) {
+            if(multiSize) {
+                for(i = 0; i < count; i++) {
                     sizes[i] = markerSizeFunc(markerOpts.size[i]);
+                    sizeTotal += sizes[i];
                 }
-            }
-            else {
-                size = markerSizeFunc(markerOpts.size);
-                for(i = 0; i < count; ++i) {
-                    sizes[i] = size;
+                sizeAvg = sizeTotal / count;
+            } else {
+                s = markerSizeFunc(markerOpts.size);
+                for(i = 0; i < count; i++) {
+                    sizes[i] = s;
                 }
             }
 
             // See  https://github.com/plotly/plotly.js/pull/1781#discussion_r121820798
-            if(Array.isArray(markerOpts.line.width)) {
-                for(i = 0; i < count; ++i) {
+            if(multiLineWidth) {
+                for(i = 0; i < count; i++) {
                     borderSizes[i] = markerSizeFunc(markerOpts.line.width[i]);
                 }
-            }
-            else {
-                size = markerSizeFunc(markerOpts.line.width);
-                for(i = 0; i < count; ++i) {
-                    borderSizes[i] = size;
+            } else {
+                s = markerSizeFunc(markerOpts.line.width);
+                for(i = 0; i < count; i++) {
+                    borderSizes[i] = s;
                 }
             }
-        }
-        else {
-            size = markerOptions.size = markerSizeFunc(markerOpts && markerOpts.size || 10);
+
+            markerOptions.sizeAvg = sizeAvg;
+        } else {
+            markerOptions.size = markerSizeFunc(markerOpts && markerOpts.size || 10);
             markerOptions.borderSizes = markerSizeFunc(markerOpts.line.width);
         }
 
@@ -520,9 +504,9 @@ function sceneOptions(container, subplot, trace, positions) {
 }
 
 // make sure scene exists on subplot, return it
-function sceneUpdate(container, subplot) {
+function sceneUpdate(gd, subplot) {
     var scene = subplot._scene;
-    var layout = container._fullLayout;
+    var fullLayout = gd._fullLayout;
 
     if(!subplot._scene) {
         scene = subplot._scene = {
@@ -599,9 +583,12 @@ function sceneUpdate(container, subplot) {
 
         // make sure canvas is clear
         scene.clear = function clear() {
-            var vpSize = layout._size, width = layout.width, height = layout.height, vp, gl, regl;
+            var vpSize = fullLayout._size;
+            var width = fullLayout.width;
+            var height = fullLayout.height;
             var xaxis = subplot.xaxis;
             var yaxis = subplot.yaxis;
+            var vp, gl, regl;
 
             // multisubplot case
             if(xaxis && xaxis.domain && yaxis && yaxis.domain) {
@@ -720,20 +707,22 @@ function getSymbolSdf(symbol) {
     return symbolSdf || null;
 }
 
-function plot(container, subplot, cdata) {
+function plot(gd, subplot, cdata) {
     if(!cdata.length) return;
 
-    var layout = container._fullLayout;
+    var fullLayout = gd._fullLayout;
     var scene = cdata[0][0].t.scene;
-    var dragmode = layout.dragmode;
+    var dragmode = fullLayout.dragmode;
 
     // we may have more subplots than initialized data due to Axes.getSubplots method
     if(!scene) return;
 
-    var vpSize = layout._size, width = layout.width, height = layout.height;
+    var vpSize = fullLayout._size;
+    var width = fullLayout.width;
+    var height = fullLayout.height;
 
     // make sure proper regl instances are created
-    layout._glcanvas.each(function(d) {
+    fullLayout._glcanvas.each(function(d) {
         if(d.regl || d.pick) return;
         d.regl = createRegl({
             canvas: this,
@@ -742,14 +731,14 @@ function plot(container, subplot, cdata) {
                 preserveDrawingBuffer: true
             },
             extensions: ['ANGLE_instanced_arrays', 'OES_element_index_uint'],
-            pixelRatio: container._context.plotGlPixelRatio || global.devicePixelRatio
+            pixelRatio: gd._context.plotGlPixelRatio || global.devicePixelRatio
         });
     });
 
-    var regl = layout._glcanvas.data()[0].regl;
+    var regl = fullLayout._glcanvas.data()[0].regl;
 
     // that is needed for fills
-    linkTraces(container, subplot, cdata);
+    linkTraces(gd, subplot, cdata);
 
     if(scene.dirty) {
         // make sure scenes are created
@@ -878,11 +867,11 @@ function plot(container, subplot, cdata) {
         var trace = cd.trace;
         var stash = cd.t;
         var id = stash.index;
-        var x = stash.rawx,
-            y = stash.rawy;
+        var x = stash.x;
+        var y = stash.y;
 
-        var xaxis = subplot.xaxis || Axes.getFromId(container, trace.xaxis || 'x');
-        var yaxis = subplot.yaxis || Axes.getFromId(container, trace.yaxis || 'y');
+        var xaxis = subplot.xaxis || Axes.getFromId(gd, trace.xaxis || 'x');
+        var yaxis = subplot.yaxis || Axes.getFromId(gd, trace.yaxis || 'y');
         var i;
 
         var range = [
@@ -922,7 +911,8 @@ function plot(container, subplot, cdata) {
             }
 
             // precalculate px coords since we are not going to pan during select
-            var xpx = Array(stash.count), ypx = Array(stash.count);
+            var xpx = new Array(stash.count);
+            var ypx = new Array(stash.count);
             for(i = 0; i < stash.count; i++) {
                 xpx[i] = xaxis.c2p(x[i]);
                 ypx[i] = yaxis.c2p(y[i]);
@@ -944,7 +934,7 @@ function plot(container, subplot, cdata) {
         // create select2d
         if(!scene.select2d) {
             // create scatter instance by cloning scatter2d
-            scene.select2d = createScatter(layout._glcanvas.data()[1].regl, {clone: scene.scatter2d});
+            scene.select2d = createScatter(fullLayout._glcanvas.data()[1].regl, {clone: scene.scatter2d});
         }
 
         if(scene.scatter2d && scene.selectBatch && scene.selectBatch.length) {
@@ -988,8 +978,8 @@ function hoverPoints(pointData, xval, yval, hovermode) {
     var trace = cd[0].trace;
     var xa = pointData.xa;
     var ya = pointData.ya;
-    var x = stash.rawx;
-    var y = stash.rawy;
+    var x = stash.x;
+    var y = stash.y;
     var xpx = xa.c2p(xval);
     var ypx = ya.c2p(yval);
     var maxDistance = pointData.distance;
@@ -1096,9 +1086,9 @@ function hoverPoints(pointData, xval, yval, hovermode) {
         di.mgc = Array.isArray(grad.color) ? grad.color[id] : grad.color;
     }
 
-    var xc = xa.c2p(di.x, true),
-        yc = ya.c2p(di.y, true),
-        rad = di.mrc || 1;
+    var xp = xa.c2p(di.x, true);
+    var yp = ya.c2p(di.y, true);
+    var rad = di.mrc || 1;
 
     var hoverlabel = trace.hoverlabel;
 
@@ -1121,12 +1111,12 @@ function hoverPoints(pointData, xval, yval, hovermode) {
     Lib.extendFlat(pointData, {
         color: getTraceColor(trace, di),
 
-        x0: xc - rad,
-        x1: xc + rad,
+        x0: xp - rad,
+        x1: xp + rad,
         xLabelVal: di.x,
 
-        y0: yc - rad,
-        y1: yc + rad,
+        y0: yp - rad,
+        y1: yp + rad,
         yLabelVal: di.y,
 
         cd: fakeCd,
@@ -1145,15 +1135,12 @@ function hoverPoints(pointData, xval, yval, hovermode) {
 }
 
 function selectPoints(searchInfo, polygon) {
-    var cd = searchInfo.cd,
-        selection = [],
-        trace = cd[0].trace,
-        stash = cd[0].t,
-        x = stash.x,
-        y = stash.y,
-        rawx = stash.rawx,
-        rawy = stash.rawy;
-
+    var cd = searchInfo.cd;
+    var selection = [];
+    var trace = cd[0].trace;
+    var stash = cd[0].t;
+    var x = stash.x;
+    var y = stash.y;
     var scene = stash.scene;
 
     if(!scene) return selection;
@@ -1163,7 +1150,9 @@ function selectPoints(searchInfo, polygon) {
 
     // degenerate polygon does not enable selection
     // filter out points by visible scatter ones
-    var els = null, unels = null, i;
+    var els = null;
+    var unels = null;
+    var i;
     if(polygon !== false && !polygon.degenerate) {
         els = [], unels = [];
         for(i = 0; i < stash.count; i++) {
@@ -1171,16 +1160,15 @@ function selectPoints(searchInfo, polygon) {
                 els.push(i);
                 selection.push({
                     pointNumber: i,
-                    x: rawx ? rawx[i] : x[i],
-                    y: rawy ? rawy[i] : y[i]
+                    x: x[i],
+                    y: y[i]
                 });
             }
             else {
                 unels.push(i);
             }
         }
-    }
-    else {
+    } else {
         unels = arrayRange(stash.count);
     }
 
diff --git a/test/image/baselines/gl2d_10.png b/test/image/baselines/gl2d_10.png
index b3d8ce18148..85bcc6a1a3a 100644
Binary files a/test/image/baselines/gl2d_10.png and b/test/image/baselines/gl2d_10.png differ
diff --git a/test/image/baselines/gl2d_12.png b/test/image/baselines/gl2d_12.png
index 9f35f0bb4fe..e0e6c389512 100644
Binary files a/test/image/baselines/gl2d_12.png and b/test/image/baselines/gl2d_12.png differ
diff --git a/test/image/baselines/gl2d_14.png b/test/image/baselines/gl2d_14.png
index 9a4ae8542e8..d90ff1e2468 100644
Binary files a/test/image/baselines/gl2d_14.png and b/test/image/baselines/gl2d_14.png differ
diff --git a/test/image/baselines/gl2d_17.png b/test/image/baselines/gl2d_17.png
index 85a564fd72c..7eeb7dea3a8 100644
Binary files a/test/image/baselines/gl2d_17.png and b/test/image/baselines/gl2d_17.png differ
diff --git a/test/image/baselines/gl2d_axes_booleans.png b/test/image/baselines/gl2d_axes_booleans.png
index e0350f5c8de..7e523efca3b 100644
Binary files a/test/image/baselines/gl2d_axes_booleans.png and b/test/image/baselines/gl2d_axes_booleans.png differ
diff --git a/test/image/baselines/gl2d_axes_labels.png b/test/image/baselines/gl2d_axes_labels.png
index 5cf474017f0..decf839b993 100644
Binary files a/test/image/baselines/gl2d_axes_labels.png and b/test/image/baselines/gl2d_axes_labels.png differ
diff --git a/test/image/baselines/gl2d_axes_labels2.png b/test/image/baselines/gl2d_axes_labels2.png
index 07d41bf98a3..0df05344ea9 100644
Binary files a/test/image/baselines/gl2d_axes_labels2.png and b/test/image/baselines/gl2d_axes_labels2.png differ
diff --git a/test/image/baselines/gl2d_axes_lines.png b/test/image/baselines/gl2d_axes_lines.png
index 6d2711ff435..de668a0dc13 100644
Binary files a/test/image/baselines/gl2d_axes_lines.png and b/test/image/baselines/gl2d_axes_lines.png differ
diff --git a/test/image/baselines/gl2d_axes_range_mode.png b/test/image/baselines/gl2d_axes_range_mode.png
index 22f6212f49c..98eca06f700 100644
Binary files a/test/image/baselines/gl2d_axes_range_mode.png and b/test/image/baselines/gl2d_axes_range_mode.png differ
diff --git a/test/image/baselines/gl2d_axes_range_type.png b/test/image/baselines/gl2d_axes_range_type.png
index ba6739c52cc..5e02124eb9a 100644
Binary files a/test/image/baselines/gl2d_axes_range_type.png and b/test/image/baselines/gl2d_axes_range_type.png differ
diff --git a/test/image/baselines/gl2d_clean-number.png b/test/image/baselines/gl2d_clean-number.png
new file mode 100644
index 00000000000..4143c7c7dce
Binary files /dev/null and b/test/image/baselines/gl2d_clean-number.png differ
diff --git a/test/image/baselines/gl2d_connect_gaps.png b/test/image/baselines/gl2d_connect_gaps.png
index 69d5a638652..dba70d4dc06 100644
Binary files a/test/image/baselines/gl2d_connect_gaps.png and b/test/image/baselines/gl2d_connect_gaps.png differ
diff --git a/test/image/baselines/gl2d_date_axes.png b/test/image/baselines/gl2d_date_axes.png
index 309ec31a081..35a016d6f19 100644
Binary files a/test/image/baselines/gl2d_date_axes.png and b/test/image/baselines/gl2d_date_axes.png differ
diff --git a/test/image/baselines/gl2d_error_bars.png b/test/image/baselines/gl2d_error_bars.png
index 7c2ef3fe710..0cd99081555 100644
Binary files a/test/image/baselines/gl2d_error_bars.png and b/test/image/baselines/gl2d_error_bars.png differ
diff --git a/test/image/baselines/gl2d_error_bars_log.png b/test/image/baselines/gl2d_error_bars_log.png
index d8b75b45d95..26cc4c4c472 100644
Binary files a/test/image/baselines/gl2d_error_bars_log.png and b/test/image/baselines/gl2d_error_bars_log.png differ
diff --git a/test/image/baselines/gl2d_fonts.png b/test/image/baselines/gl2d_fonts.png
index 038bcef6f67..6465d9087c6 100644
Binary files a/test/image/baselines/gl2d_fonts.png and b/test/image/baselines/gl2d_fonts.png differ
diff --git a/test/image/baselines/gl2d_layout_image.png b/test/image/baselines/gl2d_layout_image.png
index 89a268319f9..fa45cb7793a 100644
Binary files a/test/image/baselines/gl2d_layout_image.png and b/test/image/baselines/gl2d_layout_image.png differ
diff --git a/test/image/baselines/gl2d_line_aligned.png b/test/image/baselines/gl2d_line_aligned.png
index 2d3752f23c6..84913b81e0f 100644
Binary files a/test/image/baselines/gl2d_line_aligned.png and b/test/image/baselines/gl2d_line_aligned.png differ
diff --git a/test/image/baselines/gl2d_line_dash.png b/test/image/baselines/gl2d_line_dash.png
index af3a62f6466..1b73c3f0907 100644
Binary files a/test/image/baselines/gl2d_line_dash.png and b/test/image/baselines/gl2d_line_dash.png differ
diff --git a/test/image/baselines/gl2d_line_select.png b/test/image/baselines/gl2d_line_select.png
index acdf282ae05..150c00b55a2 100644
Binary files a/test/image/baselines/gl2d_line_select.png and b/test/image/baselines/gl2d_line_select.png differ
diff --git a/test/image/baselines/gl2d_marker_size.png b/test/image/baselines/gl2d_marker_size.png
index 2aaffd39d60..563f0272edd 100644
Binary files a/test/image/baselines/gl2d_marker_size.png and b/test/image/baselines/gl2d_marker_size.png differ
diff --git a/test/image/baselines/gl2d_marker_symbols.png b/test/image/baselines/gl2d_marker_symbols.png
index f8b4b8eba58..954265506ed 100644
Binary files a/test/image/baselines/gl2d_marker_symbols.png and b/test/image/baselines/gl2d_marker_symbols.png differ
diff --git a/test/image/baselines/gl2d_multiple-traces-axes-labels.png b/test/image/baselines/gl2d_multiple-traces-axes-labels.png
index c38de480a7f..deff530274c 100644
Binary files a/test/image/baselines/gl2d_multiple-traces-axes-labels.png and b/test/image/baselines/gl2d_multiple-traces-axes-labels.png differ
diff --git a/test/image/baselines/gl2d_multiple-traces-axes.png b/test/image/baselines/gl2d_multiple-traces-axes.png
index 024f7b7578b..5c44cfc442d 100644
Binary files a/test/image/baselines/gl2d_multiple-traces-axes.png and b/test/image/baselines/gl2d_multiple-traces-axes.png differ
diff --git a/test/image/baselines/gl2d_multiple_subplots.png b/test/image/baselines/gl2d_multiple_subplots.png
index 6335bb92491..f0a814a8a6b 100644
Binary files a/test/image/baselines/gl2d_multiple_subplots.png and b/test/image/baselines/gl2d_multiple_subplots.png differ
diff --git a/test/image/baselines/gl2d_open_marker_line_width.png b/test/image/baselines/gl2d_open_marker_line_width.png
index 389948b230f..b8519424f4d 100644
Binary files a/test/image/baselines/gl2d_open_marker_line_width.png and b/test/image/baselines/gl2d_open_marker_line_width.png differ
diff --git a/test/image/baselines/gl2d_scatter-color-clustering.png b/test/image/baselines/gl2d_scatter-color-clustering.png
index 228aa2179ff..98e1e811832 100644
Binary files a/test/image/baselines/gl2d_scatter-color-clustering.png and b/test/image/baselines/gl2d_scatter-color-clustering.png differ
diff --git a/test/image/baselines/gl2d_scatter-colorscale-colorbar.png b/test/image/baselines/gl2d_scatter-colorscale-colorbar.png
index 87f05bdc541..e2ebc54e4a8 100644
Binary files a/test/image/baselines/gl2d_scatter-colorscale-colorbar.png and b/test/image/baselines/gl2d_scatter-colorscale-colorbar.png differ
diff --git a/test/image/baselines/gl2d_scatter-colorscale-points.png b/test/image/baselines/gl2d_scatter-colorscale-points.png
index 0242f8616aa..2aea7fb1d79 100644
Binary files a/test/image/baselines/gl2d_scatter-colorscale-points.png and b/test/image/baselines/gl2d_scatter-colorscale-points.png differ
diff --git a/test/image/baselines/gl2d_scatter-marker-line-colorscales.png b/test/image/baselines/gl2d_scatter-marker-line-colorscales.png
index 0de117bf3d0..ca93022e7c3 100644
Binary files a/test/image/baselines/gl2d_scatter-marker-line-colorscales.png and b/test/image/baselines/gl2d_scatter-marker-line-colorscales.png differ
diff --git a/test/image/baselines/gl2d_scatter_fill_self_next.png b/test/image/baselines/gl2d_scatter_fill_self_next.png
index 42cd181a489..41bfa5171f6 100644
Binary files a/test/image/baselines/gl2d_scatter_fill_self_next.png and b/test/image/baselines/gl2d_scatter_fill_self_next.png differ
diff --git a/test/image/baselines/gl2d_shapes_below_traces.png b/test/image/baselines/gl2d_shapes_below_traces.png
index 7eae642d04a..8c8a17c86c8 100644
Binary files a/test/image/baselines/gl2d_shapes_below_traces.png and b/test/image/baselines/gl2d_shapes_below_traces.png differ
diff --git a/test/image/baselines/gl2d_simple_inset.png b/test/image/baselines/gl2d_simple_inset.png
index b87b1d68337..c0005789be9 100644
Binary files a/test/image/baselines/gl2d_simple_inset.png and b/test/image/baselines/gl2d_simple_inset.png differ
diff --git a/test/image/baselines/gl2d_size_margins.png b/test/image/baselines/gl2d_size_margins.png
index 1cea44693ad..20d53998065 100644
Binary files a/test/image/baselines/gl2d_size_margins.png and b/test/image/baselines/gl2d_size_margins.png differ
diff --git a/test/image/baselines/gl2d_stacked_coupled_subplots.png b/test/image/baselines/gl2d_stacked_coupled_subplots.png
index 534e823812d..c67933ea7e3 100644
Binary files a/test/image/baselines/gl2d_stacked_coupled_subplots.png and b/test/image/baselines/gl2d_stacked_coupled_subplots.png differ
diff --git a/test/image/baselines/gl2d_stacked_subplots.png b/test/image/baselines/gl2d_stacked_subplots.png
index 79cef6fec93..c7d26103984 100644
Binary files a/test/image/baselines/gl2d_stacked_subplots.png and b/test/image/baselines/gl2d_stacked_subplots.png differ
diff --git a/test/image/baselines/gl2d_subplots_anchor.png b/test/image/baselines/gl2d_subplots_anchor.png
index 078e27ed403..341f440ab3b 100644
Binary files a/test/image/baselines/gl2d_subplots_anchor.png and b/test/image/baselines/gl2d_subplots_anchor.png differ
diff --git a/test/image/baselines/gl2d_tick-labels.png b/test/image/baselines/gl2d_tick-labels.png
index 437905db4ca..759baf31cfa 100644
Binary files a/test/image/baselines/gl2d_tick-labels.png and b/test/image/baselines/gl2d_tick-labels.png differ
diff --git a/test/image/mocks/gl2d_clean-number.json b/test/image/mocks/gl2d_clean-number.json
new file mode 100644
index 00000000000..6969e2d58fd
--- /dev/null
+++ b/test/image/mocks/gl2d_clean-number.json
@@ -0,0 +1,7 @@
+{
+  "data": [{
+    "type": "scattergl",
+    "x": ["1", " 2 ", "3$", "4%"],
+    "y": ["1", "   2    ", "$3", "%4"]
+  }]
+}
diff --git a/test/jasmine/tests/gl2d_click_test.js b/test/jasmine/tests/gl2d_click_test.js
index 852c543f44f..23512108888 100644
--- a/test/jasmine/tests/gl2d_click_test.js
+++ b/test/jasmine/tests/gl2d_click_test.js
@@ -534,11 +534,22 @@ describe('@gl Test hover and click interactions', function() {
 
 describe('@noCI @gl Test gl2d lasso/select:', function() {
     var mockFancy = require('@mocks/gl2d_14.json');
+    delete mockFancy.layout.xaxis.autorange;
+    delete mockFancy.layout.yaxis.autorange;
+    mockFancy.layout.xaxis.range = [-2.951309064136961, 2.0954721318818916];
+    mockFancy.layout.yaxis.range = [-0.9248866483012275, 1.3232607344525835];
+
     var mockFast = Lib.extendDeep({}, mockFancy, {
         data: [{mode: 'markers'}],
         layout: {
-            xaxis: {type: 'linear'},
-            yaxis: {type: 'linear'}
+            xaxis: {
+                type: 'linear',
+                range: [-3.869222222222223, 73.55522222222223]
+            },
+            yaxis: {
+                type: 'linear',
+                range: [-0.7402222222222222, 17.144222222222222]
+            }
         }
     });
 
diff --git a/test/jasmine/tests/gl2d_plot_interact_test.js b/test/jasmine/tests/gl2d_plot_interact_test.js
index 0a219692b1c..7ebdd5c2756 100644
--- a/test/jasmine/tests/gl2d_plot_interact_test.js
+++ b/test/jasmine/tests/gl2d_plot_interact_test.js
@@ -209,7 +209,6 @@ describe('@gl Test gl plot side effects', function() {
 
 describe('@gl Test gl2d plots', function() {
     var gd;
-
     var mock = require('@mocks/gl2d_10.json');
 
     beforeEach(function() {
@@ -255,9 +254,9 @@ describe('@gl Test gl2d plots', function() {
         var relayoutCallback = jasmine.createSpy('relayoutCallback');
 
         var originalX = [-0.3037383177570093, 5.303738317757009];
-        var originalY = [-0.5, 6.1];
-        var newX = [-0.5, 5];
-        var newY = [-1.7, 4.95];
+        var originalY = [-0.5806379476536665, 6.218528262566369];
+        var newX = [-0.5516431924882629, 5.082159624413145];
+        var newY = [-1.7947747709072441, 5.004391439312791];
         var precision = 1;
 
         Plotly.newPlot(gd, _mock)
@@ -584,8 +583,8 @@ describe('@gl Test gl2d plots', function() {
             });
         })
         .then(function() {
-            expect(gd.layout.xaxis.range).toBeCloseToArray([-7.6, 23.6], 1);
-            expect(gd.layout.yaxis.range).toBeCloseToArray([0.2, 15.8], 1);
+            expect(gd.layout.xaxis.range).toBeCloseToArray([-8.2, 24.2], 1);
+            expect(gd.layout.yaxis.range).toBeCloseToArray([-0.12, 16.1], 1);
         })
         .catch(fail)
         .then(done);
@@ -834,3 +833,103 @@ describe('@gl Test gl2d plots', function() {
         .then(done);
     });
 });
+
+describe('Test scattergl autorange:', function() {
+    afterEach(destroyGraphDiv);
+
+    describe('should return the same value as SVG scatter for ~small~ data', function() {
+        var specs = [
+            {name: 'lines+markers', fig: require('@mocks/gl2d_10.json')},
+            {name: 'bubbles', fig: require('@mocks/gl2d_12.json')},
+            {name: 'line on log axes', fig: require('@mocks/gl2d_14.json')},
+            {name: 'fill to zero', fig: require('@mocks/gl2d_axes_labels2.json')},
+            {name: 'annotations', fig: require('@mocks/gl2d_annotations.json')}
+        ];
+
+        specs.forEach(function(s) {
+            it('- case ' + s.name, function(done) {
+                var gd = createGraphDiv();
+                var glRangeX;
+                var glRangeY;
+
+                // ensure the mocks have auto-range turned on
+                var glFig = Lib.extendDeep({}, s.fig);
+                Lib.extendDeep(glFig.layout, {xaxis: {autorange: true}});
+                Lib.extendDeep(glFig.layout, {yaxis: {autorange: true}});
+
+                var svgFig = Lib.extendDeep({}, glFig);
+                svgFig.data.forEach(function(t) { t.type = 'scatter'; });
+
+                Plotly.newPlot(gd, glFig).then(function() {
+                    glRangeX = gd._fullLayout.xaxis.range;
+                    glRangeY = gd._fullLayout.yaxis.range;
+                })
+                .then(function() {
+                    return Plotly.newPlot(gd, svgFig);
+                })
+                .then(function() {
+                    expect(gd._fullLayout.xaxis.range).toBeCloseToArray(glRangeX, 'x range');
+                    expect(gd._fullLayout.yaxis.range).toBeCloseToArray(glRangeY, 'y range');
+                })
+                .catch(fail)
+                .then(done);
+            });
+        });
+    });
+
+    describe('should return the approximative values for ~big~ data', function() {
+        beforeEach(function() {
+            spyOn(ScatterGl, 'plot');
+        });
+
+        // threshold for 'fast' axis expansion routine
+        var N = 1e5;
+        var x = new Array(N);
+        var y = new Array(N);
+        var ms = new Array(N);
+
+        Lib.seedPseudoRandom();
+
+        for(var i = 0; i < N; i++) {
+            x[i] = Lib.pseudoRandom();
+            y[i] = Lib.pseudoRandom();
+            ms[i] = 10 * Lib.pseudoRandom() + 20;
+        }
+
+        it('- case scalar marker.size', function(done) {
+            var gd = createGraphDiv();
+
+            Plotly.newPlot(gd, [{
+                type: 'scattergl',
+                mode: 'markers',
+                x: x,
+                y: y,
+                marker: {size: 10}
+            }])
+            .then(function() {
+                expect(gd._fullLayout.xaxis.range).toBeCloseToArray([-0.02, 1.02], 'x range');
+                expect(gd._fullLayout.yaxis.range).toBeCloseToArray([-0.04, 1.04], 'y range');
+            })
+            .catch(fail)
+            .then(done);
+        });
+
+        it('- case array marker.size', function(done) {
+            var gd = createGraphDiv();
+
+            Plotly.newPlot(gd, [{
+                type: 'scattergl',
+                mode: 'markers',
+                x: x,
+                y: y,
+                marker: {size: ms}
+            }])
+            .then(function() {
+                expect(gd._fullLayout.xaxis.range).toBeCloseToArray([-0.05, 1.05], 'x range');
+                expect(gd._fullLayout.yaxis.range).toBeCloseToArray([-0.11, 1.11], 'y range');
+            })
+            .catch(fail)
+            .then(done);
+        });
+    });
+});
diff --git a/test/jasmine/tests/plot_api_test.js b/test/jasmine/tests/plot_api_test.js
index 0d52ac76d28..14f61d65a60 100644
--- a/test/jasmine/tests/plot_api_test.js
+++ b/test/jasmine/tests/plot_api_test.js
@@ -523,7 +523,7 @@ describe('Test plot api', function() {
             return gd;
         }
 
-        it('should trigger recalc when switching into select or lasso dragmode', function() {
+        it('should trigger replot (but not recalc) when switching into select or lasso dragmode for scattergl traces', function() {
             var gd = mock({
                 data: [{
                     type: 'scattergl',
@@ -541,8 +541,8 @@ describe('Test plot api', function() {
                 expect(subroutines.layoutReplot).not.toHaveBeenCalled();
             }
 
-            function expectRecalc() {
-                expect(gd.calcdata).toBeUndefined();
+            function expectReplot() {
+                expect(gd.calcdata).toBeDefined();
                 expect(subroutines.doModeBar).not.toHaveBeenCalled();
                 expect(subroutines.layoutReplot).toHaveBeenCalled();
             }
@@ -551,7 +551,7 @@ describe('Test plot api', function() {
             expectModeBarOnly();
 
             Plotly.relayout(mock(gd), 'dragmode', 'lasso');
-            expectRecalc();
+            expectReplot();
 
             Plotly.relayout(mock(gd), 'dragmode', 'select');
             expectModeBarOnly();
@@ -563,7 +563,7 @@ describe('Test plot api', function() {
             expectModeBarOnly();
 
             Plotly.relayout(mock(gd), 'dragmode', 'select');
-            expectRecalc();
+            expectReplot();
         });
     });