diff --git a/lib/index.js b/lib/index.js
index 39a357bac96..57e33be6c60 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -48,7 +48,8 @@ Plotly.register([
require('./ohlc'),
require('./candlestick'),
- require('./scatterpolar')
+ require('./scatterpolar'),
+ require('./scatterpolargl')
]);
// transforms
diff --git a/lib/scatterpolargl.js b/lib/scatterpolargl.js
new file mode 100644
index 00000000000..33f35606ca7
--- /dev/null
+++ b/lib/scatterpolargl.js
@@ -0,0 +1,11 @@
+/**
+* Copyright 2012-2018, Plotly, Inc.
+* All rights reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*/
+
+'use strict';
+
+module.exports = require('../src/traces/scatterpolargl');
diff --git a/package.json b/package.json
index 9b20549885d..a531c1ce0e8 100644
--- a/package.json
+++ b/package.json
@@ -57,7 +57,10 @@
"3d-view": "^2.0.0",
"@plotly/d3-sankey": "^0.5.0",
"alpha-shape": "^1.0.0",
- "color-rgba": "^1.1.1",
+ "bubleify": "^1.0.0",
+ "canvas-fit": "^1.5.0",
+ "color-normalize": "^1.0.3",
+ "color-rgba": "^2.0.0",
"convex-hull": "^1.0.3",
"country-regex": "^1.1.0",
"d3": "^3.5.12",
@@ -67,24 +70,21 @@
"fast-isnumeric": "^1.1.1",
"font-atlas-sdf": "^1.3.3",
"gl-contour2d": "^1.1.2",
- "gl-error2d": "^1.2.1",
"gl-error3d": "^1.0.6",
"gl-heatmap2d": "^1.0.3",
- "gl-line2d": "^1.4.1",
"gl-line3d": "^1.1.0",
"gl-mat4": "^1.1.2",
"gl-mesh3d": "^1.3.0",
"gl-plot2d": "^1.3.0",
"gl-plot3d": "^1.5.4",
"gl-pointcloud2d": "^1.0.0",
- "gl-scatter2d": "^1.3.2",
- "gl-scatter2d-sdf": "^1.3.11",
"gl-scatter3d": "^1.0.4",
"gl-select-box": "^1.0.1",
"gl-shader": "4.2.0",
"gl-spikes2d": "^1.0.1",
"gl-surface3d": "^1.3.1",
"has-hover": "^1.0.1",
+ "kdgrass": "^1.0.1",
"mapbox-gl": "^0.22.0",
"matrix-camera-controller": "^2.1.3",
"minify-stream": "^1.1.0",
@@ -96,12 +96,16 @@
"ndarray-homography": "^1.0.0",
"ndarray-ops": "^1.2.2",
"polybooljs": "^1.2.0",
- "regl": "^1.3.0",
+ "regl": "^1.3.1",
+ "regl-error2d": "^2.0.3",
+ "regl-line2d": "^2.1.0",
+ "regl-scatter2d": "^2.1.9",
"right-now": "^1.0.0",
"robust-orientation": "^1.1.3",
"sane-topojson": "^2.0.0",
"strongly-connected-components": "^1.0.1",
"superscript-text": "^1.0.0",
+ "svg-path-sdf": "^1.1.1",
"tinycolor2": "^1.3.0",
"topojson-client": "^2.1.0",
"webgl-context": "^2.2.0",
diff --git a/src/components/drawing/index.js b/src/components/drawing/index.js
index 0aea2fc36f0..98a64b9e334 100644
--- a/src/components/drawing/index.js
+++ b/src/components/drawing/index.js
@@ -213,6 +213,7 @@ drawing.symbolNames = [];
drawing.symbolFuncs = [];
drawing.symbolNeedLines = {};
drawing.symbolNoDot = {};
+drawing.symbolNoFill = {};
drawing.symbolList = [];
Object.keys(SYMBOLDEFS).forEach(function(k) {
@@ -231,6 +232,9 @@ Object.keys(SYMBOLDEFS).forEach(function(k) {
drawing.symbolList = drawing.symbolList.concat(
[symDef.n + 200, k + '-dot', symDef.n + 300, k + '-open-dot']);
}
+ if(symDef.noFill) {
+ drawing.symbolNoFill[symDef.n] = true;
+ }
});
var MAXSYMBOL = drawing.symbolNames.length,
// add a dot in the middle of the symbol
diff --git a/src/components/drawing/symbol_defs.js b/src/components/drawing/symbol_defs.js
index 86883414b08..45c7e3401d9 100644
--- a/src/components/drawing/symbol_defs.js
+++ b/src/components/drawing/symbol_defs.js
@@ -355,7 +355,8 @@ module.exports = {
return 'M0,' + rc + 'V-' + rc + 'M' + rc + ',0H-' + rc;
},
needLine: true,
- noDot: true
+ noDot: true,
+ noFill: true
},
'x-thin': {
n: 34,
@@ -365,7 +366,8 @@ module.exports = {
'M' + rx + ',-' + rx + 'L-' + rx + ',' + rx;
},
needLine: true,
- noDot: true
+ noDot: true,
+ noFill: true
},
asterisk: {
n: 35,
@@ -377,7 +379,8 @@ module.exports = {
'M' + rs + ',-' + rs + 'L-' + rs + ',' + rs;
},
needLine: true,
- noDot: true
+ noDot: true,
+ noFill: true
},
hash: {
n: 36,
@@ -389,7 +392,8 @@ module.exports = {
'M' + r2 + ',' + r1 + 'H-' + r2 +
'm0,-' + r2 + 'H' + r2;
},
- needLine: true
+ needLine: true,
+ noFill: true
},
'y-up': {
n: 37,
@@ -400,7 +404,8 @@ module.exports = {
return 'M-' + x + ',' + y1 + 'L0,0M' + x + ',' + y1 + 'L0,0M0,-' + y0 + 'L0,0';
},
needLine: true,
- noDot: true
+ noDot: true,
+ noFill: true
},
'y-down': {
n: 38,
@@ -411,7 +416,8 @@ module.exports = {
return 'M-' + x + ',-' + y1 + 'L0,0M' + x + ',-' + y1 + 'L0,0M0,' + y0 + 'L0,0';
},
needLine: true,
- noDot: true
+ noDot: true,
+ noFill: true
},
'y-left': {
n: 39,
@@ -422,7 +428,8 @@ module.exports = {
return 'M' + x1 + ',' + y + 'L0,0M' + x1 + ',-' + y + 'L0,0M-' + x0 + ',0L0,0';
},
needLine: true,
- noDot: true
+ noDot: true,
+ noFill: true
},
'y-right': {
n: 40,
@@ -433,7 +440,8 @@ module.exports = {
return 'M-' + x1 + ',' + y + 'L0,0M-' + x1 + ',-' + y + 'L0,0M' + x0 + ',0L0,0';
},
needLine: true,
- noDot: true
+ noDot: true,
+ noFill: true
},
'line-ew': {
n: 41,
@@ -442,7 +450,8 @@ module.exports = {
return 'M' + rc + ',0H-' + rc;
},
needLine: true,
- noDot: true
+ noDot: true,
+ noFill: true
},
'line-ns': {
n: 42,
@@ -451,7 +460,8 @@ module.exports = {
return 'M0,' + rc + 'V-' + rc;
},
needLine: true,
- noDot: true
+ noDot: true,
+ noFill: true
},
'line-ne': {
n: 43,
@@ -460,7 +470,8 @@ module.exports = {
return 'M' + rx + ',-' + rx + 'L-' + rx + ',' + rx;
},
needLine: true,
- noDot: true
+ noDot: true,
+ noFill: true
},
'line-nw': {
n: 44,
@@ -469,6 +480,7 @@ module.exports = {
return 'M' + rx + ',' + rx + 'L-' + rx + ',-' + rx;
},
needLine: true,
- noDot: true
+ noDot: true,
+ noFill: true
}
};
diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js
index 4c606c3bcba..efbaf07e306 100644
--- a/src/components/fx/hover.js
+++ b/src/components/fx/hover.js
@@ -519,7 +519,7 @@ function createHoverText(hoverData, opts, gd) {
var i, traceHoverinfo;
for(i = 0; i < hoverData.length; i++) {
traceHoverinfo = hoverData[i].hoverinfo || hoverData[i].trace.hoverinfo;
- var parts = traceHoverinfo.split('+');
+ var parts = Array.isArray(traceHoverinfo) ? traceHoverinfo : traceHoverinfo.split('+');
if(parts.indexOf('all') === -1 &&
parts.indexOf(hovermode) === -1) {
showCommonLabel = false;
@@ -1077,8 +1077,9 @@ function cleanPoint(d, hovermode) {
}
var infomode = d.hoverinfo || d.trace.hoverinfo;
+
if(infomode !== 'all') {
- infomode = infomode.split('+');
+ infomode = Array.isArray(infomode) ? infomode : infomode.split('+');
if(infomode.indexOf('x') === -1) d.xLabel = undefined;
if(infomode.indexOf('y') === -1) d.yLabel = undefined;
if(infomode.indexOf('z') === -1) d.zLabel = undefined;
diff --git a/src/constants/gl2d_markers.js b/src/constants/gl2d_markers.js
deleted file mode 100644
index dc0720cf091..00000000000
--- a/src/constants/gl2d_markers.js
+++ /dev/null
@@ -1,132 +0,0 @@
-/**
-* Copyright 2012-2018, Plotly, Inc.
-* All rights reserved.
-*
-* This source code is licensed under the MIT license found in the
-* LICENSE file in the root directory of this source tree.
-*/
-
-
-'use strict';
-
-var extendFlat = require('../lib/extend').extendFlat;
-
-var symbolsWithOpenSupport = {
- 'circle': {
- unicode: '●'
- },
- 'square': {
- unicode: '■'
- },
- 'diamond': {
- unicode: '◆'
- },
- 'cross': {
- unicode: '✚'
- },
- 'x': {
- unicode: '❌'
- },
- 'triangle-up': {
- unicode: '▲'
- },
- 'triangle-down': {
- unicode: '▼'
- },
- 'triangle-left': {
- unicode: '◄'
- },
- 'triangle-right': {
- unicode: '►'
- },
- 'triangle-ne': {
- unicode: '◥'
- },
- 'triangle-nw': {
- unicode: '◤'
- },
- 'triangle-se': {
- unicode: '◢'
- },
- 'triangle-sw': {
- unicode: '◣'
- },
- 'pentagon': {
- unicode: '⬟'
- },
- 'hexagon': {
- unicode: '⬢'
- },
- 'hexagon2': {
- unicode: '⬣'
- },
- 'star': {
- unicode: '★'
- },
- 'diamond-tall': {
- unicode: '♦'
- },
- 'bowtie': {
- unicode: '⧓'
- },
- 'diamond-x': {
- unicode: '❖'
- },
- 'cross-thin': {
- unicode: '+',
- noBorder: true
- },
- 'asterisk': {
- unicode: '✳',
- noBorder: true
- },
- 'y-up': {
- unicode: '⅄',
- noBorder: true
- },
- 'y-down': {
- unicode: 'Y',
- noBorder: true
- },
- 'line-ew': {
- unicode: '─',
- noBorder: true
- },
- 'line-ns': {
- unicode: '│',
- noBorder: true
- }
-};
-
-var openSymbols = {};
-var keys = Object.keys(symbolsWithOpenSupport);
-
-for(var i = 0; i < keys.length; i++) {
- var k = keys[i];
- openSymbols[k + '-open'] = extendFlat({}, symbolsWithOpenSupport[k]);
-}
-
-var otherSymbols = {
- 'circle-cross-open': {
- unicode: '⨁',
- noFill: true
- },
- 'circle-x-open': {
- unicode: '⨂',
- noFill: true
- },
- 'square-cross-open': {
- unicode: '⊞',
- noFill: true
- },
- 'square-x-open': {
- unicode: '⊠',
- noFill: true
- }
-};
-
-module.exports = extendFlat({},
- symbolsWithOpenSupport,
- openSymbols,
- otherSymbols
-);
diff --git a/src/fonts/ploticon/config.json b/src/fonts/ploticon/config.json
index 851669be315..6bdb659f75d 100644
--- a/src/fonts/ploticon/config.json
+++ b/src/fonts/ploticon/config.json
@@ -87,7 +87,7 @@
"width": 1500
},
"search": [
- "tooltip_basic"
+ "tooltip_basic"
]
},
{
diff --git a/src/lib/gl_format_color.js b/src/lib/gl_format_color.js
index 2607b99ea07..e725613e2d3 100644
--- a/src/lib/gl_format_color.js
+++ b/src/lib/gl_format_color.js
@@ -10,7 +10,7 @@
'use strict';
var isNumeric = require('fast-isnumeric');
-var rgba = require('color-rgba');
+var rgba = require('color-normalize');
var Colorscale = require('../components/colorscale');
var colorDflt = require('../components/color/attributes').defaultLine;
@@ -59,6 +59,7 @@ function formatColor(containerIn, opacityIn, len) {
if(isArrayColorIn) {
getColor = function(c, i) {
+ // FIXME: there is double work, considering that sclFunc does the opposite
return c[i] === undefined ? colorDfltRgba : rgba(sclFunc(c[i]));
};
}
diff --git a/src/lib/str2rgbarray.js b/src/lib/str2rgbarray.js
index 9b9f2590447..ed7be8c1df5 100644
--- a/src/lib/str2rgbarray.js
+++ b/src/lib/str2rgbarray.js
@@ -9,11 +9,11 @@
'use strict';
-var rgba = require('color-rgba');
+var rgba = require('color-normalize');
function str2RgbaArray(color) {
- var colorOut = rgba(color);
- return colorOut.length ? colorOut : [0, 0, 0, 1];
+ if(!color) return [0, 0, 0, 1];
+ return rgba(color);
}
module.exports = str2RgbaArray;
diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js
index 356ebd484aa..9296a02db31 100644
--- a/src/plot_api/plot_api.js
+++ b/src/plot_api/plot_api.js
@@ -223,16 +223,11 @@ Plotly.plot = function(gd, data, layout, config) {
'left': 0,
'width': '100%',
'height': '100%',
- 'overflow': 'visible'
+ 'overflow': 'visible',
+ 'pointer-events': 'none'
})
.attr('width', fullLayout.width)
.attr('height', fullLayout.height);
-
- fullLayout._glcanvas.filter(function(d) {
- return !d.pick;
- }).style({
- 'pointer-events': 'none'
- });
}
return Lib.syncOrAsync([
@@ -2817,6 +2812,7 @@ function makePlotFramework(gd) {
// FIXME: parcoords reuses this object, not the best pattern
fullLayout._glcontainer = fullLayout._paperdiv.selectAll('.gl-container')
.data([{}]);
+
fullLayout._glcontainer.enter().append('div')
.classed('gl-container', true);
diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js
index b82041d6f8b..18a5a807959 100644
--- a/src/plot_api/subroutines.js
+++ b/src/plot_api/subroutines.js
@@ -485,7 +485,6 @@ exports.doModeBar = function(gd) {
if(updateFx) updateFx(fullLayout);
}
-
return Plots.previousPromises(gd);
};
diff --git a/src/plots/cartesian/dragbox.js b/src/plots/cartesian/dragbox.js
index 044e45be39e..6693e57b205 100644
--- a/src/plots/cartesian/dragbox.js
+++ b/src/plots/cartesian/dragbox.js
@@ -746,7 +746,9 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
}
// don't scale at all if neither axis is scalable here
- if(!xScaleFactor2 && !yScaleFactor2) continue;
+ if(!xScaleFactor2 && !yScaleFactor2) {
+ continue;
+ }
// but if only one is, reset the other axis scaling
if(!xScaleFactor2) xScaleFactor2 = 1;
diff --git a/src/plots/cartesian/index.js b/src/plots/cartesian/index.js
index 7b7c065281f..5b1fcf4dd6a 100644
--- a/src/plots/cartesian/index.js
+++ b/src/plots/cartesian/index.js
@@ -16,6 +16,7 @@ var getModuleCalcData = require('../get_data').getModuleCalcData;
var axisIds = require('./axis_ids');
var constants = require('./constants');
+var xmlnsNamespaces = require('../../constants/xmlns_namespaces');
exports.name = 'cartesian';
@@ -209,7 +210,7 @@ function plotOne(gd, plotinfo, cdSubplot, transitionOpts, makeOnCompleteCallback
// plot all traces of this type on this subplot at once
var cdModule = getModuleCalcData(cdSubplot, _module);
- _module.plot(gd, plotinfo, cdModule, transitionOpts, makeOnCompleteCallback);
+ if(_module.plot) _module.plot(gd, plotinfo, cdModule, transitionOpts, makeOnCompleteCallback);
}
}
@@ -217,13 +218,14 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
var oldModules = oldFullLayout._modules || [],
newModules = newFullLayout._modules || [];
- var hadScatter, hasScatter, i;
+ var hadScatter, hasScatter, hadGl, hasGl, i, oldPlots, ids, subplotInfo;
+
for(i = 0; i < oldModules.length; i++) {
if(oldModules[i].name === 'scatter') {
hadScatter = true;
- break;
}
+ break;
}
for(i = 0; i < newModules.length; i++) {
@@ -233,12 +235,26 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
}
}
+ for(i = 0; i < oldModules.length; i++) {
+ if(oldModules[i].name === 'scattergl') {
+ hadGl = true;
+ }
+ break;
+ }
+
+ for(i = 0; i < newModules.length; i++) {
+ if(newModules[i].name === 'scattergl') {
+ hasGl = true;
+ break;
+ }
+ }
+
if(hadScatter && !hasScatter) {
- var oldPlots = oldFullLayout._plots,
- ids = Object.keys(oldPlots || {});
+ oldPlots = oldFullLayout._plots;
+ ids = Object.keys(oldPlots || {});
for(i = 0; i < ids.length; i++) {
- var subplotInfo = oldPlots[ids[i]];
+ subplotInfo = oldPlots[ids[i]];
if(subplotInfo.plot) {
subplotInfo.plot.select('g.scatterlayer')
@@ -253,6 +269,19 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
.remove();
}
+ if(hadGl && !hasGl) {
+ oldPlots = oldFullLayout._plots;
+ ids = Object.keys(oldPlots || {});
+
+ for(i = 0; i < ids.length; i++) {
+ subplotInfo = oldPlots[ids[i]];
+
+ if(subplotInfo._scene) {
+ subplotInfo._scene.destroy();
+ }
+ }
+ }
+
var oldSubplotList = oldFullLayout._subplots || {};
var newSubplotList = newFullLayout._subplots || {xaxis: [], yaxis: []};
@@ -304,7 +333,6 @@ exports.drawFramework = function(gd) {
plotinfo.overlays = [];
makeSubplotLayer(plotinfo);
-
// fill in list of overlay subplots
if(plotinfo.mainplot) {
var mainplot = fullLayout._plots[plotinfo.mainplot];
@@ -496,3 +524,28 @@ function joinLayer(parent, nodeType, className, dataVal) {
return layer;
}
+
+exports.toSVG = function(gd) {
+ var imageRoot = gd._fullLayout._glimages;
+ var root = d3.select(gd).selectAll('.svg-container');
+ var canvases = root.filter(function(d, i) {return i === root.size() - 1;})
+ .selectAll('.gl-canvas-context, .gl-canvas-focus');
+
+ function canvasToImage() {
+ var canvas = this;
+ var imageData = canvas.toDataURL('image/png');
+ var image = imageRoot.append('svg:image');
+
+ image.attr({
+ xmlns: xmlnsNamespaces.svg,
+ 'xlink:href': imageData,
+ preserveAspectRatio: 'none',
+ x: 0,
+ y: 0,
+ width: canvas.width,
+ height: canvas.height
+ });
+ }
+
+ canvases.each(canvasToImage);
+};
diff --git a/src/plots/cartesian/select.js b/src/plots/cartesian/select.js
index 55bcd1a958a..92837250622 100644
--- a/src/plots/cartesian/select.js
+++ b/src/plots/cartesian/select.js
@@ -14,6 +14,7 @@ var polygon = require('../../lib/polygon');
var throttle = require('../../lib/throttle');
var color = require('../../components/color');
var makeEventData = require('../../components/fx/helpers').makeEventData;
+var Fx = require('../../components/fx');
var axes = require('./axes');
var constants = require('./constants');
@@ -62,12 +63,11 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
if(mode === 'lasso') {
filterPoly = filteredPolygon([[x0, y0]], constants.BENDPX);
}
-
- var outlines = zoomLayer.selectAll('path.select-outline').data([1, 2]);
+ var outlines = zoomLayer.selectAll('path.select-outline-' + plotinfo.id).data([1, 2]);
outlines.enter()
.append('path')
- .attr('class', function(d) { return 'select-outline select-outline-' + d; })
+ .attr('class', function(d) { return 'select-outline select-outline-' + d + ' select-outline-' + plotinfo.id; })
.attr('transform', 'translate(' + xs + ', ' + ys + ')')
.attr('d', path0 + 'Z');
@@ -148,7 +148,7 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
}
};
} else {
- fillRangeItems = function(eventData, currentPolygon, filterPoly) {
+ fillRangeItems = function(eventData, poly, filterPoly) {
var dataPts = eventData.lassoPoints = {};
for(i = 0; i < allAxes.length; i++) {
@@ -225,7 +225,8 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
var ppts = mergedPolygons[i];
paths.push(ppts.join('L') + 'L' + ppts[0]);
}
- outlines.attr('d', 'M' + paths.join('M') + 'Z');
+ outlines
+ .attr('d', 'M' + paths.join('M') + 'Z');
throttle.throttle(
throttleID,
@@ -233,14 +234,15 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
function() {
selection = [];
- var traceSelections = [], traceSelection;
+ var thisSelection, traceSelections = [], traceSelection;
for(i = 0; i < searchTraces.length; i++) {
searchInfo = searchTraces[i];
traceSelection = searchInfo.selectPoints(searchInfo, testPoly);
traceSelections.push(traceSelection);
- var thisSelection = fillSelectionItem(traceSelection, searchInfo);
+ thisSelection = fillSelectionItem(traceSelection, searchInfo);
+
if(selection.length) {
for(var j = 0; j < thisSelection.length; j++) {
selection.push(thisSelection[j]);
@@ -257,7 +259,7 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
);
};
- dragOptions.clickFn = function(numClicks) {
+ dragOptions.clickFn = function(numClicks, evt) {
corners.remove();
throttle.done(throttleID).then(function() {
@@ -278,6 +280,8 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
// but in case anyone depends on it we don't want to break it now.
gd.emit('plotly_selected', undefined);
}
+
+ Fx.click(gd, evt);
});
};
@@ -319,8 +323,8 @@ function updateSelectedState(gd, searchTraces, eventData) {
var fullData = pt.fullData;
if(pt.pointIndices) {
- data.selectedpoints = data.selectedpoints.concat(pt.pointIndices);
- fullData.selectedpoints = fullData.selectedpoints.concat(pt.pointIndices);
+ [].push.apply(data.selectedpoints, pt.pointIndices);
+ [].push.apply(fullData.selectedpoints, pt.pointIndices);
} else {
data.selectedpoints.push(pt.pointIndex);
fullData.selectedpoints.push(pt.pointIndex);
@@ -332,6 +336,11 @@ function updateSelectedState(gd, searchTraces, eventData) {
trace = searchTraces[i].cd[0].trace;
delete trace.selectedpoints;
delete trace._input.selectedpoints;
+
+ // delete scattergl selection
+ if(searchTraces[i].cd[0].t && searchTraces[i].cd[0].t.scene) {
+ searchTraces[i].cd[0].t.scene.clearSelect();
+ }
}
}
diff --git a/src/plots/geo/geo.js b/src/plots/geo/geo.js
index c0362781854..6aabf11a77f 100644
--- a/src/plots/geo/geo.js
+++ b/src/plots/geo/geo.js
@@ -140,7 +140,7 @@ proto.update = function(geoCalcData, fullLayout) {
this.updateDims(fullLayout, geoLayout);
this.updateFx(fullLayout, geoLayout);
- Plots.generalUpdatePerTraceModule(this, geoCalcData, geoLayout);
+ Plots.generalUpdatePerTraceModule(this.graphDiv, this, geoCalcData, geoLayout);
var scatterLayer = this.layers.frontplot.select('.scatterlayer');
this.dataPoints.point = scatterLayer.selectAll('.point');
diff --git a/src/plots/plots.js b/src/plots/plots.js
index a54052cf16e..a1736502e59 100644
--- a/src/plots/plots.js
+++ b/src/plots/plots.js
@@ -49,7 +49,6 @@ plots.computeAPICommandBindings = commandModule.computeAPICommandBindings;
plots.manageCommandObserver = commandModule.manageCommandObserver;
plots.hasSimpleAPICommandBindings = commandModule.hasSimpleAPICommandBindings;
-
// in some cases the browser doesn't seem to know how big
// the text is at first, so it needs to draw it,
// then wait a little, then draw it again
@@ -586,7 +585,6 @@ plots.createTransitionData = function(gd) {
// or trace has a category
plots._hasPlotType = function(category) {
// check plot
-
var basePlotModules = this._basePlotModules || [];
var i;
@@ -701,10 +699,6 @@ plots.linkSubplots = function(newFullData, newFullLayout, oldFullData, oldFullLa
if(oldSubplot) {
plotinfo = newSubplots[id] = oldSubplot;
- if(plotinfo._scene2d) {
- plotinfo._scene2d.updateRefs(newFullLayout);
- }
-
if(plotinfo.xaxis.layer !== xaxis.layer) {
plotinfo.xlines.attr('d', null);
plotinfo.xaxislayer.selectAll('*').remove();
@@ -928,7 +922,6 @@ plots.supplyDataDefaults = function(dataIn, dataOut, layout, fullLayout) {
}
}
else {
-
// add identify refs for consistency with transformed traces
fullTrace._fullInput = fullTrace;
fullTrace._expandedInput = fullTrace;
@@ -1122,7 +1115,7 @@ plots.supplyTraceDefaults = function(traceIn, colorIndex, layout, traceInIndex)
traceOut.visible = !!traceOut.visible;
}
- if(_module && _module.selectPoints && traceOut.type !== 'scattergl') {
+ if(_module && _module.selectPoints) {
coerce('selectedpoints');
}
@@ -1417,7 +1410,6 @@ plots.supplyLayoutModuleDefaults = function(layoutIn, layoutOut, fullData, trans
// Remove all plotly attributes from a div so it can be replotted fresh
// TODO: these really need to be encapsulated into a much smaller set...
plots.purge = function(gd) {
-
// note: we DO NOT remove _context because it doesn't change when we insert
// a new plot, and may have been set outside of our scope.
@@ -2436,10 +2428,10 @@ plots.rehover = function(gd) {
}
};
-plots.generalUpdatePerTraceModule = function(subplot, subplotCalcData, subplotLayout) {
- var traceHashOld = subplot.traceHash,
- traceHash = {},
- i;
+plots.generalUpdatePerTraceModule = function(gd, subplot, subplotCalcData, subplotLayout) {
+ var traceHashOld = subplot.traceHash;
+ var traceHash = {};
+ var i;
// build up moduleName -> calcData hash
for(i = 0; i < subplotCalcData.length; i++) {
@@ -2458,7 +2450,6 @@ plots.generalUpdatePerTraceModule = function(subplot, subplotCalcData, subplotLa
// plot method is called so that it is properly
// removed from the DOM.
for(var moduleNameOld in traceHashOld) {
-
if(!traceHash[moduleNameOld]) {
var fakeCalcTrace = traceHashOld[moduleNameOld][0],
fakeTrace = fakeCalcTrace[0].trace;
@@ -2473,7 +2464,7 @@ plots.generalUpdatePerTraceModule = function(subplot, subplotCalcData, subplotLa
var moduleCalcData = traceHash[moduleName];
var _module = moduleCalcData[0][0].trace._module;
- _module.plot(subplot, Lib.filterVisible(moduleCalcData), subplotLayout);
+ _module.plot(gd, subplot, Lib.filterVisible(moduleCalcData), subplotLayout);
}
// update moduleName -> calcData hash
diff --git a/src/plots/polar/index.js b/src/plots/polar/index.js
index c0f134f52fe..9c8695245f6 100644
--- a/src/plots/polar/index.js
+++ b/src/plots/polar/index.js
@@ -79,5 +79,6 @@ module.exports = {
layoutAttributes: require('./layout_attributes'),
supplyLayoutDefaults: require('./layout_defaults'),
plot: plot,
- clean: clean
+ clean: clean,
+ toSVG: require('../cartesian').toSVG
};
diff --git a/src/plots/polar/polar.js b/src/plots/polar/polar.js
index d1cad6e1f62..7db125ce6bc 100644
--- a/src/plots/polar/polar.js
+++ b/src/plots/polar/polar.js
@@ -85,7 +85,7 @@ proto.plot = function(polarCalcData, fullLayout) {
_this.updateLayers(fullLayout, polarLayout);
_this.updateLayout(fullLayout, polarLayout);
- Plots.generalUpdatePerTraceModule(_this, polarCalcData, polarLayout);
+ Plots.generalUpdatePerTraceModule(_this.gd, _this, polarCalcData, polarLayout);
_this.updateFx(fullLayout, polarLayout);
};
@@ -837,7 +837,7 @@ proto.updateRadialDrag = function(fullLayout, polarLayout) {
var _module = moduleCalcData[0][0].trace._module;
var polarLayoutNow = gd._fullLayout[_this.id];
- _module.plot(_this, moduleCalcDataVisible, polarLayoutNow);
+ _module.plot(gd, _this, moduleCalcDataVisible, polarLayoutNow);
if(!Registry.traceIs(k, 'gl')) {
for(var i = 0; i < moduleCalcDataVisible.length; i++) {
@@ -962,7 +962,7 @@ proto.updateAngularDrag = function(fullLayout, polarLayout) {
var _module = moduleCalcData[0][0].trace._module;
var polarLayoutNow = gd._fullLayout[_this.id];
- _module.plot(_this, moduleCalcDataVisible, polarLayoutNow);
+ _module.plot(gd, _this, moduleCalcDataVisible, polarLayoutNow);
}
}
}
diff --git a/src/plots/ternary/ternary.js b/src/plots/ternary/ternary.js
index 36b83231edf..cf2b607e824 100644
--- a/src/plots/ternary/ternary.js
+++ b/src/plots/ternary/ternary.js
@@ -64,7 +64,7 @@ proto.plot = function(ternaryCalcData, fullLayout) {
_this.updateLayers(ternaryLayout);
_this.adjustLayout(ternaryLayout, graphSize);
- Plots.generalUpdatePerTraceModule(_this, ternaryCalcData, ternaryLayout);
+ Plots.generalUpdatePerTraceModule(_this.graphDiv, _this, ternaryCalcData, ternaryLayout);
_this.layers.plotbg.select('path').call(Color.fill, ternaryLayout.bgcolor);
};
diff --git a/src/traces/choropleth/plot.js b/src/traces/choropleth/plot.js
index c88df083ac2..e0579accf3a 100644
--- a/src/traces/choropleth/plot.js
+++ b/src/traces/choropleth/plot.js
@@ -17,7 +17,7 @@ var getTopojsonFeatures = require('../../lib/topojson_utils').getTopojsonFeature
var locationToFeature = require('../../lib/geo_location_utils').locationToFeature;
var style = require('./style');
-module.exports = function plot(geo, calcData) {
+module.exports = function plot(gd, geo, calcData) {
for(var i = 0; i < calcData.length; i++) {
calcGeoJSON(calcData[i], geo.topojson);
}
@@ -45,7 +45,7 @@ module.exports = function plot(geo, calcData) {
paths.exit().remove();
// call style here within topojson request callback
- style(geo.graphDiv, calcTrace);
+ style(gd, calcTrace);
});
};
diff --git a/src/traces/parcoords/attributes.js b/src/traces/parcoords/attributes.js
index b9968d029b1..1713b722d86 100644
--- a/src/traces/parcoords/attributes.js
+++ b/src/traces/parcoords/attributes.js
@@ -106,6 +106,7 @@ module.exports = {
line: extendFlat(
// the default autocolorscale isn't quite usable for parcoords due to context ambiguity around 0 (grey, off-white)
+
// autocolorscale therefore defaults to false too, to avoid being overridden by the blue-white-red autocolor palette
extendDeepAll(
colorAttributes('line', 'calc'),
@@ -123,7 +124,6 @@ module.exports = {
'The default value is false, so that `parcoords` colorscale can default to `Viridis`.'
].join(' ')
}
-
}
),
diff --git a/src/traces/parcoords/base_plot.js b/src/traces/parcoords/base_plot.js
index 4b8ab7379d0..25fbfd48b29 100644
--- a/src/traces/parcoords/base_plot.js
+++ b/src/traces/parcoords/base_plot.js
@@ -33,7 +33,6 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
};
exports.toSVG = function(gd) {
-
var imageRoot = gd._fullLayout._glimages;
var root = d3.select(gd).selectAll('.svg-container');
var canvases = root.filter(function(d, i) {return i === root.size() - 1;})
@@ -47,11 +46,11 @@ exports.toSVG = function(gd) {
image.attr({
xmlns: xmlnsNamespaces.svg,
'xlink:href': imageData,
+ preserveAspectRatio: 'none',
x: 0,
y: 0,
width: canvas.width,
- height: canvas.height,
- preserveAspectRatio: 'none'
+ height: canvas.height
});
}
diff --git a/src/traces/parcoords/lines.js b/src/traces/parcoords/lines.js
index 62b47591c4d..fb1072780d8 100644
--- a/src/traces/parcoords/lines.js
+++ b/src/traces/parcoords/lines.js
@@ -55,7 +55,8 @@ function renderBlock(regl, glAes, renderState, blockLineCount, sampleCount, item
item.offset = sectionVertexCount * blockNumber * blockLineCount;
item.count = sectionVertexCount * count;
if(blockNumber === 0) {
- window.cancelAnimationFrame(renderState.currentRafs[rafKey]); // stop drawing possibly stale glyphs before clearing
+ // stop drawing possibly stale glyphs before clearing
+ window.cancelAnimationFrame(renderState.currentRafs[rafKey]);
delete renderState.currentRafs[rafKey];
clear(regl, item.scissorX, item.scissorY, item.scissorWidth, item.viewBoxSize[1]);
}
@@ -353,6 +354,7 @@ module.exports = function(canvasGL, d, scatter) {
colorClamp: colorClamp,
scatter: scatter || 0,
+
scissorX: (I === leftmost ? 0 : x + overdrag) + (model.pad.l - overdrag) + model.layoutWidth * domain.x[0],
scissorWidth: (I === rightmost ? canvasWidth - x + overdrag : panelSizeX + 0.5) + (I === leftmost ? x + overdrag : 0),
scissorY: y + model.pad.b + model.layoutHeight * domain.y[0],
@@ -431,6 +433,7 @@ module.exports = function(canvasGL, d, scatter) {
}
function destroy() {
+ canvasGL.style['pointer-events'] = 'none';
paletteTexture.destroy();
}
diff --git a/src/traces/parcoords/parcoords.js b/src/traces/parcoords/parcoords.js
index 317ada1e08f..74f1a31f111 100644
--- a/src/traces/parcoords/parcoords.js
+++ b/src/traces/parcoords/parcoords.js
@@ -305,6 +305,7 @@ module.exports = function(root, svg, parcoordsLineLayers, styledData, layout, ca
.filter(function(d) {
return d.pick;
})
+ .style('pointer-events', 'auto')
.on('mousemove', function(d) {
if(linePickActive && d.lineLayer && callbacks && callbacks.hover) {
var event = d3.event;
diff --git a/src/traces/parcoords/plot.js b/src/traces/parcoords/plot.js
index 71b3e7860c2..6d18d227bfc 100644
--- a/src/traces/parcoords/plot.js
+++ b/src/traces/parcoords/plot.js
@@ -12,7 +12,6 @@ var parcoords = require('./parcoords');
var createRegl = require('regl');
module.exports = function plot(gd, cdparcoords) {
-
var fullLayout = gd._fullLayout;
var svg = fullLayout._toppaper;
var root = fullLayout._paperdiv;
diff --git a/src/traces/pointcloud/attributes.js b/src/traces/pointcloud/attributes.js
index 30570bb4cdc..df1e43900ba 100644
--- a/src/traces/pointcloud/attributes.js
+++ b/src/traces/pointcloud/attributes.js
@@ -8,7 +8,7 @@
'use strict';
-var scatterglAttrs = require('../scattergl/attributes');
+var scatterglAttrs = require('../scatter/attributes');
module.exports = {
x: scatterglAttrs.x,
diff --git a/src/traces/scattergeo/plot.js b/src/traces/scattergeo/plot.js
index f4fbacb15eb..9bba530371e 100644
--- a/src/traces/scattergeo/plot.js
+++ b/src/traces/scattergeo/plot.js
@@ -19,7 +19,7 @@ var geoJsonUtils = require('../../lib/geojson_utils');
var subTypes = require('../scatter/subtypes');
var style = require('./style');
-module.exports = function plot(geo, calcData) {
+module.exports = function plot(gd, geo, calcData) {
for(var i = 0; i < calcData.length; i++) {
calcGeoJSON(calcData[i], geo.topojson);
}
@@ -79,7 +79,7 @@ module.exports = function plot(geo, calcData) {
}
// call style here within topojson request callback
- style(geo.graphDiv, calcTrace);
+ style(gd, calcTrace);
});
};
diff --git a/src/traces/scattergl/attributes.js b/src/traces/scattergl/attributes.js
index 8e2b18e8a4c..0c69b843c0a 100644
--- a/src/traces/scattergl/attributes.js
+++ b/src/traces/scattergl/attributes.js
@@ -12,7 +12,6 @@ var scatterAttrs = require('../scatter/attributes');
var colorAttributes = require('../../components/colorscale/color_attributes');
var DASHES = require('../../constants/gl2d_dashes');
-var MARKERS = require('../../constants/gl2d_markers');
var extendFlat = require('../../lib/extend').extendFlat;
var overrideAll = require('../../plot_api/edit_types').overrideAll;
@@ -58,14 +57,7 @@ var attrs = module.exports = overrideAll({
}
},
marker: extendFlat({}, colorAttributes('marker'), {
- symbol: {
- valType: 'enumerated',
- values: Object.keys(MARKERS),
- dflt: 'circle',
- arrayOk: true,
- role: 'style',
- description: 'Sets the marker symbol type.'
- },
+ symbol: scatterMarkerAttrs.symbol,
size: scatterMarkerAttrs.size,
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
@@ -78,11 +70,18 @@ var attrs = module.exports = overrideAll({
})
}),
connectgaps: scatterAttrs.connectgaps,
- fill: extendFlat({}, scatterAttrs.fill, {
- values: ['none', 'tozeroy', 'tozerox']
- }),
+ fill: scatterAttrs.fill,
fillcolor: scatterAttrs.fillcolor,
+ hoveron: scatterAttrs.hoveron,
+
+ selected: {
+ marker: scatterAttrs.selected.marker
+ },
+ unselected: {
+ marker: scatterAttrs.unselected.marker
+ },
+
error_y: scatterAttrs.error_y,
error_x: scatterAttrs.error_x
}, 'calc', 'nested');
diff --git a/src/traces/scattergl/calc.js b/src/traces/scattergl/calc.js
deleted file mode 100644
index 2cc5238b8d1..00000000000
--- a/src/traces/scattergl/calc.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
-* Copyright 2012-2018, Plotly, Inc.
-* All rights reserved.
-*
-* This source code is licensed under the MIT license found in the
-* LICENSE file in the root directory of this source tree.
-*/
-
-
-'use strict';
-
-var Axes = require('../../plots/cartesian/axes');
-var arraysToCalcdata = require('../scatter/arrays_to_calcdata');
-var calcColorscales = require('../scatter/colorscale_calc');
-
-module.exports = function calc(gd, trace) {
- var dragmode = gd._fullLayout.dragmode;
- var cd;
-
- if(dragmode === 'lasso' || dragmode === 'select') {
- var xa = Axes.getFromId(gd, trace.xaxis || 'x');
- var ya = Axes.getFromId(gd, trace.yaxis || 'y');
-
- var x = xa.makeCalcdata(trace, 'x');
- var y = ya.makeCalcdata(trace, 'y');
-
- var serieslen = Math.min(x.length, y.length), i;
-
- // create the "calculated data" to plot
- cd = new Array(serieslen);
-
- for(i = 0; i < serieslen; i++) {
- cd[i] = {x: x[i], y: y[i]};
- }
- } else {
- cd = [{x: false, y: false, trace: trace, t: {}}];
- arraysToCalcdata(cd, trace);
- }
-
- calcColorscales(trace);
-
- return cd;
-};
diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js
deleted file mode 100644
index 4796a95145a..00000000000
--- a/src/traces/scattergl/convert.js
+++ /dev/null
@@ -1,768 +0,0 @@
-/**
-* Copyright 2012-2018, Plotly, Inc.
-* All rights reserved.
-*
-* This source code is licensed under the MIT license found in the
-* LICENSE file in the root directory of this source tree.
-*/
-
-
-'use strict';
-
-var createScatter = require('gl-scatter2d');
-var createFancyScatter = require('gl-scatter2d-sdf');
-var createLine = require('gl-line2d');
-var createError = require('gl-error2d');
-var isNumeric = require('fast-isnumeric');
-
-var Lib = require('../../lib');
-var Axes = require('../../plots/cartesian/axes');
-var autoType = require('../../plots/cartesian/axis_autotype');
-var ErrorBars = require('../../components/errorbars');
-var str2RGBArray = require('../../lib/str2rgbarray');
-var truncate = require('../../lib/typed_array_truncate');
-var formatColor = require('../../lib/gl_format_color');
-var subTypes = require('../scatter/subtypes');
-var makeBubbleSizeFn = require('../scatter/make_bubble_size_func');
-var getTraceColor = require('../scatter/get_trace_color');
-var MARKER_SYMBOLS = require('../../constants/gl2d_markers');
-var DASHES = require('../../constants/gl2d_dashes');
-var DESELECTDIM = require('../../constants/interactions').DESELECTDIM;
-
-var AXES = ['xaxis', 'yaxis'];
-var TRANSPARENT = [0, 0, 0, 0];
-
-function LineWithMarkers(scene, uid) {
- this.scene = scene;
- this.uid = uid;
- this.type = 'scattergl';
-
- this.pickXData = [];
- this.pickYData = [];
- this.xData = [];
- this.yData = [];
- this.textLabels = [];
- this.color = 'rgb(0, 0, 0)';
- this.name = '';
- this.hoverinfo = 'all';
- this.connectgaps = true;
-
- this.index = null;
- this.idToIndex = [];
- this.bounds = [0, 0, 0, 0];
-
- this.isVisible = false;
- this.hasLines = false;
- this.hasErrorX = false;
- this.hasErrorY = false;
- this.hasMarkers = false;
-
- this.line = this.initObject(createLine, {
- positions: new Float64Array(0),
- color: [0, 0, 0, 1],
- width: 1,
- fill: [false, false, false, false],
- fillColor: [
- [0, 0, 0, 1],
- [0, 0, 0, 1],
- [0, 0, 0, 1],
- [0, 0, 0, 1]],
- dashes: [1],
- }, 0);
-
- this.errorX = this.initObject(createError, {
- positions: new Float64Array(0),
- errors: new Float64Array(0),
- lineWidth: 1,
- capSize: 0,
- color: [0, 0, 0, 1]
- }, 1);
-
- this.errorY = this.initObject(createError, {
- positions: new Float64Array(0),
- errors: new Float64Array(0),
- lineWidth: 1,
- capSize: 0,
- color: [0, 0, 0, 1]
- }, 2);
-
- var scatterOptions0 = {
- positions: new Float64Array(0),
- sizes: [],
- colors: [],
- glyphs: [],
- borderWidths: [],
- borderColors: [],
- size: 12,
- color: [0, 0, 0, 1],
- borderSize: 1,
- borderColor: [0, 0, 0, 1],
- snapPoints: true
- };
- var scatterOptions1 = Lib.extendFlat({}, scatterOptions0, {snapPoints: false});
-
- this.scatter = this.initObject(createScatter, scatterOptions0, 3);
- this.fancyScatter = this.initObject(createFancyScatter, scatterOptions0, 4);
- this.selectScatter = this.initObject(createScatter, scatterOptions1, 5);
-}
-
-var proto = LineWithMarkers.prototype;
-
-proto.initObject = function(createFn, options, objIndex) {
- var _this = this;
- var glplot = _this.scene.glplot;
- var options0 = Lib.extendFlat({}, options);
- var obj = null;
-
- function update() {
- if(!obj) {
- obj = createFn(glplot, options);
- obj._trace = _this;
- obj._index = objIndex;
- }
- obj.update(options);
- }
-
- function clear() {
- if(obj) obj.update(options0);
- }
-
- function dispose() {
- if(obj) obj.dispose();
- }
-
- return {
- options: options,
- update: update,
- clear: clear,
- dispose: dispose
- };
-};
-
-proto.handlePick = function(pickResult) {
- var index = pickResult.pointId;
-
- if(pickResult.object !== this.line || this.connectgaps) {
- index = this.idToIndex[pickResult.pointId];
- }
-
- var x = this.pickXData[index];
-
- return {
- trace: this,
- dataCoord: pickResult.dataCoord,
- traceCoord: [
- isNumeric(x) || !Lib.isDateTime(x) ? x : Lib.dateTime2ms(x),
- this.pickYData[index]
- ],
- textLabel: Array.isArray(this.textLabels) ?
- this.textLabels[index] :
- this.textLabels,
- color: Array.isArray(this.color) ?
- this.color[index] :
- this.color,
- name: this.name,
- pointIndex: index,
- hoverinfo: this.hoverinfo
- };
-};
-
-// check if trace is fancy
-proto.isFancy = function(options) {
- if(this.scene.xaxis.type !== 'linear' && this.scene.xaxis.type !== 'date') return true;
- if(this.scene.yaxis.type !== 'linear') return true;
-
- if(!options.x || !options.y) return true;
-
- if(this.hasMarkers) {
- var marker = options.marker || {};
-
- if(Array.isArray(marker.symbol) ||
- marker.symbol !== 'circle' ||
- Array.isArray(marker.size) ||
- Array.isArray(marker.color) ||
- Array.isArray(marker.line.width) ||
- Array.isArray(marker.line.color) ||
- Array.isArray(marker.opacity)
- ) return true;
- }
-
- if(this.hasLines && !this.connectgaps) return true;
-
- if(this.hasErrorX) return true;
- if(this.hasErrorY) return true;
-
- return false;
-};
-
-// handle the situation where values can be array-like or not array like
-function convertArray(convert, data, count) {
- if(!Array.isArray(data)) data = [data];
-
- return _convertArray(convert, data, count);
-}
-
-function _convertArray(convert, data, count) {
- var result = new Array(count),
- data0 = data[0];
-
- for(var i = 0; i < count; ++i) {
- result[i] = (i >= data.length) ?
- convert(data0) :
- convert(data[i]);
- }
-
- return result;
-}
-
-var convertNumber = convertArray.bind(null, function(x) { return +x; });
-var convertColorBase = convertArray.bind(null, str2RGBArray);
-var convertSymbol = convertArray.bind(null, function(x) {
- return MARKER_SYMBOLS[x] ? x : 'circle';
-});
-
-function convertColor(color, opacity, count) {
- return _convertColor(
- convertColorBase(color, count),
- convertNumber(opacity, count),
- count
- );
-}
-
-function convertColorScale(containerIn, markerOpacity, traceOpacity, count) {
- var colors = formatColor(containerIn, markerOpacity, count);
-
- colors = Array.isArray(colors[0]) ?
- colors :
- _convertArray(Lib.identity, [colors], count);
-
- return _convertColor(
- colors,
- convertNumber(traceOpacity, count),
- count
- );
-}
-
-function _convertColor(colors, opacities, count) {
- var result = new Array(4 * count);
-
- for(var i = 0; i < count; ++i) {
- for(var j = 0; j < 3; ++j) result[4 * i + j] = colors[i][j];
-
- result[4 * i + 3] = colors[i][3] * opacities[i];
- }
-
- return result;
-}
-
-function isSymbolOpen(symbol) {
- return symbol.split('-open')[1] === '';
-}
-
-function fillColor(colorIn, colorOut, offsetIn, offsetOut, isDimmed) {
- var dim = isDimmed ? DESELECTDIM : 1;
- var j;
-
- for(j = 0; j < 3; j++) {
- colorIn[4 * offsetIn + j] = colorOut[4 * offsetOut + j];
- }
- colorIn[4 * offsetIn + j] = dim * colorOut[4 * offsetOut + j];
-}
-
-proto.update = function(options, cdscatter) {
- if(options.visible !== true) {
- this.isVisible = false;
- this.hasLines = false;
- this.hasErrorX = false;
- this.hasErrorY = false;
- this.hasMarkers = false;
- }
- else {
- this.isVisible = true;
- this.hasLines = subTypes.hasLines(options);
- this.hasErrorX = options.error_x.visible === true;
- this.hasErrorY = options.error_y.visible === true;
- this.hasMarkers = subTypes.hasMarkers(options);
- }
-
- this.textLabels = options.text;
- this.name = options.name;
- this.hoverinfo = options.hoverinfo;
- this.bounds = [Infinity, Infinity, -Infinity, -Infinity];
- this.connectgaps = !!options.connectgaps;
-
- if(!this.isVisible) {
- this.line.clear();
- this.errorX.clear();
- this.errorY.clear();
- this.scatter.clear();
- this.fancyScatter.clear();
- }
- else if(this.isFancy(options)) {
- this.updateFancy(options);
- }
- else {
- this.updateFast(options);
- }
-
- // sort objects so that order is preserve on updates:
- // - lines
- // - errorX
- // - errorY
- // - markers
- this.scene.glplot.objects.sort(function(a, b) {
- return a._index - b._index;
- });
-
- // set trace index so that scene2d can sort object per traces
- this.index = options.index;
-
- // not quite on-par with 'scatter', but close enough for now
- // does not handle the colorscale case
- this.color = getTraceColor(options, {});
-
- // provide reference for selecting points
- if(cdscatter && cdscatter[0] && !cdscatter[0]._glTrace) {
- cdscatter[0]._glTrace = this;
- }
-};
-
-// We'd ideally know that all values are of fast types; sampling gives no certainty but faster
-// (for the future, typed arrays can guarantee it, and Date values can be done with
-// representing the epoch milliseconds in a typed array;
-// also, perhaps the Python / R interfaces take care of String->Date conversions
-// such that there's no need to check for string dates in plotly.js)
-// Patterned from axis_autotype.js:moreDates
-// Code DRYing is not done to preserve the most direct compilation possible for speed;
-// also, there are quite a few differences
-function allFastTypesLikely(a) {
- var len = a.length,
- inc = Math.max(1, (len - 1) / Math.min(Math.max(len, 1), 1000)),
- ai;
-
- for(var i = 0; i < len; i += inc) {
- ai = a[Math.floor(i)];
- if(!isNumeric(ai) && !(ai instanceof Date)) {
- return false;
- }
- }
-
- return true;
-}
-
-proto.updateFast = function(options) {
- var x = this.xData = this.pickXData = options.x;
- var y = this.yData = this.pickYData = options.y;
-
- var len = x.length,
- idToIndex = new Array(len),
- positions = new Float64Array(2 * len),
- bounds = this.bounds,
- pId = 0,
- ptr = 0,
- selection = options.selection,
- i, selPositions, l;
-
- var xx, yy;
-
- var xcalendar = options.xcalendar;
-
- var fastType = allFastTypesLikely(x);
- var isDateTime = !fastType && autoType(x, xcalendar) === 'date';
-
- // TODO add 'very fast' mode that bypasses this loop
- // TODO bypass this on modebar +/- zoom
- if(fastType || isDateTime) {
-
- for(i = 0; i < len; ++i) {
- xx = x[i];
- yy = y[i];
-
- if(isNumeric(yy)) {
-
- if(!fastType) {
- xx = Lib.dateTime2ms(xx, xcalendar);
- }
-
- positions[ptr++] = xx;
- positions[ptr++] = yy;
-
- idToIndex[pId++] = i;
-
- bounds[0] = Math.min(bounds[0], xx);
- bounds[1] = Math.min(bounds[1], yy);
- bounds[2] = Math.max(bounds[2], xx);
- bounds[3] = Math.max(bounds[3], yy);
- }
- }
- }
-
- positions = truncate(positions, ptr);
- this.idToIndex = idToIndex;
-
- // form selected set
- if(selection && selection.length) {
- selPositions = new Float64Array(2 * selection.length);
-
- for(i = 0, l = selection.length; i < l; i++) {
- selPositions[i * 2 + 0] = selection[i].x;
- selPositions[i * 2 + 1] = selection[i].y;
- }
- }
-
- this.updateLines(options, positions);
- this.updateError('X', options);
- this.updateError('Y', options);
-
- var markerSize;
-
- if(this.hasMarkers) {
- var markerColor, borderColor, opacity;
-
- // if we have selPositions array - means we have to render all points transparent, and selected points opaque
- if(selPositions) {
- this.scatter.options.positions = null;
-
- markerColor = str2RGBArray(options.marker.color);
- borderColor = str2RGBArray(options.marker.line.color);
- opacity = (options.opacity) * (options.marker.opacity) * DESELECTDIM;
-
- markerColor[3] *= opacity;
- this.scatter.options.color = markerColor;
-
- borderColor[3] *= opacity;
- this.scatter.options.borderColor = borderColor;
-
- markerSize = options.marker.size;
- this.scatter.options.size = markerSize;
- this.scatter.options.borderSize = options.marker.line.width;
-
- this.scatter.update();
- this.scatter.options.positions = positions;
-
-
- this.selectScatter.options.positions = selPositions;
-
- markerColor = str2RGBArray(options.marker.color);
- borderColor = str2RGBArray(options.marker.line.color);
- opacity = (options.opacity) * (options.marker.opacity);
-
- markerColor[3] *= opacity;
- this.selectScatter.options.color = markerColor;
-
- borderColor[3] *= opacity;
- this.selectScatter.options.borderColor = borderColor;
-
- markerSize = options.marker.size;
- this.selectScatter.options.size = markerSize;
- this.selectScatter.options.borderSize = options.marker.line.width;
-
- this.selectScatter.update();
- }
-
- else {
- this.scatter.options.positions = positions;
-
- markerColor = str2RGBArray(options.marker.color);
- borderColor = str2RGBArray(options.marker.line.color);
- opacity = (options.opacity) * (options.marker.opacity);
- markerColor[3] *= opacity;
- this.scatter.options.color = markerColor;
-
- borderColor[3] *= opacity;
- this.scatter.options.borderColor = borderColor;
-
- markerSize = options.marker.size;
- this.scatter.options.size = markerSize;
- this.scatter.options.borderSize = options.marker.line.width;
-
- this.scatter.update();
- }
-
- }
- else {
- this.scatter.clear();
- }
-
- // turn off fancy scatter plot
- this.fancyScatter.clear();
-
- // add item for autorange routine
- this.expandAxesFast(bounds, markerSize);
-};
-
-proto.updateFancy = function(options) {
- var scene = this.scene,
- xaxis = scene.xaxis,
- yaxis = scene.yaxis,
- bounds = this.bounds,
- selection = options.selection;
-
- // makeCalcdata runs d2c (data-to-coordinate) on every point
- var x = this.pickXData = xaxis.makeCalcdata(options, 'x').slice();
- var y = this.pickYData = yaxis.makeCalcdata(options, 'y').slice();
-
- this.xData = x.slice();
- this.yData = y.slice();
-
- // get error values
- var errorVals = ErrorBars.calcFromTrace(options, scene.fullLayout);
-
- var len = x.length,
- idToIndex = new Array(len),
- positions = new Float64Array(2 * len),
- errorsX = new Float64Array(4 * len),
- errorsY = new Float64Array(4 * len),
- pId = 0,
- ptr = 0,
- ptrX = 0,
- ptrY = 0;
-
- var getX = (xaxis.type === 'log') ? xaxis.d2l : function(x) { return x; };
- var getY = (yaxis.type === 'log') ? yaxis.d2l : function(y) { return y; };
-
- var i, xx, yy, ex0, ex1, ey0, ey1;
-
- for(i = 0; i < len; ++i) {
- this.xData[i] = xx = getX(x[i]);
- this.yData[i] = yy = getY(y[i]);
-
- if(isNaN(xx) || isNaN(yy)) continue;
-
- idToIndex[pId++] = i;
-
- positions[ptr++] = xx;
- positions[ptr++] = yy;
-
- ex0 = errorsX[ptrX++] = xx - errorVals[i].xs || 0;
- ex1 = errorsX[ptrX++] = errorVals[i].xh - xx || 0;
- errorsX[ptrX++] = 0;
- errorsX[ptrX++] = 0;
-
- errorsY[ptrY++] = 0;
- errorsY[ptrY++] = 0;
- ey0 = errorsY[ptrY++] = yy - errorVals[i].ys || 0;
- ey1 = errorsY[ptrY++] = errorVals[i].yh - yy || 0;
-
- bounds[0] = Math.min(bounds[0], xx - ex0);
- bounds[1] = Math.min(bounds[1], yy - ey0);
- bounds[2] = Math.max(bounds[2], xx + ex1);
- bounds[3] = Math.max(bounds[3], yy + ey1);
- }
-
- positions = truncate(positions, ptr);
- this.idToIndex = idToIndex;
-
- this.updateLines(options, positions);
- this.updateError('X', options, positions, errorsX);
- this.updateError('Y', options, positions, errorsY);
-
- var sizes, selIds;
-
- if(selection && selection.length) {
- selIds = {};
- for(i = 0; i < selection.length; i++) {
- selIds[selection[i].pointNumber] = true;
- }
- }
-
- if(this.hasMarkers) {
- this.scatter.options.positions = positions;
-
- // TODO rewrite convert function so that
- // we don't have to loop through the data another time
-
- this.scatter.options.sizes = new Array(pId);
- this.scatter.options.glyphs = new Array(pId);
- this.scatter.options.borderWidths = new Array(pId);
- this.scatter.options.colors = new Array(pId * 4);
- this.scatter.options.borderColors = new Array(pId * 4);
-
- var markerSizeFunc = makeBubbleSizeFn(options);
- var markerOpts = options.marker;
- var markerOpacity = markerOpts.opacity;
- var traceOpacity = options.opacity;
- var symbols = convertSymbol(markerOpts.symbol, len);
- var colors = convertColorScale(markerOpts, markerOpacity, traceOpacity, len);
- var borderWidths = convertNumber(markerOpts.line.width, len);
- var borderColors = convertColorScale(markerOpts.line, markerOpacity, traceOpacity, len);
- var index, size, symbol, symbolSpec, isOpen, isDimmed, _colors, _borderColors, bw, minBorderWidth;
-
- sizes = convertArray(markerSizeFunc, markerOpts.size, len);
-
- for(i = 0; i < pId; ++i) {
- index = idToIndex[i];
-
- symbol = symbols[index];
- symbolSpec = MARKER_SYMBOLS[symbol];
- isOpen = isSymbolOpen(symbol);
- isDimmed = selIds && !selIds[index];
-
- if(symbolSpec.noBorder && !isOpen) {
- _colors = borderColors;
- } else {
- _colors = colors;
- }
-
- if(isOpen) {
- _borderColors = colors;
- } else {
- _borderColors = borderColors;
- }
-
- // See https://github.com/plotly/plotly.js/pull/1781#discussion_r121820798
- // for more info on this logic
- size = sizes[index];
- bw = borderWidths[index];
- minBorderWidth = (symbolSpec.noBorder || symbolSpec.noFill) ? 0.1 * size : 0;
-
- this.scatter.options.sizes[i] = 4.0 * size;
- this.scatter.options.glyphs[i] = symbolSpec.unicode;
- this.scatter.options.borderWidths[i] = 0.5 * ((bw > minBorderWidth) ? bw - minBorderWidth : 0);
-
- if(isOpen && !symbolSpec.noBorder && !symbolSpec.noFill) {
- fillColor(this.scatter.options.colors, TRANSPARENT, i, 0);
- } else {
- fillColor(this.scatter.options.colors, _colors, i, index, isDimmed);
- }
- fillColor(this.scatter.options.borderColors, _borderColors, i, index, isDimmed);
- }
-
- // prevent scatter from resnapping points
- if(selIds) {
- this.scatter.options.positions = null;
- this.fancyScatter.update();
- this.scatter.options.positions = positions;
- }
- else {
- this.fancyScatter.update();
- }
- }
- else {
- this.fancyScatter.clear();
- }
-
- // turn off fast scatter plot
- this.scatter.clear();
-
- // add item for autorange routine
- this.expandAxesFancy(x, y, sizes);
-};
-
-proto.updateLines = function(options, positions) {
- var i;
-
- if(this.hasLines) {
- var linePositions = positions;
-
- if(!options.connectgaps) {
- var p = 0;
- var x = this.xData;
- var y = this.yData;
- linePositions = new Float64Array(2 * x.length);
-
- for(i = 0; i < x.length; ++i) {
- linePositions[p++] = x[i];
- linePositions[p++] = y[i];
- }
- }
-
- this.line.options.positions = linePositions;
-
- var lineColor = convertColor(options.line.color, options.opacity, 1),
- lineWidth = Math.round(0.5 * this.line.options.width),
- dashes = (DASHES[options.line.dash] || [1]).slice();
-
- for(i = 0; i < dashes.length; ++i) dashes[i] *= lineWidth;
-
- switch(options.fill) {
- case 'tozeroy':
- this.line.options.fill = [false, true, false, false];
- break;
- case 'tozerox':
- this.line.options.fill = [true, false, false, false];
- break;
- default:
- this.line.options.fill = [false, false, false, false];
- break;
- }
-
- var fillColor = str2RGBArray(options.fillcolor);
-
- this.line.options.color = lineColor;
- this.line.options.width = 2.0 * options.line.width;
- this.line.options.dashes = dashes;
- this.line.options.fillColor = [fillColor, fillColor, fillColor, fillColor];
-
- this.line.update();
- }
- else {
- this.line.clear();
- }
-};
-
-proto.updateError = function(axLetter, options, positions, errors) {
- var errorObj = this['error' + axLetter],
- errorOptions = options['error_' + axLetter.toLowerCase()];
-
- if(axLetter.toLowerCase() === 'x' && errorOptions.copy_ystyle) {
- errorOptions = options.error_y;
- }
-
- if(this['hasError' + axLetter]) {
- errorObj.options.positions = positions;
- errorObj.options.errors = errors;
- errorObj.options.capSize = errorOptions.width;
- errorObj.options.lineWidth = errorOptions.thickness / 2; // ballpark rescaling
- errorObj.options.color = convertColor(errorOptions.color, 1, 1);
-
- errorObj.update();
- }
- else {
- errorObj.clear();
- }
-};
-
-proto.expandAxesFast = function(bounds, markerSize) {
- var pad = markerSize || 10;
- var ax, min, max;
-
- for(var i = 0; i < 2; i++) {
- ax = this.scene[AXES[i]];
-
- min = ax._min;
- if(!min) min = [];
- min.push({ val: bounds[i], pad: pad });
-
- max = ax._max;
- if(!max) max = [];
- max.push({ val: bounds[i + 2], pad: pad });
- }
-};
-
-// not quite on-par with 'scatter' (scatter fill in several other expand options)
-// but close enough for now
-proto.expandAxesFancy = function(x, y, ppad) {
- var scene = this.scene,
- expandOpts = { padded: true, ppad: ppad };
-
- Axes.expand(scene.xaxis, x, expandOpts);
- Axes.expand(scene.yaxis, y, expandOpts);
-};
-
-proto.dispose = function() {
- this.line.dispose();
- this.errorX.dispose();
- this.errorY.dispose();
- this.scatter.dispose();
- this.fancyScatter.dispose();
-};
-
-function createLineWithMarkers(scene, data, cdscatter) {
- var plot = new LineWithMarkers(scene, data.uid);
- plot.update(data, cdscatter);
-
- return plot;
-}
-
-module.exports = createLineWithMarkers;
diff --git a/src/traces/scattergl/defaults.js b/src/traces/scattergl/defaults.js
index 498135065fd..24b1281b129 100644
--- a/src/traces/scattergl/defaults.js
+++ b/src/traces/scattergl/defaults.js
@@ -27,6 +27,9 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
+ var isOpen = traceIn.marker ? /-open/.test(traceIn.marker.symbol) : false;
+ var isBubble = subTypes.isBubble(traceIn);
+
var len = handleXYDefaults(traceIn, traceOut, layout, coerce);
if(!len) {
traceOut.visible = false;
@@ -41,8 +44,12 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce);
}
+ var dfltHoverOn = [];
+
if(subTypes.hasMarkers(traceOut)) {
- handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {noSelect: true});
+ handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce);
+ coerce('marker.line.width', isOpen || isBubble ? 1 : 0);
+ dfltHoverOn.push('points');
}
coerce('fill');
@@ -50,6 +57,14 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
}
+ if(traceOut.fill === 'tonext' || traceOut.fill === 'toself') {
+ dfltHoverOn.push('fills');
+ }
+
+ coerce('hoveron', dfltHoverOn.join('+') || 'points');
+
errorBarsSupplyDefaults(traceIn, traceOut, defaultColor, {axis: 'y'});
errorBarsSupplyDefaults(traceIn, traceOut, defaultColor, {axis: 'x', inherit: 'y'});
+
+ Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
diff --git a/src/traces/scattergl/index.js b/src/traces/scattergl/index.js
index 648ff49fb38..3ee553e6992 100644
--- a/src/traces/scattergl/index.js
+++ b/src/traces/scattergl/index.js
@@ -8,29 +8,1226 @@
'use strict';
-var ScatterGl = {};
-
-ScatterGl.attributes = require('./attributes');
-ScatterGl.supplyDefaults = require('./defaults');
-ScatterGl.colorbar = require('../scatter/colorbar');
-ScatterGl.hoverPoints = require('../scatter/hover');
-
-// reuse the Scatter3D 'dummy' calc step so that legends know what to do
-ScatterGl.calc = require('./calc');
-ScatterGl.plot = require('./convert');
-ScatterGl.selectPoints = require('./select');
-
-ScatterGl.moduleType = 'trace';
-ScatterGl.name = 'scattergl';
-ScatterGl.basePlotModule = require('../../plots/gl2d');
-ScatterGl.categories = ['gl', 'gl2d', 'symbols', 'errorBarsOK', 'markerColorscale', 'showLegend', 'scatter-like'];
-ScatterGl.meta = {
- description: [
- 'The data visualized as scatter point or lines is set in `x` and `y`',
- 'using the WebGl plotting engine.',
- 'Bubble charts are achieved by setting `marker.size` and/or `marker.color`',
- 'to a numerical arrays.'
- ].join(' ')
-};
+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 Fx = require('../../components/fx');
+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 createScatter = require('regl-scatter2d');
+var createLine = require('regl-line2d');
+var createError = require('regl-error2d');
+var rgba = require('color-normalize');
+var svgSdf = require('svg-path-sdf');
+var createRegl = require('regl');
+var fillHoverText = require('../scatter/fill_hover_text');
+var isNumeric = require('fast-isnumeric');
+
+var MAXDIST = Fx.constants.MAXDIST;
+var SYMBOL_SDF_SIZE = 200;
+var SYMBOL_SIZE = 20;
+var SYMBOL_STROKE = SYMBOL_SIZE / 20;
+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 stash = {};
+ var xaxis = Axes.getFromId(container, trace.xaxis);
+ var yaxis = Axes.getFromId(container, trace.yaxis);
+
+ var subplot = layout._plots[trace.xaxis + trace.yaxis];
+
+ var x = xaxis.type === 'linear' ? trace.x : xaxis.makeCalcdata(trace, 'x');
+ var y = yaxis.type === 'linear' ? trace.y : yaxis.makeCalcdata(trace, 'y');
+
+ var count = (x || y).length, i, l, xx, yy;
+
+ if(!x) {
+ x = Array(count);
+ for(i = 0; i < count; i++) {
+ x[i] = i;
+ }
+ }
+ if(!y) {
+ y = Array(count);
+ for(i = 0; i < count; i++) {
+ y[i] = i;
+ }
+ }
+
+ // get log converted positions
+ var rawx, rawy;
+ if(xaxis.type === 'log') {
+ rawx = Array(x.length);
+ for(i = 0, l = x.length; i < l; i++) {
+ rawx[i] = x[i];
+ x[i] = xaxis.d2l(x[i]);
+ }
+ }
+ else {
+ rawx = x;
+ for(i = 0, l = x.length; i < l; i++) {
+ x[i] = parseFloat(x[i]);
+ }
+ }
+ if(yaxis.type === 'log') {
+ rawy = Array(y.length);
+ for(i = 0, l = y.length; i < l; i++) {
+ rawy[i] = y[i];
+ y[i] = yaxis.d2l(y[i]);
+ }
+ }
+ else {
+ rawy = y;
+ for(i = 0, l = y.length; i < l; i++) {
+ y[i] = parseFloat(y[i]);
+ }
+ }
+
+ // we need hi-precision for scatter2d
+ positions = new Array(count * 2);
+
+ for(i = 0; i < count; 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') {
+ // FIXME: delegate this to webworker
+ stash.tree = kdtree(positions, 512);
+ }
+ else {
+ var ids = stash.ids = Array(count);
+ for(i = 0; i < count; i++) {
+ ids[i] = i;
+ }
+ }
+
+
+ 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(Array.isArray(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 });
+ }
+ }
+ }
+
+ // 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;
+ if(options.line && !scene.line2d) scene.line2d = true;
+ if((options.errorX || options.errorY) && !scene.error2d) scene.error2d = true;
+
+ // save scene options batch
+ scene.lineOptions.push(options.line);
+ scene.errorXOptions.push(options.errorX);
+ scene.errorYOptions.push(options.errorY);
+ scene.fillOptions.push(options.fill);
+ scene.markerOptions.push(options.marker);
+ scene.selectedOptions.push(options.selected);
+ scene.unselectedOptions.push(options.unselected);
+ scene.count++;
+
+ // stash scene ref
+ stash.scene = scene;
+ stash.index = scene.count - 1;
+ stash.x = x;
+ stash.y = y;
+ stash.rawx = rawx;
+ stash.rawy = rawy;
+ stash.positions = positions;
+ stash.count = count;
+
+ return [{x: false, y: false, t: stash, trace: trace}];
+}
+
+// create scene options
+function sceneOptions(container, subplot, trace, positions) {
+ var layout = container._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 hasLines, hasErrorX, hasErrorY, hasError, hasMarkers, hasFill;
+
+ if(trace.visible !== true) {
+ hasLines = false;
+ hasErrorX = false;
+ hasErrorY = false;
+ hasMarkers = false;
+ hasFill = false;
+ }
+ 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;
+ hasError = hasErrorX || hasErrorY;
+ hasMarkers = subTypes.hasMarkers(trace);
+ hasFill = !!trace.fill && trace.fill !== 'none';
+ }
+
+ var lineOptions, markerOptions, errorXOptions, errorYOptions, fillOptions, selectedOptions, unselectedOptions;
+ var linePositions;
+
+ // get error values
+ var errorVals = hasError ? ErrorBars.calcFromTrace(trace, layout) : null;
+
+ if(hasErrorX) {
+ errorXOptions = {};
+ errorXOptions.positions = positions;
+ var errorsX = new Float64Array(4 * count);
+
+ if(xaxis.type === 'log') {
+ for(i = 0; i < count; ++i) {
+ errorsX[ptrX++] = positions[i * 2] - xaxis.d2l(errorVals[i].xs) || 0;
+ errorsX[ptrX++] = xaxis.d2l(errorVals[i].xh) - positions[i * 2] || 0;
+ errorsX[ptrX++] = 0;
+ errorsX[ptrX++] = 0;
+ }
+ } else {
+ for(i = 0; i < count; ++i) {
+ errorsX[ptrX++] = positions[i * 2] - errorVals[i].xs || 0;
+ errorsX[ptrX++] = errorVals[i].xh - positions[i * 2] || 0;
+ errorsX[ptrX++] = 0;
+ errorsX[ptrX++] = 0;
+ }
+ }
+
+ if(trace.error_x.copy_ystyle) {
+ trace.error_x = trace.error_y;
+ }
+
+ errorXOptions.errors = errorsX;
+ errorXOptions.capSize = trace.error_x.width * 2;
+ errorXOptions.lineWidth = trace.error_x.thickness;
+ errorXOptions.color = trace.error_x.color;
+ }
+
+ if(hasErrorY) {
+ errorYOptions = {};
+ errorYOptions.positions = positions;
+ var errorsY = new Float64Array(4 * count);
+
+ if(yaxis.type === 'log') {
+ for(i = 0; i < count; ++i) {
+ errorsY[ptrY++] = 0;
+ errorsY[ptrY++] = 0;
+ errorsY[ptrY++] = positions[i * 2 + 1] - yaxis.d2l(errorVals[i].ys) || 0;
+ errorsY[ptrY++] = yaxis.d2l(errorVals[i].yh) - positions[i * 2 + 1] || 0;
+ }
+ } else {
+ for(i = 0; i < count; ++i) {
+ errorsY[ptrY++] = 0;
+ errorsY[ptrY++] = 0;
+ errorsY[ptrY++] = positions[i * 2 + 1] - errorVals[i].ys || 0;
+ errorsY[ptrY++] = errorVals[i].yh - positions[i * 2 + 1] || 0;
+ }
+ }
+
+ errorYOptions.errors = errorsY;
+ errorYOptions.capSize = trace.error_y.width * 2;
+ errorYOptions.lineWidth = trace.error_y.thickness;
+ errorYOptions.color = trace.error_y.color;
+ }
+
+ if(hasLines) {
+ lineOptions = {};
+ lineOptions.thickness = trace.line.width;
+ lineOptions.color = trace.line.color;
+ lineOptions.opacity = trace.opacity;
+ lineOptions.overlay = true;
+
+ var dashes = (DASHES[trace.line.dash] || [1]).slice();
+ for(i = 0; i < dashes.length; ++i) dashes[i] *= lineOptions.thickness;
+ lineOptions.dashes = dashes;
+
+ if(trace.line.shape === 'hv') {
+ linePositions = [];
+ for(i = 0; i < Math.floor(positions.length / 2) - 1; i++) {
+ if(isNaN(positions[i * 2]) || isNaN(positions[i * 2 + 1])) {
+ linePositions.push(NaN);
+ linePositions.push(NaN);
+ linePositions.push(NaN);
+ linePositions.push(NaN);
+ }
+ else {
+ linePositions.push(positions[i * 2]);
+ linePositions.push(positions[i * 2 + 1]);
+ linePositions.push(positions[i * 2 + 2]);
+ linePositions.push(positions[i * 2 + 1]);
+ }
+ }
+ linePositions.push(positions[positions.length - 2]);
+ linePositions.push(positions[positions.length - 1]);
+ }
+ else if(trace.line.shape === 'vh') {
+ linePositions = [];
+ for(i = 0; i < Math.floor(positions.length / 2) - 1; i++) {
+ if(isNaN(positions[i * 2]) || isNaN(positions[i * 2 + 1])) {
+ linePositions.push(NaN);
+ linePositions.push(NaN);
+ linePositions.push(NaN);
+ linePositions.push(NaN);
+ }
+ else {
+ linePositions.push(positions[i * 2]);
+ linePositions.push(positions[i * 2 + 1]);
+ linePositions.push(positions[i * 2]);
+ linePositions.push(positions[i * 2 + 3]);
+ }
+ }
+ linePositions.push(positions[positions.length - 2]);
+ linePositions.push(positions[positions.length - 1]);
+ }
+ else {
+ linePositions = positions;
+ }
+
+ // If we have data with gaps, we ought to use rect joins
+ // FIXME: get rid of this
+ var hasNaN = false;
+ for(i = 0; i < linePositions.length; i++) {
+ if(isNaN(linePositions[i])) {
+ hasNaN = true;
+ break;
+ }
+ }
+ lineOptions.join = (hasNaN || linePositions.length > TOO_MANY_POINTS) ? 'rect' : hasMarkers ? 'rect' : 'round';
+
+ // fill gaps
+ if(hasNaN && trace.connectgaps) {
+ var lastX = linePositions[0], lastY = linePositions[1];
+ for(i = 0; i < linePositions.length; i += 2) {
+ if(isNaN(linePositions[i]) || isNaN(linePositions[i + 1])) {
+ linePositions[i] = lastX;
+ linePositions[i + 1] = lastY;
+ }
+ else {
+ lastX = linePositions[i];
+ lastY = linePositions[i + 1];
+ }
+ }
+ }
+
+ lineOptions.positions = linePositions;
+ }
+
+ if(hasFill) {
+ fillOptions = {};
+ fillOptions.fill = trace.fillcolor;
+ fillOptions.thickness = 0;
+ fillOptions.closed = true;
+ }
+
+ if(hasMarkers) {
+ markerOptions = makeMarkerOptions(markerOpts);
+ selectedOptions = trace.selected ? makeMarkerOptions(extend({}, markerOpts, trace.selected.marker)) : markerOptions;
+ unselectedOptions = trace.unselected ? makeMarkerOptions(extend({}, markerOpts, trace.unselected.marker)) : markerOptions;
+
+ markerOptions.positions = positions;
+ }
+
+ function makeMarkerOptions(markerOpts) {
+ var markerOptions = {}, i;
+
+ // get basic symbol info
+ var multiMarker = Array.isArray(markerOpts.symbol);
+ var isOpen, symbol;
+ if(!multiMarker) {
+ isOpen = /-open/.test(markerOpts.symbol);
+ }
+
+ // prepare colors
+ if(multiMarker || Array.isArray(markerOpts.color) || Array.isArray(markerOpts.line.color) || Array.isArray(markerOpts.line) || Array.isArray(markerOpts.opacity)) {
+ markerOptions.colors = new Array(count);
+ markerOptions.borderColors = new Array(count);
+ var colors = formatColor(markerOpts, markerOpts.opacity, count);
+ var borderColors = formatColor(markerOpts.line, markerOpts.opacity, count);
+
+ if(!Array.isArray(borderColors[0])) {
+ var borderColor = borderColors;
+ borderColors = Array(count);
+ for(i = 0; i < count; i++) {
+ borderColors[i] = borderColor;
+ }
+ }
+ if(!Array.isArray(colors[0])) {
+ var color = colors;
+ colors = Array(count);
+ for(i = 0; i < count; i++) {
+ colors[i] = color;
+ }
+ }
+
+ markerOptions.colors = colors;
+ markerOptions.borderColors = borderColors;
+
+ for(i = 0; i < count; i++) {
+ if(multiMarker) {
+ symbol = markerOpts.symbol[i];
+ isOpen = /-open/.test(symbol);
+ }
+ if(isOpen) {
+ borderColors[i] = colors[i].slice();
+ colors[i] = colors[i].slice();
+ colors[i][3] = 0;
+ }
+ }
+
+ markerOptions.opacity = trace.opacity;
+ }
+ else {
+ if(isOpen) {
+ markerOptions.color = rgba(markerOpts.color, 'uint8');
+ markerOptions.color[3] = 0;
+ markerOptions.borderColor = rgba(markerOpts.color, 'uint8');
+ }
+ else {
+ markerOptions.color = rgba(markerOpts.color, 'uint8');
+ markerOptions.borderColor = rgba(markerOpts.line.color, 'uint8');
+ }
+
+ markerOptions.opacity = trace.opacity * markerOpts.opacity;
+ }
+
+ // prepare markers
+ if(Array.isArray(markerOpts.symbol)) {
+ markerOptions.markers = new Array(count);
+ for(i = 0; i < count; ++i) {
+ markerOptions.markers[i] = getSymbolSdf(markerOpts.symbol[i]);
+ }
+ }
+ else {
+ markerOptions.marker = getSymbolSdf(markerOpts.symbol);
+ }
+
+ // prepare sizes and expand axes
+ var multiSize = markerOpts && (Array.isArray(markerOpts.size) || Array.isArray(markerOpts.line.width));
+ var markerSizeFunc = makeBubbleSizeFn(trace);
+ var size, sizes;
+
+ if(multiSize) {
+ sizes = markerOptions.sizes = new Array(count);
+ var borderSizes = markerOptions.borderSizes = new Array(count);
+
+ if(Array.isArray(markerOpts.size)) {
+ for(i = 0; i < count; ++i) {
+ sizes[i] = markerSizeFunc(markerOpts.size[i]);
+ }
+ }
+ else {
+ size = markerSizeFunc(markerOpts.size);
+ for(i = 0; i < count; ++i) {
+ sizes[i] = size;
+ }
+ }
+
+ // See https://github.com/plotly/plotly.js/pull/1781#discussion_r121820798
+ if(Array.isArray(markerOpts.line.width)) {
+ 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 {
+ size = markerOptions.size = markerSizeFunc(markerOpts && markerOpts.size || 10);
+ markerOptions.borderSizes = markerSizeFunc(markerOpts.line.width);
+ }
+
+ return markerOptions;
+ }
+
+ return {
+ line: lineOptions,
+ marker: markerOptions,
+ errorX: errorXOptions,
+ errorY: errorYOptions,
+ fill: fillOptions,
+ selected: selectedOptions,
+ unselected: unselectedOptions
+ };
+}
+
+// make sure scene exists on subplot, return it
+function sceneUpdate(container, subplot) {
+ var scene = subplot._scene;
+ var layout = container._fullLayout;
+
+ if(!subplot._scene) {
+ scene = subplot._scene = {
+ // number of traces in subplot, since scene:subplot → 1:1
+ count: 0,
+
+ // whether scene requires init hook in plot call (dirty plot call)
+ dirty: true,
+
+ // last used options
+ lineOptions: [],
+ fillOptions: [],
+ markerOptions: [],
+ selectedOptions: [],
+ unselectedOptions: [],
+ errorXOptions: [],
+ errorYOptions: [],
+ selectBatch: null,
+ unselectBatch: null,
+
+ // regl- component stubs, initialized in dirty plot call
+ fill2d: false,
+ scatter2d: false,
+ error2d: false,
+ line2d: false,
+ select2d: null
+ };
+
+ // apply new option to all regl components
+ scene.update = function update(opt) {
+ var opts = Array(scene.count);
+ for(var i = 0; i < scene.count; i++) {
+ opts[i] = opt;
+ }
+ if(scene.fill2d) scene.fill2d.update(opts);
+ if(scene.scatter2d) scene.scatter2d.update(opts);
+ if(scene.line2d) scene.line2d.update(opts);
+ if(scene.error2d) scene.error2d.update(opts.concat(opts));
+ if(scene.select2d) scene.select2d.update(opts);
+
+ scene.draw();
+ };
+
+ // draw traces in proper order
+ scene.draw = function draw() {
+ var i;
+ for(i = 0; i < scene.count; i++) {
+ if(scene.fill2d) scene.fill2d.draw(i);
+ }
+ for(i = 0; i < scene.count; i++) {
+ if(scene.line2d) {
+ scene.line2d.draw(i);
+ }
+ if(scene.error2d) {
+ scene.error2d.draw(i);
+ scene.error2d.draw(i + scene.count);
+ }
+ if(scene.scatter2d && !scene.selectBatch) {
+ scene.scatter2d.draw(i);
+ }
+ }
+
+ // persistent selection draw
+ if(scene.select2d && scene.selectBatch) {
+ scene.select2d.draw(scene.selectBatch);
+ scene.scatter2d.draw(scene.unselectBatch);
+ }
+
+ scene.dirty = false;
+ };
+
+ // make sure canvas is clear
+ scene.clear = function clear() {
+ var vpSize = layout._size, width = layout.width, height = layout.height, vp, gl, regl;
+ var xaxis = subplot.xaxis;
+ var yaxis = subplot.yaxis;
+
+ // multisubplot case
+ if(xaxis && xaxis.domain && yaxis && yaxis.domain) {
+ vp = [
+ vpSize.l + xaxis.domain[0] * vpSize.w,
+ vpSize.b + yaxis.domain[0] * vpSize.h,
+ (width - vpSize.r) - (1 - xaxis.domain[1]) * vpSize.w,
+ (height - vpSize.t) - (1 - yaxis.domain[1]) * vpSize.h
+ ];
+ }
+ else {
+ vp = [
+ vpSize.l,
+ vpSize.b,
+ (width - vpSize.r),
+ (height - vpSize.t)
+ ];
+ }
+
+ if(scene.select2d) {
+ regl = scene.select2d.regl;
+ gl = regl._gl;
+ gl.enable(gl.SCISSOR_TEST);
+ gl.scissor(vp[0], vp[1], vp[2] - vp[0], vp[3] - vp[1]);
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+
+ if(scene.scatter2d) {
+ regl = scene.scatter2d.regl;
+ gl = regl._gl;
+ gl.enable(gl.SCISSOR_TEST);
+ gl.scissor(vp[0], vp[1], vp[2] - vp[0], vp[3] - vp[1]);
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+ };
+
+ // remove selection
+ scene.clearSelect = function clearSelect() {
+ if(!scene.selectBatch) return;
+ scene.selectBatch = null;
+ scene.unselectBatch = null;
+ scene.scatter2d.update(scene.markerOptions);
+ scene.clear();
+ scene.draw();
+ };
+
+ // remove scene resources
+ scene.destroy = function destroy() {
+ if(scene.fill2d) scene.fill2d.destroy();
+ if(scene.scatter2d) scene.scatter2d.destroy();
+ if(scene.error2d) scene.error2d.destroy();
+ if(scene.line2d) scene.line2d.destroy();
+ if(scene.select2d) scene.select2d.destroy();
+
+ scene.lineOptions = null;
+ scene.fillOptions = null;
+ scene.markerOptions = null;
+ scene.selectedOptions = null;
+ scene.unselectedOptions = null;
+ scene.errorXOptions = null;
+ scene.errorYOptions = null;
+ scene.selectBatch = null;
+ scene.unselectBatch = null;
+
+ delete subplot._scene;
+ };
+ }
+
+ // In case if we have scene from the last calc - reset data
+ if(!scene.dirty) {
+ scene.dirty = true;
+ scene.count = 0;
+ scene.lineOptions = [];
+ scene.fillOptions = [];
+ scene.markerOptions = [];
+ scene.selectedOptions = [];
+ scene.unselectedOptions = [];
+ scene.errorXOptions = [];
+ scene.errorYOptions = [];
+ }
-module.exports = ScatterGl;
+ return scene;
+}
+
+function getSymbolSdf(symbol) {
+ if(symbol === 'circle') return null;
+
+ var symbolPath, symbolSdf;
+ var symbolNumber = Drawing.symbolNumber(symbol);
+ var symbolFunc = Drawing.symbolFuncs[symbolNumber % 100];
+ var symbolNoDot = !!Drawing.symbolNoDot[symbolNumber % 100];
+ var symbolNoFill = !!Drawing.symbolNoFill[symbolNumber % 100];
+
+ var isDot = DOT_RE.test(symbol);
+
+ // get symbol sdf from cache or generate it
+ if(SYMBOL_SDF[symbol]) return SYMBOL_SDF[symbol];
+
+ if(isDot && !symbolNoDot) {
+ symbolPath = symbolFunc(SYMBOL_SIZE * 1.1) + SYMBOL_SVG_CIRCLE;
+ }
+ else {
+ symbolPath = symbolFunc(SYMBOL_SIZE);
+ }
+
+ symbolSdf = svgSdf(symbolPath, {
+ w: SYMBOL_SDF_SIZE,
+ h: SYMBOL_SDF_SIZE,
+ viewBox: [-SYMBOL_SIZE, -SYMBOL_SIZE, SYMBOL_SIZE, SYMBOL_SIZE],
+ stroke: symbolNoFill ? SYMBOL_STROKE : -SYMBOL_STROKE
+ });
+ SYMBOL_SDF[symbol] = symbolSdf;
+
+ return symbolSdf || null;
+}
+
+function plot(container, subplot, cdata) {
+ if(!cdata.length) return;
+
+ var layout = container._fullLayout;
+ var stash = cdata[0][0].t;
+ var scene = stash.scene;
+
+ // 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;
+
+ // make sure proper regl instances are created
+ layout._glcanvas.each(function(d) {
+ if(d.regl || d.pick) return;
+ d.regl = createRegl({
+ canvas: this,
+ attributes: {
+ antialias: !d.pick,
+ preserveDrawingBuffer: true
+ },
+ extensions: ['ANGLE_instanced_arrays', 'OES_element_index_uint'],
+ pixelRatio: container._context.plotGlPixelRatio || global.devicePixelRatio
+ });
+ });
+
+ var regl = layout._glcanvas.data()[0].regl;
+
+ // that is needed for fills
+ linkTraces(container, subplot, cdata);
+
+ if(scene.dirty) {
+ // make sure scenes are created
+ if(scene.error2d === true) {
+ scene.error2d = createError(regl);
+ }
+ if(scene.line2d === true) {
+ scene.line2d = createLine(regl);
+ }
+ if(scene.scatter2d === true) {
+ scene.scatter2d = createScatter(regl);
+ }
+ if(scene.fill2d === true) {
+ scene.fill2d = createLine(regl);
+ }
+
+ if(scene.line2d) {
+ scene.line2d.update(scene.lineOptions);
+ }
+ if(scene.error2d) {
+ var errorBatch = (scene.errorXOptions || []).concat(scene.errorYOptions || []);
+ scene.error2d.update(errorBatch);
+ }
+ if(scene.scatter2d) {
+ if(!scene.selectBatch) {
+ scene.scatter2d.update(scene.markerOptions);
+ }
+ else {
+ scene.scatter2d.update(scene.unselectedOptions);
+ scene.select2d.update(scene.selectedOptions);
+ }
+ }
+ // fill requires linked traces, so we generate it's positions here
+ if(scene.fill2d) {
+ scene.fillOptions.forEach(function(fillOptions, i) {
+ var cdscatter = cdata[i];
+ if(!fillOptions || !cdscatter || !cdscatter[0] || !cdscatter[0].trace) return;
+ var cd = cdscatter[0];
+ var trace = cd.trace;
+ var stash = cd.t;
+ var lineOptions = scene.lineOptions[i];
+ var last, j;
+
+ var pos = [], srcPos = (lineOptions && lineOptions.positions) || stash.positions;
+
+ if(trace.fill === 'tozeroy') {
+ pos = [srcPos[0], 0];
+ pos = pos.concat(srcPos);
+ pos.push(srcPos[srcPos.length - 2]);
+ pos.push(0);
+ }
+ else if(trace.fill === 'tozerox') {
+ pos = [0, srcPos[1]];
+ pos = pos.concat(srcPos);
+ pos.push(0);
+ pos.push(srcPos[srcPos.length - 1]);
+ }
+ else if(trace.fill === 'toself' || trace.fill === 'tonext') {
+ pos = [];
+ last = 0;
+ for(j = 0; j < srcPos.length; j += 2) {
+ if(isNaN(srcPos[j]) || isNaN(srcPos[j + 1])) {
+ pos = pos.concat(srcPos.slice(last, j));
+ pos.push(srcPos[last], srcPos[last + 1]);
+ last = j + 2;
+ }
+ }
+ pos = pos.concat(srcPos.slice(last));
+ if(last) {
+ pos.push(srcPos[last], srcPos[last + 1]);
+ }
+ }
+ else {
+ var nextTrace = trace._nexttrace;
+
+ if(nextTrace) {
+ var nextOptions = scene.lineOptions[i + 1];
+
+ if(nextOptions) {
+ var nextPos = nextOptions.positions;
+ if(trace.fill === 'tonexty') {
+ pos = srcPos.slice();
+
+ for(i = Math.floor(nextPos.length / 2); i--;) {
+ var xx = nextPos[i * 2], yy = nextPos[i * 2 + 1];
+ if(isNaN(xx) || isNaN(yy)) continue;
+ pos.push(xx);
+ pos.push(yy);
+ }
+ fillOptions.fill = nextTrace.fillcolor;
+ }
+ }
+ }
+ }
+
+ // detect prev trace positions to exclude from current fill
+ if(trace._prevtrace && trace._prevtrace.fill === 'tonext') {
+ var prevLinePos = scene.lineOptions[i - 1].positions;
+
+ // FIXME: likely this logic should be tested better
+ var offset = pos.length / 2;
+ last = offset;
+ var hole = [last];
+ for(j = 0; j < prevLinePos.length; j += 2) {
+ if(isNaN(prevLinePos[j]) || isNaN(prevLinePos[j + 1])) {
+ hole.push(j / 2 + offset + 1);
+ last = j + 2;
+ }
+ }
+
+ pos = pos.concat(prevLinePos);
+ fillOptions.hole = hole;
+ }
+
+ fillOptions.opacity = trace.opacity;
+ fillOptions.positions = pos;
+ });
+
+ scene.fill2d.update(scene.fillOptions);
+ }
+ }
+
+ // make sure selection layer is initialized if we require selection
+ var dragmode = layout.dragmode;
+
+ if(dragmode === 'lasso' || dragmode === 'select') {
+ if(scene.select2d && scene.selectBatch) {
+ scene.scatter2d.update(scene.unselectedOptions);
+ }
+ }
+
+ // provide viewport and range
+ var vpRange = cdata.map(function(cdscatter) {
+ if(!cdscatter || !cdscatter[0] || !cdscatter[0].trace) return;
+ var cd = cdscatter[0];
+ var trace = cd.trace;
+ var stash = cd.t;
+ var x = stash.rawx,
+ y = stash.rawy;
+
+ var xaxis = subplot.xaxis || Axes.getFromId(container, trace.xaxis || 'x');
+ var yaxis = subplot.yaxis || Axes.getFromId(container, trace.yaxis || 'y');
+ var i;
+
+ var range = [
+ (xaxis._rl || xaxis.range)[0],
+ (yaxis._rl || yaxis.range)[0],
+ (xaxis._rl || xaxis.range)[1],
+ (yaxis._rl || yaxis.range)[1]
+ ];
+
+ var viewport = [
+ vpSize.l + xaxis.domain[0] * vpSize.w,
+ vpSize.b + yaxis.domain[0] * vpSize.h,
+ (width - vpSize.r) - (1 - xaxis.domain[1]) * vpSize.w,
+ (height - vpSize.t) - (1 - yaxis.domain[1]) * vpSize.h
+ ];
+
+ if(trace.selectedpoints || dragmode === 'lasso' || dragmode === 'select') {
+ // create select2d
+ if(!scene.select2d && scene.scatter2d) {
+ var selectRegl = layout._glcanvas.data()[1].regl;
+
+ // smol hack to create scatter instance by cloning scatter2d
+ scene.select2d = createScatter(selectRegl, {clone: scene.scatter2d});
+ scene.select2d.update(scene.selectedOptions);
+
+ // create selection style once we have something selected
+ if(trace.selectedpoints && !scene.selectBatch) {
+ scene.selectBatch = Array(scene.count);
+ scene.unselectBatch = Array(scene.count);
+ scene.scatter2d.update(scene.unselectedOptions);
+ }
+ }
+ else {
+ // update selection positions, since they may have changed by panning or alike
+ scene.select2d.update(scene.selectedOptions);
+ }
+
+ // form unselected batch
+ if(trace.selectedpoints && !scene.unselectBatch[stash.index]) {
+ scene.selectBatch[stash.index] = trace.selectedpoints;
+ var selPts = trace.selectedpoints;
+ var selDict = {};
+ for(i = 0; i < selPts.length; i++) {
+ selDict[selPts[i]] = true;
+ }
+ var unselPts = [];
+ for(i = 0; i < stash.count; i++) {
+ if(!selDict[i]) unselPts.push(i);
+ }
+ scene.unselectBatch[stash.index] = unselPts;
+ }
+
+ // precalculate px coords since we are not going to pan during select
+ var xpx = Array(stash.count), ypx = Array(stash.count);
+ for(i = 0; i < stash.count; i++) {
+ xpx[i] = xaxis.c2p(x[i]);
+ ypx[i] = yaxis.c2p(y[i]);
+ }
+ stash.xpx = xpx;
+ stash.ypx = ypx;
+ }
+ else {
+ stash.xpx = stash.ypx = null;
+ }
+
+ return trace.visible ? {
+ viewport: viewport,
+ range: range
+ } : null;
+ });
+
+ // uploat viewport/range data to GPU
+ if(scene.fill2d) {
+ scene.fill2d.update(vpRange);
+ }
+ if(scene.line2d) {
+ scene.line2d.update(vpRange);
+ }
+ if(scene.error2d) {
+ scene.error2d.update(vpRange.concat(vpRange));
+ }
+ if(scene.scatter2d) {
+ scene.scatter2d.update(vpRange);
+ }
+ if(scene.select2d) {
+ scene.select2d.update(vpRange);
+ }
+
+ scene.draw();
+
+ return;
+}
+
+function hoverPoints(pointData, xval, yval, hovermode) {
+ var cd = pointData.cd,
+ stash = cd[0].t,
+ trace = cd[0].trace,
+ xa = pointData.xa,
+ ya = pointData.ya,
+ x = stash.rawx,
+ y = stash.rawy,
+ xpx = xa.c2p(xval),
+ ypx = ya.c2p(yval),
+ ids;
+
+ // FIXME: make sure this is a proper way to calc search radius
+ if(stash.tree) {
+ var xl = xa.p2c(xpx - MAXDIST),
+ xr = xa.p2c(xpx + MAXDIST),
+ yl = ya.p2c(ypx - MAXDIST),
+ yr = ya.p2c(ypx + MAXDIST);
+
+ if(hovermode === 'x') {
+ ids = stash.tree.range(
+ Math.min(xl, xr), Math.min(ya._rl[0], ya._rl[1]),
+ Math.max(xl, xr), Math.max(ya._rl[0], ya._rl[1])
+ );
+ }
+ else {
+ ids = stash.tree.range(
+ Math.min(xl, xr), Math.min(yl, yr),
+ Math.max(xl, xr), Math.max(yl, yr)
+ );
+ }
+ }
+ else if(stash.ids) {
+ ids = stash.ids;
+ }
+ else return [pointData];
+
+ // pick the id closest to the point
+ // note that point possibly may not be found
+ var min = MAXDIST, id, ptx, pty, i, dx, dy, dist;
+
+ if(hovermode === 'x') {
+ for(i = 0; i < ids.length; i++) {
+ ptx = x[ids[i]];
+ dx = Math.abs(xa.c2p(ptx) - xpx);
+ if(dx < min) {
+ min = dx;
+ id = ids[i];
+ }
+ }
+ }
+ else {
+ for(i = 0; i < ids.length; i++) {
+ ptx = x[ids[i]];
+ pty = y[ids[i]];
+ dx = xa.c2p(ptx) - xpx, dy = ya.c2p(pty) - ypx;
+
+ dist = Math.sqrt(dx * dx + dy * dy);
+ if(dist < min) {
+ min = dist;
+ id = ids[i];
+ }
+ }
+ }
+
+ pointData.index = id;
+
+ if(id === undefined) return [pointData];
+
+ // the closest data point
+ var di = {
+ pointNumber: id,
+ x: x[id],
+ y: y[id]
+ };
+
+ // that is single-item arrays_to_calcdata excerpt, since we are doing it for a single point and we don't have to do it beforehead for 1e6 points
+ di.tx = Array.isArray(trace.text) ? trace.text[id] : trace.text;
+ di.htx = Array.isArray(trace.hovertext) ? trace.hovertext[id] : trace.hovertext;
+ di.data = Array.isArray(trace.customdata) ? trace.customdata[id] : trace.customdata;
+ di.tp = Array.isArray(trace.textposition) ? trace.textposition[id] : trace.textposition;
+
+ var font = trace.textfont;
+ if(font) {
+ di.ts = Array.isArray(font.size) ? font.size[id] : font.size;
+ di.tc = Array.isArray(font.color) ? font.color[id] : font.color;
+ di.tf = Array.isArray(font.family) ? font.family[id] : font.family;
+ }
+
+ var marker = trace.marker;
+ if(marker) {
+ di.ms = Array.isArray(marker.size) ? marker.size[id] : marker.size;
+ di.mo = Array.isArray(marker.opacity) ? marker.opacity[id] : marker.opacity;
+ di.mx = Array.isArray(marker.symbol) ? marker.symbol[id] : marker.symbol;
+ di.mc = Array.isArray(marker.color) ? marker.color[id] : marker.color;
+ }
+
+ var line = marker && marker.line;
+ if(line) {
+ di.mlc = Array.isArray(line.color) ? line.color[id] : line.color;
+ di.mlw = Array.isArray(line.width) ? line.width[id] : line.width;
+ }
+
+ var grad = marker && marker.gradient;
+ if(grad && grad.type !== 'none') {
+ di.mgt = Array.isArray(grad.type) ? grad.type[id] : grad.type;
+ 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 hoverlabel = trace.hoverlabel;
+
+ if(hoverlabel) {
+ di.hbg = Array.isArray(hoverlabel.bgcolor) ? hoverlabel.bgcolor[id] : hoverlabel.bgcolor;
+ di.hbc = Array.isArray(hoverlabel.bordercolor) ? hoverlabel.bordercolor[id] : hoverlabel.bordercolor;
+ di.hts = Array.isArray(hoverlabel.font.size) ? hoverlabel.font.size[id] : hoverlabel.font.size;
+ di.htc = Array.isArray(hoverlabel.font.color) ? hoverlabel.font.color[id] : hoverlabel.font.color;
+ di.htf = Array.isArray(hoverlabel.font.family) ? hoverlabel.font.family[id] : hoverlabel.font.family;
+ di.hnl = Array.isArray(hoverlabel.namelength) ? hoverlabel.namelength[id] : hoverlabel.namelength;
+ }
+ var hoverinfo = trace.hoverinfo;
+ if(hoverinfo) {
+ di.hi = Array.isArray(hoverinfo) ? hoverinfo[id] : hoverinfo;
+ }
+
+ var fakeCd = {};
+ fakeCd[pointData.index] = di;
+
+ Lib.extendFlat(pointData, {
+ color: getTraceColor(trace, di),
+
+ x0: xc - rad,
+ x1: xc + rad,
+ xLabelVal: di.x,
+
+ y0: yc - rad,
+ y1: yc + rad,
+ yLabelVal: di.y,
+
+ cd: fakeCd
+ });
+
+ if(di.htx) pointData.text = di.htx;
+ else if(di.tx) pointData.text = di.tx;
+ else if(trace.text) pointData.text = trace.text;
+
+ fillHoverText(di, trace, pointData);
+ ErrorBars.hoverInfo(di, trace, pointData);
+
+ return [pointData];
+}
+
+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 scene = stash.scene;
+
+ if(!scene) return selection;
+
+ var hasOnlyLines = (!subTypes.hasMarkers(trace) && !subTypes.hasText(trace));
+ if(trace.visible !== true || hasOnlyLines) return selection;
+
+ // degenerate polygon does not enable selection
+ // filter out points by visible scatter ones
+ var els = null, unels = null, i;
+ if(polygon !== false && !polygon.degenerate) {
+ els = [], unels = [];
+ for(i = 0; i < stash.count; i++) {
+ if(polygon.contains([stash.xpx[i], stash.ypx[i]])) {
+ els.push(i);
+ selection.push({
+ pointNumber: i,
+ x: rawx ? rawx[i] : x[i],
+ y: rawy ? rawy[i] : y[i]
+ });
+ }
+ else {
+ unels.push(i);
+ }
+ }
+ }
+ else {
+ unels = Array(stash.count);
+ for(i = 0; i < stash.count; i++) {
+ unels[i] = i;
+ }
+ }
+
+ // create selection style once we have something selected
+ if(!scene.selectBatch) {
+ scene.selectBatch = Array(scene.count);
+ scene.unselectBatch = Array(scene.count);
+ scene.scatter2d.update(scene.unselectedOptions);
+ }
+ scene.selectBatch[stash.index] = els;
+ scene.unselectBatch[stash.index] = unels;
+
+ return selection;
+}
+
+function style(gd, cd) {
+ if(cd) {
+ var stash = cd[0].t;
+ var scene = stash.scene;
+ scene.clear();
+ scene.draw();
+ }
+}
+
+module.exports = {
+ moduleType: 'trace',
+ name: 'scattergl',
+ basePlotModule: require('../../plots/cartesian'),
+ categories: ['gl', 'regl', 'cartesian', 'symbols', 'errorBarsOK', 'markerColorscale', 'showLegend', 'scatter-like'],
+
+ attributes: require('./attributes'),
+ supplyDefaults: require('./defaults'),
+ cleanData: require('../scatter/clean_data'),
+ colorbar: require('../scatter/colorbar'),
+ calc: calc,
+ plot: plot,
+ hoverPoints: hoverPoints,
+ style: style,
+ selectPoints: selectPoints,
+
+ sceneOptions: sceneOptions,
+ sceneUpdate: sceneUpdate,
+
+ meta: {
+ hrName: 'scatter_gl',
+ description: [
+ 'The data visualized as scatter point or lines is set in `x` and `y`',
+ 'using the WebGL plotting engine.',
+ 'Bubble charts are achieved by setting `marker.size` and/or `marker.color`',
+ 'to a numerical arrays.'
+ ].join(' ')
+ }
+};
diff --git a/src/traces/scattergl/select.js b/src/traces/scattergl/select.js
deleted file mode 100644
index c2b425bba81..00000000000
--- a/src/traces/scattergl/select.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
-* Copyright 2012-2018, Plotly, Inc.
-* All rights reserved.
-*
-* This source code is licensed under the MIT license found in the
-* LICENSE file in the root directory of this source tree.
-*/
-
-
-'use strict';
-
-var subtypes = require('../scatter/subtypes');
-
-module.exports = function selectPoints(searchInfo, polygon) {
- var cd = searchInfo.cd,
- xa = searchInfo.xaxis,
- ya = searchInfo.yaxis,
- selection = [],
- trace = cd[0].trace,
- i,
- di,
- x,
- y;
-
- var glTrace = cd[0]._glTrace;
-
- if(!glTrace) return;
-
- var scene = glTrace.scene;
-
- var hasOnlyLines = (!subtypes.hasMarkers(trace) && !subtypes.hasText(trace));
- if(hasOnlyLines) return [];
-
- // filter out points by visible scatter ones
- if(polygon === false) {
- // clear selection
- for(i = 0; i < cd.length; i++) cd[i].dim = 0;
- }
- else {
- for(i = 0; i < cd.length; i++) {
- di = cd[i];
- x = xa.c2p(di.x);
- y = ya.c2p(di.y);
- if(polygon.contains([x, y])) {
- selection.push({
- pointNumber: i,
- x: xa.c2d(di.x),
- y: ya.c2d(di.y)
- });
- di.dim = 0;
- }
- else di.dim = 1;
- }
- }
-
- // highlight selected points here
- trace.selection = selection;
-
- glTrace.update(trace, cd);
- scene.glplot.setDirty();
-
- return selection;
-};
diff --git a/src/traces/scatterpolar/hover.js b/src/traces/scatterpolar/hover.js
index b81abf2fa98..8202724a332 100644
--- a/src/traces/scatterpolar/hover.js
+++ b/src/traces/scatterpolar/hover.js
@@ -12,7 +12,7 @@ var scatterHover = require('../scatter/hover');
var Axes = require('../../plots/cartesian/axes');
var Lib = require('../../lib');
-module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
+function hoverPoints(pointData, xval, yval, hovermode) {
var scatterPointData = scatterHover(pointData, xval, yval, hovermode);
if(!scatterPointData || scatterPointData[0].index === false) return;
@@ -25,23 +25,29 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
var subplot = pointData.subplot;
var cdi = newPointData.cd[newPointData.index];
+ var trace = newPointData.trace;
if(!subplot.isPtWithinSector(cdi)) return;
newPointData.xLabelVal = undefined;
newPointData.yLabelVal = undefined;
+ newPointData.extraText = makeHoverPointText(cdi, trace, subplot);
- var trace = newPointData.trace;
+ return scatterPointData;
+}
+
+function makeHoverPointText(cdi, trace, subplot) {
var radialAxis = subplot.radialAxis;
var angularAxis = subplot.angularAxis;
var hoverinfo = cdi.hi || trace.hoverinfo;
var parts = hoverinfo.split('+');
var text = [];
- var rad = angularAxis._c2rad(cdi.theta, trace.thetaunit);
radialAxis._hovertitle = 'r';
angularAxis._hovertitle = 'θ';
+ var rad = angularAxis._c2rad(cdi.theta, trace.thetaunit);
+
// show theta value in unit of angular axis
var theta;
if(angularAxis.type === 'linear' && trace.thetaunit !== angularAxis.thetaunit) {
@@ -58,7 +64,10 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
if(parts.indexOf('r') !== -1) textPart(radialAxis, radialAxis.c2r(cdi.r));
if(parts.indexOf('theta') !== -1) textPart(angularAxis, theta);
- newPointData.extraText = text.join('
');
+ return text.join('
');
+}
- return scatterPointData;
+module.exports = {
+ hoverPoints: hoverPoints,
+ makeHoverPointText: makeHoverPointText
};
diff --git a/src/traces/scatterpolar/index.js b/src/traces/scatterpolar/index.js
index cd7b0734a51..4b16c1c7fed 100644
--- a/src/traces/scatterpolar/index.js
+++ b/src/traces/scatterpolar/index.js
@@ -19,16 +19,16 @@ module.exports = {
calc: require('./calc'),
plot: require('./plot'),
style: require('../scatter/style').style,
- hoverPoints: require('./hover'),
+ hoverPoints: require('./hover').hoverPoints,
selectPoints: require('../scatter/select'),
meta: {
hrName: 'scatter_polar',
description: [
- 'The scatterpolar trace type encompasses line charts, scatter charts, text charts, and bubble charts.',
+ 'The scatterpolar trace type encompasses line charts, scatter charts, text charts, and bubble charts',
'in polar coordinates.',
'The data visualized as scatter point or lines is set in',
- '`r` (radial) and `theta` (angular). coordintes',
+ '`r` (radial) and `theta` (angular) coordinates',
'Text (appearing either on the chart or on hover only) is via `text`.',
'Bubble charts are achieved by setting `marker.size` and/or `marker.color`',
'to numerical arrays.'
diff --git a/src/traces/scatterpolar/plot.js b/src/traces/scatterpolar/plot.js
index 5513416d909..3e5cb62a30b 100644
--- a/src/traces/scatterpolar/plot.js
+++ b/src/traces/scatterpolar/plot.js
@@ -11,7 +11,7 @@
var scatterPlot = require('../scatter/plot');
var BADNUM = require('../../constants/numerical').BADNUM;
-module.exports = function plot(subplot, moduleCalcData) {
+module.exports = function plot(gd, subplot, moduleCalcData) {
var i, j;
var plotinfo = {
@@ -60,5 +60,5 @@ module.exports = function plot(subplot, moduleCalcData) {
}
}
- scatterPlot(subplot.graphDiv, plotinfo, moduleCalcData);
+ scatterPlot(gd, plotinfo, moduleCalcData);
};
diff --git a/src/traces/scatterpolargl/attributes.js b/src/traces/scatterpolargl/attributes.js
new file mode 100644
index 00000000000..6f1ce8c6dc4
--- /dev/null
+++ b/src/traces/scatterpolargl/attributes.js
@@ -0,0 +1,37 @@
+/**
+* Copyright 2012-2018, Plotly, Inc.
+* All rights reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*/
+
+'use strict';
+
+var scatterPolarAttrs = require('../scatterpolar/attributes');
+var scatterGlAttrs = require('../scattergl/attributes');
+
+module.exports = {
+ mode: scatterPolarAttrs.mode,
+ r: scatterPolarAttrs.r,
+ theta: scatterPolarAttrs.theta,
+ thetaunit: scatterPolarAttrs.thetaunit,
+
+ text: scatterPolarAttrs.text,
+ // no hovertext
+
+ line: scatterGlAttrs.line,
+ connectgaps: scatterGlAttrs.connectgaps,
+
+ marker: scatterGlAttrs.marker,
+ // no cliponaxis
+
+ fill: scatterGlAttrs.fill,
+ fillcolor: scatterGlAttrs.fillcolor,
+
+ hoverinfo: scatterPolarAttrs.hoverinfo,
+ hoveron: scatterPolarAttrs.hoveron,
+
+ selected: scatterPolarAttrs.selected,
+ unselected: scatterPolarAttrs.unselected
+};
diff --git a/src/traces/scatterpolargl/defaults.js b/src/traces/scatterpolargl/defaults.js
new file mode 100644
index 00000000000..f34e1e5bce4
--- /dev/null
+++ b/src/traces/scatterpolargl/defaults.js
@@ -0,0 +1,65 @@
+/**
+* Copyright 2012-2018, Plotly, Inc.
+* All rights reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*/
+
+'use strict';
+
+var Lib = require('../../lib');
+
+var subTypes = require('../scatter/subtypes');
+var handleMarkerDefaults = require('../scatter/marker_defaults');
+var handleLineDefaults = require('../scatter/line_defaults');
+var handleFillColorDefaults = require('../scatter/fillcolor_defaults');
+var PTS_LINESONLY = require('../scatter/constants').PTS_LINESONLY;
+
+var attributes = require('./attributes');
+
+module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
+ function coerce(attr, dflt) {
+ return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
+ }
+
+ var r = coerce('r');
+ var theta = coerce('theta');
+ var len = (r && theta) ? Math.min(r.length, theta.length) : 0;
+
+ if(!len) {
+ traceOut.visible = false;
+ return;
+ }
+
+ if(len < r.length) traceOut.r = r.slice(0, len);
+ if(len < theta.length) traceOut.theta = theta.slice(0, len);
+
+ coerce('thetaunit');
+ coerce('mode', len < PTS_LINESONLY ? 'lines+markers' : 'lines');
+ coerce('text');
+
+ if(subTypes.hasLines(traceOut)) {
+ handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce);
+ coerce('connectgaps');
+ }
+
+ var dfltHoverOn = [];
+
+ if(subTypes.hasMarkers(traceOut)) {
+ handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce);
+ dfltHoverOn.push('points');
+ }
+
+ coerce('fill');
+ if(traceOut.fill !== 'none') {
+ handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
+ }
+
+ if(traceOut.fill === 'tonext' || traceOut.fill === 'toself') {
+ dfltHoverOn.push('fills');
+ }
+ coerce('hoveron', dfltHoverOn.join('+') || 'points');
+
+ Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
+};
diff --git a/src/traces/scatterpolargl/index.js b/src/traces/scatterpolargl/index.js
new file mode 100644
index 00000000000..6a7a4a1b94a
--- /dev/null
+++ b/src/traces/scatterpolargl/index.js
@@ -0,0 +1,197 @@
+/**
+* Copyright 2012-2018, Plotly, Inc.
+* All rights reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*/
+
+'use strict';
+
+var kdtree = require('kdgrass');
+var isNumeric = require('fast-isnumeric');
+
+var ScatterGl = require('../scattergl');
+var calcColorscales = require('../scatter/colorscale_calc');
+var Axes = require('../../plots/cartesian/axes');
+var makeHoverPointText = require('../scatterpolar/hover').makeHoverPointText;
+var subTypes = require('../scatter/subtypes');
+
+function calc(container, trace) {
+ var layout = container._fullLayout;
+ var subplotId = trace.subplot;
+ var radialAxis = layout[subplotId].radialaxis;
+ var angularAxis = layout[subplotId].angularaxis;
+ var rArray = radialAxis.makeCalcdata(trace, 'r');
+ var thetaArray = angularAxis.makeCalcdata(trace, 'theta');
+ var stash = {};
+
+ calcColorscales(trace);
+
+ stash.r = rArray;
+ stash.theta = thetaArray;
+
+ Axes.expand(radialAxis, rArray, {tozero: true});
+
+ if(angularAxis.type !== 'linear') {
+ angularAxis.autorange = true;
+ Axes.expand(angularAxis, thetaArray);
+ }
+
+ return [{x: false, y: false, t: stash, trace: trace}];
+}
+
+function plot(container, subplot, cdata) {
+ var radialAxis = subplot.radialAxis;
+ var angularAxis = subplot.angularAxis;
+ var rRange = radialAxis.range;
+
+ var scene = ScatterGl.sceneUpdate(container, subplot);
+ scene.clear();
+
+ cdata.forEach(function(cdscatter, traceIndex) {
+ if(!cdscatter || !cdscatter[0] || !cdscatter[0].trace) return;
+ var cd = cdscatter[0];
+ var trace = cd.trace;
+ var stash = cd.t;
+ var rArray = stash.r;
+ var thetaArray = stash.theta;
+ var i, r, rr, theta, rad;
+
+ var subRArray = rArray.slice();
+ var subThetaArray = thetaArray.slice();
+
+ // filter out by range
+ for(i = 0; i < rArray.length; i++) {
+ r = rArray[i], theta = thetaArray[i];
+ rad = angularAxis.c2rad(theta, trace.thetaunit);
+
+ if(!subplot.isPtWithinSector({r: r, rad: rad})) {
+ subRArray[i] = NaN;
+ subThetaArray[i] = NaN;
+ }
+ }
+
+ var count = rArray.length;
+ var positions = new Array(count * 2), x = Array(count), y = Array(count);
+
+ function c2rad(v) {
+ return angularAxis.c2rad(v, trace.thetaunit);
+ }
+
+ for(i = 0; i < count; i++) {
+ r = subRArray[i];
+ theta = subThetaArray[i];
+
+ if(isNumeric(r) && isNumeric(theta) && r >= 0) {
+ rr = radialAxis.c2r(r) - rRange[0];
+ rad = c2rad(theta);
+
+ x[i] = positions[i * 2] = rr * Math.cos(rad);
+ y[i] = positions[i * 2 + 1] = rr * Math.sin(rad);
+ } else {
+ x[i] = y[i] = positions[i * 2] = positions[i * 2 + 1] = NaN;
+ }
+ }
+
+ var options = ScatterGl.sceneOptions(container, subplot, trace, positions);
+
+ // set flags to create scene renderers
+ if(options.fill && !scene.fill2d) scene.fill2d = true;
+ if(options.marker && !scene.scatter2d) scene.scatter2d = true;
+ if(options.line && !scene.line2d) scene.line2d = true;
+ if((options.errorX || options.errorY) && !scene.error2d) scene.error2d = true;
+
+ // bring positions to selected/unselected options
+ if(subTypes.hasMarkers(trace)) {
+ options.selected.positions = options.unselected.positions = options.marker.positions;
+ }
+
+ // save scene options batch
+ scene.lineOptions.push(options.line);
+ scene.errorXOptions.push(options.errorX);
+ scene.errorYOptions.push(options.errorY);
+ scene.fillOptions.push(options.fill);
+ scene.markerOptions.push(options.marker);
+ scene.selectedOptions.push(options.selected);
+ scene.unselectedOptions.push(options.unselected);
+ scene.count = cdata.length;
+
+ // stash scene ref
+ stash.scene = scene;
+ stash.index = traceIndex;
+ stash.x = x;
+ stash.y = y;
+ stash.rawx = x;
+ stash.rawy = y;
+ stash.r = rArray;
+ stash.theta = thetaArray;
+ stash.positions = positions;
+ stash.count = count;
+ stash.tree = kdtree(positions, 512);
+ });
+
+ return ScatterGl.plot(container, subplot, cdata);
+}
+
+function hoverPoints(pointData, xval, yval, hovermode) {
+ var cd = pointData.cd;
+ var stash = cd[0].t;
+ var rArray = stash.r;
+ var thetaArray = stash.theta;
+
+ var scatterPointData = ScatterGl.hoverPoints(pointData, xval, yval, hovermode);
+ if(!scatterPointData || scatterPointData[0].index === false) return;
+
+ var newPointData = scatterPointData[0];
+
+ if(newPointData.index === undefined) {
+ return scatterPointData;
+ }
+
+ var subplot = pointData.subplot;
+ var angularAxis = subplot.angularAxis;
+ var cdi = newPointData.cd[newPointData.index];
+ var trace = newPointData.trace;
+
+ // augment pointData with r/theta param
+ cdi.r = rArray[newPointData.index];
+ cdi.theta = thetaArray[newPointData.index];
+ cdi.rad = angularAxis.c2rad(cdi.theta, trace.thetaunit);
+
+ if(!subplot.isPtWithinSector(cdi)) return;
+
+ newPointData.xLabelVal = undefined;
+ newPointData.yLabelVal = undefined;
+ newPointData.extraText = makeHoverPointText(cdi, trace, subplot);
+
+ return scatterPointData;
+}
+
+module.exports = {
+ moduleType: 'trace',
+ name: 'scatterpolargl',
+ basePlotModule: require('../../plots/polar'),
+ categories: ['gl', 'regl', 'polar', 'symbols', 'markerColorscale', 'showLegend', 'scatter-like'],
+
+ attributes: require('./attributes'),
+ supplyDefaults: require('./defaults'),
+
+ calc: calc,
+ plot: plot,
+ hoverPoints: hoverPoints,
+ style: ScatterGl.style,
+ selectPoints: ScatterGl.selectPoints,
+
+ meta: {
+ hrName: 'scatter_polar_gl',
+ description: [
+ 'The scatterpolargl trace type encompasses line charts, scatter charts, and bubble charts',
+ 'in polar coordinates using the WebGL plotting engine.',
+ 'The data visualized as scatter point or lines is set in',
+ '`r` (radial) and `theta` (angular) coordinates',
+ 'Bubble charts are achieved by setting `marker.size` and/or `marker.color`',
+ 'to numerical arrays.'
+ ].join(' ')
+ }
+};
diff --git a/src/traces/scatterternary/plot.js b/src/traces/scatterternary/plot.js
index 02dee000684..26b323d306e 100644
--- a/src/traces/scatterternary/plot.js
+++ b/src/traces/scatterternary/plot.js
@@ -11,8 +11,7 @@
var scatterPlot = require('../scatter/plot');
-
-module.exports = function plot(ternary, moduleCalcData) {
+module.exports = function plot(gd, ternary, moduleCalcData) {
var plotContainer = ternary.plotContainer;
// remove all nodes inside the scatter layer
@@ -26,5 +25,5 @@ module.exports = function plot(ternary, moduleCalcData) {
layerClipId: ternary._hasClipOnAxisFalse ? ternary.clipIdRelative : null
};
- scatterPlot(ternary.graphDiv, plotinfo, moduleCalcData);
+ scatterPlot(gd, plotinfo, moduleCalcData);
};
diff --git a/tasks/ci_test.sh b/tasks/ci_test.sh
index 12608154d92..de7ddd51719 100755
--- a/tasks/ci_test.sh
+++ b/tasks/ci_test.sh
@@ -8,7 +8,6 @@ case $CIRCLE_NODE_INDEX in
npm run test-image || EXIT_STATE=$?
npm run test-image-gl2d || EXIT_STATE=$?
npm run test-bundle || EXIT_STATE=$?
- npm run test-syntax || EXIT_STATE=$?
npm run lint || EXIT_STATE=$?
exit $EXIT_STATE
;;
@@ -16,6 +15,7 @@ case $CIRCLE_NODE_INDEX in
1)
npm run test-jasmine || EXIT_STATE=$?
npm run test-export || EXIT_STATE=$?
+ npm run test-syntax || EXIT_STATE=$?
exit $EXIT_STATE
;;
diff --git a/test/image/baselines/gl2d_10.png b/test/image/baselines/gl2d_10.png
index 36932d9a204..b3d8ce18148 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 dbda9d4c0bb..9f35f0bb4fe 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 a8ede620d7d..9a4ae8542e8 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 5797e3ce4a3..85a564fd72c 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_annotations.png b/test/image/baselines/gl2d_annotations.png
index f1d41279b72..7fc9eeae93a 100644
Binary files a/test/image/baselines/gl2d_annotations.png and b/test/image/baselines/gl2d_annotations.png differ
diff --git a/test/image/baselines/gl2d_axes_booleans.png b/test/image/baselines/gl2d_axes_booleans.png
index 378d57d0226..e0350f5c8de 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 79126e72024..5cf474017f0 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
new file mode 100644
index 00000000000..07d41bf98a3
Binary files /dev/null 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 d6c1f079692..6d2711ff435 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_manual.png b/test/image/baselines/gl2d_axes_range_manual.png
index d11f89af02d..0f9047db8fa 100644
Binary files a/test/image/baselines/gl2d_axes_range_manual.png and b/test/image/baselines/gl2d_axes_range_manual.png differ
diff --git a/test/image/baselines/gl2d_axes_range_mode.png b/test/image/baselines/gl2d_axes_range_mode.png
index 18692d3c313..22f6212f49c 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 a038b80cdda..ba6739c52cc 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_connect_gaps.png b/test/image/baselines/gl2d_connect_gaps.png
index 1ca8bb38f1f..69d5a638652 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 a40439641a0..309ec31a081 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 2ea2a53889c..7c2ef3fe710 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
new file mode 100644
index 00000000000..d8b75b45d95
Binary files /dev/null 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 2171e6a505e..038bcef6f67 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
new file mode 100644
index 00000000000..89a268319f9
Binary files /dev/null and b/test/image/baselines/gl2d_layout_image.png differ
diff --git a/test/image/baselines/gl2d_line_dash.png b/test/image/baselines/gl2d_line_dash.png
new file mode 100644
index 00000000000..af3a62f6466
Binary files /dev/null and b/test/image/baselines/gl2d_line_dash.png differ
diff --git a/test/image/baselines/gl2d_marker_line_width.png b/test/image/baselines/gl2d_marker_line_width.png
index 86431cb8663..3ceaa69dce0 100644
Binary files a/test/image/baselines/gl2d_marker_line_width.png and b/test/image/baselines/gl2d_marker_line_width.png differ
diff --git a/test/image/baselines/gl2d_marker_size.png b/test/image/baselines/gl2d_marker_size.png
new file mode 100644
index 00000000000..2aaffd39d60
Binary files /dev/null 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 ab5da027992..f8b4b8eba58 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
new file mode 100644
index 00000000000..c38de480a7f
Binary files /dev/null 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
new file mode 100644
index 00000000000..024f7b7578b
Binary files /dev/null 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 058ce315bbb..6335bb92491 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
new file mode 100644
index 00000000000..389948b230f
Binary files /dev/null and b/test/image/baselines/gl2d_open_marker_line_width.png differ
diff --git a/test/image/baselines/gl2d_scatter-colorscale-colorbar.png b/test/image/baselines/gl2d_scatter-colorscale-colorbar.png
index 73b9ae98016..87f05bdc541 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
new file mode 100644
index 00000000000..0242f8616aa
Binary files /dev/null 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 ead2030832c..0de117bf3d0 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-subplot-panel.png b/test/image/baselines/gl2d_scatter-subplot-panel.png
new file mode 100644
index 00000000000..e65cdfc48ed
Binary files /dev/null and b/test/image/baselines/gl2d_scatter-subplot-panel.png differ
diff --git a/test/image/baselines/gl2d_scatter_fill_self_next.png b/test/image/baselines/gl2d_scatter_fill_self_next.png
new file mode 100644
index 00000000000..42cd181a489
Binary files /dev/null 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
new file mode 100644
index 00000000000..7eae642d04a
Binary files /dev/null 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 b7d0f20651f..b87b1d68337 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 700af178465..1cea44693ad 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 bda5a6a2f36..534e823812d 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 7734163777c..79cef6fec93 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
new file mode 100644
index 00000000000..078e27ed403
Binary files /dev/null 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
new file mode 100644
index 00000000000..437905db4ca
Binary files /dev/null and b/test/image/baselines/gl2d_tick-labels.png differ
diff --git a/test/image/baselines/gl2d_ultra_zoom.png b/test/image/baselines/gl2d_ultra_zoom.png
new file mode 100644
index 00000000000..63d2efa81db
Binary files /dev/null and b/test/image/baselines/gl2d_ultra_zoom.png differ
diff --git a/test/image/baselines/glpolar_scatter.png b/test/image/baselines/glpolar_scatter.png
new file mode 100644
index 00000000000..71c4841359d
Binary files /dev/null and b/test/image/baselines/glpolar_scatter.png differ
diff --git a/test/image/baselines/glpolar_style.png b/test/image/baselines/glpolar_style.png
new file mode 100644
index 00000000000..35f91a65b18
Binary files /dev/null and b/test/image/baselines/glpolar_style.png differ
diff --git a/test/image/compare_pixels_test.js b/test/image/compare_pixels_test.js
index 3a51c9182cd..1094eb7b6c2 100644
--- a/test/image/compare_pixels_test.js
+++ b/test/image/compare_pixels_test.js
@@ -51,8 +51,6 @@ var QUEUE_WAIT = 10;
var pattern = process.argv[2];
var mockList = getMockList(pattern);
var isInQueue = (process.argv[3] === '--queue');
-var isCI = process.env.CIRCLECI;
-
if(mockList.length === 0) {
throw new Error('No mocks found with pattern ' + pattern);
@@ -67,18 +65,12 @@ if(!pattern) {
// gl2d have limited image-test support
if(pattern === 'gl2d_*') {
-
if(!isInQueue) {
console.log('WARN: Running gl2d image tests in batch may lead to unwanted results\n');
}
-
- if(isCI) {
- console.log('Filtering out multiple-subplot gl2d mocks:');
- mockList = mockList
- .filter(untestableGL2DonCIfilter)
- .sort(sortForGL2DonCI);
- console.log('\n');
- }
+ console.log('\nSorting gl2d mocks to avoid gl-shader conflicts');
+ sortGl2dMockList(mockList);
+ console.log('');
}
// main
@@ -111,48 +103,32 @@ function untestableFilter(mockName) {
return cond;
}
-/* gl2d mocks that have multiple subplots
- * can't be generated properly on CircleCI
- * at the moment.
- *
- * For more info see:
- * https://github.com/plotly/plotly.js/pull/980
+/* gl2d pointcloud and other non-regl gl2d mock(s)
+ * must be tested first on in order to work;
+ * sort them here.
*
- */
-function untestableGL2DonCIfilter(mockName) {
- var cond = [
- 'gl2d_multiple_subplots',
- 'gl2d_simple_inset',
- 'gl2d_stacked_coupled_subplots',
- 'gl2d_stacked_subplots'
- ].indexOf(mockName) === -1;
-
- if(!cond) console.log(' -', mockName);
-
- return cond;
-}
-
-/* gl2d pointcloud mock(s) must be tested first
- * on CircleCI in order to work; sort them here.
- *
- * Pointcloud relies on gl-shader@4.2.1 whereas
- * other gl2d trace modules rely on gl-shader@4.2.0,
- * we suspect that the lone gl context on CircleCI is
+ * gl-shader appears to conflict with regl.
+ * We suspect that the lone gl context on CircleCI is
* having issues with dealing with the two different
- * gl-shader versions.
+ * program binding algorithm.
+ *
+ * The problem will be solved by switching all our
+ * WebGL-based trace types to regl.
*
* More info here:
* https://github.com/plotly/plotly.js/pull/1037
*/
-function sortForGL2DonCI(a, b) {
- var root = 'gl2d_pointcloud',
- ai = a.indexOf(root),
- bi = b.indexOf(root);
-
- if(ai < bi) return 1;
- if(ai > bi) return -1;
-
- return 0;
+function sortGl2dMockList(mockList) {
+ var mockNames = ['gl2d_pointcloud-basic', 'gl2d_heatmapgl'];
+ var pos = 0;
+
+ mockNames.forEach(function(m) {
+ var ind = mockList.indexOf(m);
+ var tmp = mockList[pos];
+ mockList[pos] = m;
+ mockList[ind] = tmp;
+ pos++;
+ });
}
function runInBatch(mockList) {
diff --git a/test/image/mocks/gl2d_12.json b/test/image/mocks/gl2d_12.json
index 01d477ea386..1dd1a744dad 100644
--- a/test/image/mocks/gl2d_12.json
+++ b/test/image/mocks/gl2d_12.json
@@ -529,6 +529,7 @@
15389.924680000002,
20509.64777,
10808.47561,
+ 9101.25,
9786.534714,
18678.31435,
25768.25759,
@@ -561,6 +562,7 @@
75.563,
78.098,
72.476,
+ 67.59,
74.002,
74.663,
77.926,
@@ -595,6 +597,7 @@
"Country: Poland
Life Expectancy: 75.563
GDP per capita: 15389.92468
Population: 38518241.0
Year: 2007",
"Country: Portugal
Life Expectancy: 78.098
GDP per capita: 20509.64777
Population: 10642836.0
Year: 2007",
"Country: Romania
Life Expectancy: 72.476
GDP per capita: 10808.47561
Population: 22276056.0
Year: 2007",
+ "Country: Russia
Life Expectancy: 67.59
GDP per capita: 9101.25
Population: 142800000.0
Year: 2007",
"Country: Serbia
Life Expectancy: 74.002
GDP per capita: 9786.534714
Population: 10150265.0
Year: 2007",
"Country: Slovak Republic
Life Expectancy: 74.663
GDP per capita: 18678.31435
Population: 5447502.0
Year: 2007",
"Country: Slovenia
Life Expectancy: 77.926
GDP per capita: 25768.25759
Population: 2009245.0
Year: 2007",
diff --git a/test/image/mocks/gl2d_axes_labels2.json b/test/image/mocks/gl2d_axes_labels2.json
new file mode 100644
index 00000000000..94a3a7d16a7
--- /dev/null
+++ b/test/image/mocks/gl2d_axes_labels2.json
@@ -0,0 +1,15 @@
+{
+ "data": [
+ {
+ "x": ["apples", "oranges", "bananananananas", "cantaloupeeeeww", "khljh"],
+ "y": [8, 7, 6, 5, 4, 3, 2, 1, 0],
+ "type": "scattergl",
+ "fill": "tozeroy"
+ }
+ ],
+ "layout": {
+ "width": 400,
+ "height": 300,
+ "showlegend": false
+ }
+}
diff --git a/test/image/mocks/gl2d_error_bars_log.json b/test/image/mocks/gl2d_error_bars_log.json
new file mode 100644
index 00000000000..02471ffbba1
--- /dev/null
+++ b/test/image/mocks/gl2d_error_bars_log.json
@@ -0,0 +1,10 @@
+{
+ "data": [{
+ "type": "scattergl",
+ "y": [10, 2e4, 5e6],
+ "error_y": {"array": [5, 1e4, 4e6]}
+ }],
+ "layout": {
+ "yaxis": {"type": "log"}
+ }
+}
diff --git a/test/image/mocks/gl2d_layout_image.json b/test/image/mocks/gl2d_layout_image.json
new file mode 100644
index 00000000000..bbdf341604f
--- /dev/null
+++ b/test/image/mocks/gl2d_layout_image.json
@@ -0,0 +1,104 @@
+{
+ "data": [
+ {
+ "x": [1,2,3],
+ "y": ["a", "b", "c"],
+ "type": "scattergl"
+ }, {
+ "x": ["2001-01-01","2002-01-01","2003-01-01"],
+ "y": [10,100,1000],
+ "type": "scattergl",
+ "xaxis": "x2",
+ "yaxis": "y2"
+ }
+ ],
+ "layout": {
+ "plot_bgcolor": "rgba(0,0,0,0)",
+ "xaxis2": {
+ "anchor": "y2"
+ },
+ "yaxis": {
+ "domain": [0, 0.45]
+ },
+ "yaxis2": {
+ "domain": [0.55, 1],
+ "type": "log",
+ "anchor": "x2"
+ },
+ "images": [
+ {
+ "source": "https://images.plot.ly/language-icons/api-home/python-logo.png",
+ "xref": "paper",
+ "yref": "paper",
+ "x": 0,
+ "y": 1,
+ "sizex": 0.2,
+ "sizey": 0.2,
+ "xanchor": "right",
+ "yanchor": "bottom"
+ },
+ {
+ "source": "https://images.plot.ly/language-icons/api-home/js-logo.png",
+ "xref": "x",
+ "yref": "y",
+ "x": 1.5,
+ "y": "b",
+ "sizex": 1,
+ "sizey": 1,
+ "xanchor": "right",
+ "yanchor": "bottom"
+ },
+ {
+ "source": "https://images.plot.ly/language-icons/api-home/r-logo.png",
+ "xref": "x2",
+ "yref": "y2",
+ "x": "2001-01-01",
+ "y": 3,
+ "sizex": 63072000000,
+ "sizey": 2,
+ "sizing": "stretch",
+ "opacity": 0.4,
+ "layer": "below"
+ },
+ {
+ "visible": false,
+ "source": "https://images.plot.ly/language-icons/api-home/python-logo.png",
+ "xref": "x",
+ "yref": "y",
+ "x": 1,
+ "y": 3,
+ "sizex": 2,
+ "sizey": 2,
+ "sizing": "stretch",
+ "opacity": 0.4,
+ "layer": "below"
+ },
+ {
+ "source": "https://images.plot.ly/language-icons/api-home/matlab-logo.png",
+ "xref": "x",
+ "yref": "paper",
+ "x": 3,
+ "y": 0,
+ "sizex": 0.5,
+ "sizey": 1,
+ "opacity": 1,
+ "xanchor": "right",
+ "yanchor": "middle"
+ },
+ {
+ "source": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAAD1CAMAAAAMJ2tNAAAC9FBMVEUAAABEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEettEets5iYiFAAAA+3RSTlMAABVISkcS8/nwPvY/AUZraWpLAwSrtgZSmJZ7DIzRFIvQCAkXqcHAwlce4XQCI7G/L+z+X+sfBx0K5OWEMNTeN/H8VPuXy8jMdiW5ycc6wzJtyqQPho8FGLBbK73FQgsODVxWWRnZLUAqG876pfeFvDbupyYRXn+mvodoO1qauqNiNRD9tSETet9QVbPpb2dyGvXiIuO4M/jTYNZ1YdLmJy7nUbKOrbehU5mD2JFsT0lOMeCBfqLccZXdiETyOO/Pu9tzgCQ5zeqgqImc1xzGKUxF9EOTeRZ3rCB96NpNbp+SXZR8m7SqY6+NncQoLGWugpDtWD3VNDxwZtDaXE4AAAAJcEhZcwAALiMAAC4jAXilP3YAAAu4SURBVHja7Z15fEzXHsDzIyLBtIkZhmna1ExIJQZPyEYsIYKHR2jHTlQsEbEm9n2ndqlYaq21qK3UmvcoLX1FUBTP0r7XV6V9S9u3dP55c3/nZrZ77ph7eTXvvt/vD5+P+zv3nPO995zf+Z3f79xMUBAJCQkJCQkJCQkJCQkJCQkJyS8lUKZssFTKhYAm4MqWD5VKWAVtwAWH2qVSsRLBERzBERzBERzBERzBERzBEdz/KxzoXngxXCIRlfWgBThDFc5N9qpGgiM4giM4giM4giM4giM4giM4ggsAOKhW3SSR6i9FgibgXuYRvBKlDbhXeQQ1CI7gCI7gCI7gCI7gCI7gCI7gCI7gCI7gCI7gCI7gCI7gCI7gCI7g/qfgQGe2cMQAmoCLrlkrRiKv1dYGXGwcT1WH4AiO4AiO4AiO4AiO4AiO4Ajuv0Zg5e4gha8wNQBXtx5nB1m/nDbgftWA02B8Q43ANSI4giM4giM4giM4giM4giM47cOBLjohViIJwp++DQw4SEyK5UiyP9xgrpkSJ5HGTQIHLrWptH9xzYL9grPE8Ko1BQ5c8xYcTVpLDcO1IjiCIziCIziCIziCIziCCxy4Z5fCeuX57AoS01tnSKRNW6Hadr9uL1V1EHZS0PE3Uk37Wp0EVWdOfZldujoI9K9zVK3fsDlU3bpncu7qIdTXsxenF737+AUHfftxxCxUq8/iqWyCysDT9BPOJIOZp4nUOQggmadKBofKym3K6LsXJCQkJCQkJCQkJIEpENk/Ijw84k3zM/ZaIXmAUG//yOfpDYvbLmHn+WzrzR4o1BsXS3AER3AER3BYgW7Q4MFDdKBNuJyhobnD9BqFK5dnt1cxaBIOYLhdu3CRIzQMN3KUhuE62zULB4bRzxcOQG+2mA0AauBAZ7RYEq0gpx4T9wvDQX5CbGwS26FB8qCCseNGxIyvMmHipHxpH33AAWT1nNx2StWYmKnTxk6fMVNys6NAn9GzhNtnz3EeLMxh+Qx3OIAQ4YxkQrQOuM9+rg+ttPi8lLi4+QuEarsufGvRrNIMWIuMxbHePZSFA13CkqmL0pw5vFG9l46xgkeBZQVTyzPtcufBwhWtV3LglhQ6VIVvc4cHmIcJJyhTmvgJh8nC4QCwqnuRR4Jv1uo1FvALDvJfXDvLK0fZbN1c17MB/Tvrczk5xA0bJXBBkNpY+E9eZS7cps2o3OLfAGZw79pgwXxJ23lbZ8KT4QDabWvFSX5uH+Skk8nf8uEMw1C3Q88b/EtRl5GvBO615J2NxUeeG5ob7+zgrq7wJDiA5pmutx0amuZKhFcqpVMCFwS1MSc9vx0HLovV8x4ogdvdshlOtKl79r6/b/9e01BxELVq4p7C5MEBHFgvgh0cdqhHcPCADw4fEQF3dxQ7AbYPq5tMR7vjCz7m/G2b9OPRPLgofFizJnIs2omTgqrRKT/NKoMr2uD4p/jopEisECB6zW9Z/8IWuDXBhSvzO1by9JkxbCCBdWXEK+xaRoLHO65U0Z+lAOAjvLlXpNTist/FecusCA6f6E5XqwArq7DBmdHNJxzoj2O5+O2pbvYDzk5js3BKIiiGC4IDOEWKz0nKRX2MbU0EpXCfvO9xC2RXZdPOrSYe3IwN7MDFMk8j0/U8W1Aqu794f+FsF/DmTyVLUTWcjUfq+rvYO+HG6rxs4KbTeL13vg84MPweC33W06sjcPESg+6rAg4m45Rfv8yrTl11rHOXVSncam/fB+AMDriiar7gLhcKV3IjJA8ZSnDun7yiHM5pUt7xrBWSPhMuX73mt5dWCie1rpDDzMLnruXKGw7gOhZpc0Nq2CzdUVXdNSD8h4ObeO8XRs81Zzp6Ch3ylcJdrQD8fbNjXGbJw1nYxDzOmeHQH8fW6TnK4YKgZ4pwYfMqDzhbTWzsOiiFa9qN073BywXVok3ycLcOotmowGkOEnDpLCqnBs6GmyP7bXcOuIw+1J1U//cOItwIztIBObtx6PeXh7uG+H9YxoNLrIc1z1MBFwR383DQuLl/APeULXIuuPscNxss41HXWR5uHWsvkQcHD5htc01ZBXBRbfAc4F03OPNs9Jm+BMVwY3nds3ZB3QSniyiB+woLpHPbg8WM3KgGDv4oMUczFnnNYb/hJnK71wR103QycADpWOAN/r59P1qUoSEq4Er3NgPnuAzzPGzrT1bFcPEFIBvQsX9tlIOzst3JS3y4jrg7nZ+kCs74Z09PC+bi2rf8BSWhCAaXtpALtwaX8foWOTjbu56T0vPuVDxp23iMGrggWFDkYT7gBD6qzBAVcG9y4QoQLkYWzsiWuXA+HDsjLe7ZFMPdQCe5waRSl+xTcZAoh5MZlt+wvYdZ9s09xAKLfb65durgYKxdDICwIk3Ru++kKEAmGpQlXLgzqKtnk4PTnZc1tQ7tJBxIxy6qgnM8mzvCxbU5DG4/LnwXbGrgrnNXqm9R9whkraVJ9D65NW/BPV2bfJVwxm3ok6M1ACu2lPalssimCGfieYfiqBsrv4izm6fw1zm2wj+0qYQTd2+H8cT4rWP4GhNUwfH+yDdEPkZdhDxcQ7Q4vZK57917hVcGFwRlOghXCwVrC7VxFGwFVXAdsjhw36Fv3qqaPNwmNIjNeHHw0h3DTTW+pduy7djVOfbE55Uvci64O99z4Lagi3GwrjxcVA10AXkBVFiJhfOuqIULggNoUraZAc5iXTH56uA4H8eAfgdbCSw+Nqu72NDjud1/wQDf2iRvuL/6DWeYhgvlZYD+WNc6UAdnHydtMhVDCPa/ye/EHVuTq7jnWSl9NJFv491HwRtuhMXfLA8sFExK/HSwHcZF7oDSLFAp3IYZ3jXr2EIQNthXDCWkg9cDcNk6xG7hFvCACgi3NtpvuOjWwvUu+lvzVSxy7tGvHWav6XzlE7w+O9kXHOxFM1Y4yTv6Fcti7F+7R78GYY0NVvkNB7fRXuW0FCZ/WoHi9J0TruI9vYf3szGDBVdKfMcto3pjscwhnlHPEJwu9uJ97nHLmazKjySvWS75CKuEx5F39+8YnL+lHs5eXCfLNbtgUC129Yu+viPOUPIDlvu4gmujBbqNVVi64HOPVAOwuGPKYO/XLAvHTMqe1fgvqITLE3pYNLtkrpgryN57hLHFdXpSrkB/iEXONx8fJOZJrbc+ZPFc++OLnkP9R1Z0d2Uba8ZsA99pY1goDMhGgl8Z9pPypDKDK6yDe/i8jPR1LffdjTDVEBNuLRoCPCmFlTWFvaX4DVWGF1QO/vH2jtNilucfI72iqtlismvUhXsl+2rfPPrwn0+Cy25TOrBi+qmFO/mvgkWln4O65eda/NvwxPxcEORvzePm59p39B5+0OOq3ZkGTBM/BPUJx0yKIG1BLZyjlZ0DJbnBwm8MfmRWHY7WXmlW1p53fqU0iJ34XpHkK1efpxlgSIrYl+9UHHUQ51wfgO8f/eDRu6sXRur8zIlD6iOvL5NDH/fnetOWtpuVwYnhWRWLnBMud7/DOzX+9GBg6bApijscLPUkci6tEA4aSF08sJ06vj6sdDgvb9ZlYYjMURbrufuFYto2vjizJ4O7Ub8wLm7FpRze46iGYz50spozKgyOuZagX3Ztybw96V99EF4yhxNoBUNOQmxsQraVG+Qsc2r60ldNppfb/nwiycevJIGxbst7r5tMExavGRnFhoajXaHeHN6PDEHzURjuz35auAAUgOP4lh+AFuGicVNVXEFV/wIdbgCa1/pZGoQDY00xVaRFuBkY+0y5rPIQZCDDARzCFzfapkW4s5j+LF+i9mhuAMOBgZ0Ymp2lPTiHnx2GfuB+1d8xBCwc6Huwk4TjkjUDB/pEq/ArkImdTOh42VesUt23wIM7tf3+oTrrvp0qbh/ywkFDcJ5/3yh3wlN8/hvgcCebPM0nyAENl1aj9lP9xGzgwZ3bzUIR8YvGd74I8HR1RYSHhy+pG0DWMqHsz44uhTdM7Qv0N6JISEhISEhISEhISEhISEieg/wHXMU13xThNeUAAABhdEVYdGNvbW1lbnQARmlsZSBzb3VyY2U6IGh0dHA6Ly9jb21tb25zLndpa2ltZWRpYS5vcmcvd2lraS9GaWxlOlBsb3RseV9sb2dvX2Zvcl9kaWdpdGFsX2ZpbmFsXyg2KS5wbmetqmbcAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE0LTA5LTIxVDAzOjM1OjExKzAwOjAwKhOa5QAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0wOS0yMVQwMzozNToxMSswMDowMFtOIlkAAABGdEVYdHNvZnR3YXJlAEltYWdlTWFnaWNrIDYuNi45LTcgMjAxNC0wMy0wNiBRMTYgaHR0cDovL3d3dy5pbWFnZW1hZ2ljay5vcmeB07PDAAAAGHRFWHRUaHVtYjo6RG9jdW1lbnQ6OlBhZ2VzADGn/7svAAAAGXRFWHRUaHVtYjo6SW1hZ2U6OmhlaWdodAAxNzA0VsMjbQAAABh0RVh0VGh1bWI6OkltYWdlOjpXaWR0aAAxNTMxndUDgQAAABl0RVh0VGh1bWI6Ok1pbWV0eXBlAGltYWdlL3BuZz+yVk4AAAAXdEVYdFRodW1iOjpNVGltZQAxNDExMjcwNTEx0Rvi6AAAABN0RVh0VGh1bWI6OlNpemUAMjkuOUtCQvmCzmYAAAAzdEVYdFRodW1iOjpVUkkAZmlsZTovLy90bXAvbG9jYWxjb3B5X2UwNDYwYmM4MDVlYS0xLnBuZ1YfjUoAAAAASUVORK5CYII=",
+ "xref": "paper",
+ "yref": "paper",
+ "x": 0.5,
+ "y": 1,
+ "sizex": 0.2,
+ "sizey": 0.2,
+ "opacity": 1,
+ "xanchor": "middle",
+ "yanchor": "bottom"
+ }
+ ],
+ "width": 800,
+ "height": 500
+ }
+}
diff --git a/test/image/mocks/gl2d_line_dash.json b/test/image/mocks/gl2d_line_dash.json
new file mode 100644
index 00000000000..61723af8144
--- /dev/null
+++ b/test/image/mocks/gl2d_line_dash.json
@@ -0,0 +1,65 @@
+{
+ "data": [
+ {
+ "x": [
+ 1,
+ 2,
+ 3
+ ],
+ "y": [
+ 4,
+ 5,
+ 6
+ ],
+ "marker": {
+ "color": "rgb(54,144,192)",
+ "size": 12,
+ "symbol": "square",
+ "line": {
+ "color": "darkblue",
+ "width": 3
+ },
+ "opacity": 1
+ },
+ "line": {
+ "color": "rgb(3,78,123)",
+ "width": 6,
+ "dash": "dot"
+ },
+ "type": "scattergl"
+ },
+ {
+ "x": [
+ 1,
+ 2,
+ 3
+ ],
+ "y": [
+ 2,
+ 10,
+ 12
+ ],
+ "marker": {
+ "color": "fuchsia",
+ "size": 16,
+ "symbol": "cross",
+ "line": {
+ "color": "",
+ "width": 0
+ },
+ "opacity": 0.9
+ },
+ "line": {
+ "color": "purple",
+ "width": 4,
+ "dash": "dashdot"
+ },
+ "type": "scattergl"
+ }
+ ],
+ "layout": {
+ "showlegend": false,
+ "width": 800,
+ "height": 506
+ }
+}
diff --git a/test/image/mocks/gl2d_marker_size.json b/test/image/mocks/gl2d_marker_size.json
new file mode 100644
index 00000000000..cfd66112331
--- /dev/null
+++ b/test/image/mocks/gl2d_marker_size.json
@@ -0,0 +1,75 @@
+{
+ "data": [
+ {
+ "type": "scattergl",
+ "y": [5, 5, 5, 5],
+ "x": [1, 2, 3, 4],
+ "mode": "markers",
+ "marker": {
+ "color": "rgba(156, 165, 196, 0.8)",
+ "line": {
+ "color": "rgba(0, 0, 0, 0.8)",
+ "width": 5
+ },
+ "symbol": ["circle", "circle-cross-open", "circle-cross", "circle-open"],
+ "size": [20, 20, 20, 20]
+ }
+ },
+ {
+ "type": "scattergl",
+ "y": [10, 10, 10, 10],
+ "x": [1, 2, 3, 4],
+ "mode": "markers",
+ "marker": {
+ "color": "rgba(156, 165, 196, 0.8)",
+ "line": {
+ "color": "rgba(0, 0, 0, 0.8)",
+ "width": 5
+ },
+ "symbol": ["circle", "circle-cross-open", "circle-cross", "circle-open"],
+ "size": 20
+ }
+ },
+ {
+ "type": "scattergl",
+ "y": [15, 15, 15, 15],
+ "x": [1, 2, 3, 4],
+ "mode": "markers",
+ "marker": {
+ "color": "rgba(156, 165, 196, 0.8)",
+ "line": {
+ "color": "rgba(0, 0, 0, 0.8)",
+ "width": [5, 5, 5, 5]
+ },
+ "symbol": ["circle", "circle-cross-open", "circle-cross", "circle-open"],
+ "size": 20
+ }
+ },
+ {
+ "type": "scattergl",
+ "y": [20, 20, 20, 20],
+ "x": [1, 2, 3, 4],
+ "mode": "markers",
+ "marker": {
+ "color": "rgba(156, 165, 196, 0.8)",
+ "line": {
+ "color": "rgba(0, 0, 0, 0.8)",
+ "width": [5, 5, 5, 5]
+ },
+ "symbol": ["circle", "circle-cross-open", "circle-cross", "circle-open"],
+ "size": [20, 20, 20, 20]
+ }
+ }
+ ],
+ "layout": {
+ "margin": {
+ "l": 60,
+ "r": 60,
+ "b": 60,
+ "t": 60
+ },
+ "height": 400,
+ "width": 480,
+ "showlegend": false
+ }
+}
diff --git a/test/image/mocks/gl2d_marker_symbols.json b/test/image/mocks/gl2d_marker_symbols.json
index a0026b59db1..8460619f1b4 100644
--- a/test/image/mocks/gl2d_marker_symbols.json
+++ b/test/image/mocks/gl2d_marker_symbols.json
@@ -4,98 +4,18 @@
"type": "scattergl",
"mode": "markers",
"x": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 2,
- 2,
- 2,
- 2,
- 2,
- 2,
- 2,
- 2,
- 2,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 4,
- 4,
- 4,
- 4,
- 4,
- 4,
- 4,
- 4,
- 4
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4
],
"y": [
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8
],
"marker": {
"symbol": [
@@ -146,104 +66,58 @@
"line-nw"
],
"color": "blue",
- "size": [
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 1,
- 20,
- 1,
- 1,
- 1,
- 1,
- 1,
- 20,
- 1,
- 1,
- 20,
- 1,
- 1,
- 1,
- 1,
- 1,
- 20,
- 20,
- 1,
- 20,
- 1,
- 20,
- 20,
- 1,
- 1,
- 20,
- 20,
- 1,
- 1
- ],
+ "size": 20,
"line": {
"color": "orange",
"width": 1.5
}
},
"text": [
- "marker symbol: circle",
- "marker symbol: square",
- "marker symbol: diamond",
- "marker symbol: cross",
- "marker symbol: x",
- "marker symbol: triangle-up",
- "marker symbol: triangle-down",
- "marker symbol: triangle-left",
- "marker symbol: triangle-right",
- "marker symbol: triangle-ne",
- "marker symbol: triangle-se",
- "marker symbol: triangle-sw",
- "marker symbol: triangle-nw",
- "marker symbol: pentagon",
- "marker symbol: hexagon",
- "marker symbol: hexagon2",
- "marker symbol: octagon
NOT AVAILABLE",
- "marker symbol: star",
- "marker symbol: hexagram
NOT AVAILABLE",
- "marker symbol: star-triangle-up
NOT AVAILABLE",
- "marker symbol: star-triangle-down
NOT AVAILABLE",
- "marker symbol: star-square
NOT AVAILABLE",
- "marker symbol: star-diamond
NOT AVAILABLE",
- "marker symbol: diamond-tall",
- "marker symbol: diamond-wide
NOT AVAILABLE",
- "marker symbol: hourglass
NOT AVAILABLE",
- "marker symbol: bowtie",
- "marker symbol: circle-cross
NOT AVAILABLE",
- "marker symbol: circle-x
NOT AVAILABLE",
- "marker symbol: square-cross
NOT AVAILABLE",
- "marker symbol: square-x
NOT AVAILABLE",
- "marker symbol: diamond-cross
NOT AVAILABLE",
- "marker symbol: diamond-x",
- "marker symbol: cross-thin",
- "marker symbol: x-thin
NOT AVAILABLE",
- "marker symbol: asterisk",
- "marker symbol: hash
NOT AVAILABLE",
- "marker symbol: y-up",
- "marker symbol: y-down",
- "marker symbol: y-left
NOT AVAILABLE",
- "marker symbol: y-right
NOT AVAILABLE",
- "marker symbol: line-ew",
- "marker symbol: line-ns",
- "marker symbol: line-ne
NOT AVAILABLE",
- "marker symbol: line-nw
NOT AVAILABLE"
+ "marker symbol: circle
number: 0",
+ "marker symbol: square
number: 1",
+ "marker symbol: diamond
number: 2",
+ "marker symbol: cross
number: 3",
+ "marker symbol: x
number: 4",
+ "marker symbol: triangle-up
number: 5",
+ "marker symbol: triangle-down
number: 6",
+ "marker symbol: triangle-left
number: 7",
+ "marker symbol: triangle-right
number: 8",
+ "marker symbol: triangle-ne
number: 9",
+ "marker symbol: triangle-se
number: 10",
+ "marker symbol: triangle-sw
number: 11",
+ "marker symbol: triangle-nw
number: 12",
+ "marker symbol: pentagon
number: 13",
+ "marker symbol: hexagon
number: 14",
+ "marker symbol: hexagon2
number: 15",
+ "marker symbol: octagon
number: 16",
+ "marker symbol: star
number: 17",
+ "marker symbol: hexagram
number: 18",
+ "marker symbol: star-triangle-up
number: 19",
+ "marker symbol: star-triangle-down
number: 20",
+ "marker symbol: star-square
number: 21",
+ "marker symbol: star-diamond
number: 22",
+ "marker symbol: diamond-tall
number: 23",
+ "marker symbol: diamond-wide
number: 24",
+ "marker symbol: hourglass
number: 25",
+ "marker symbol: bowtie
number: 26",
+ "marker symbol: circle-cross
number: 27",
+ "marker symbol: circle-x
number: 28",
+ "marker symbol: square-cross
number: 29",
+ "marker symbol: square-x
number: 30",
+ "marker symbol: diamond-cross
number: 31",
+ "marker symbol: diamond-x
number: 32",
+ "marker symbol: cross-thin
number: 33",
+ "marker symbol: x-thin
number: 34",
+ "marker symbol: asterisk
number: 35",
+ "marker symbol: hash
number: 36",
+ "marker symbol: y-up
number: 37",
+ "marker symbol: y-down
number: 38",
+ "marker symbol: y-left
number: 39",
+ "marker symbol: y-right
number: 40",
+ "marker symbol: line-ew
number: 41",
+ "marker symbol: line-ns
number: 42",
+ "marker symbol: line-ne
number: 43",
+ "marker symbol: line-nw
number: 44"
],
"hoverinfo": "text"
},
@@ -251,98 +125,18 @@
"type": "scattergl",
"mode": "markers",
"x": [
- 5,
- 5,
- 5,
- 5,
- 5,
- 5,
- 5,
- 5,
- 5,
- 6,
- 6,
- 6,
- 6,
- 6,
- 6,
- 6,
- 6,
- 6,
- 7,
- 7,
- 7,
- 7,
- 7,
- 7,
- 7,
- 7,
- 7,
- 8,
- 8,
- 8,
- 8,
- 8,
- 8,
- 8,
- 8,
- 8,
- 9,
- 9,
- 9,
- 9,
- 9,
- 9,
- 9,
- 9,
- 9
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9
],
"y": [
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8
],
"marker": {
"symbol": [
@@ -393,104 +187,58 @@
"line-nw-open"
],
"color": "blue",
- "size": [
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 20,
- 1,
- 20,
- 1,
- 1,
- 1,
- 1,
- 1,
- 20,
- 1,
- 1,
- 20,
- 20,
- 20,
- 20,
- 20,
- 1,
- 1,
- 20,
- 1,
- 20,
- 1,
- 20,
- 20,
- 1,
- 1,
- 20,
- 20,
- 1,
- 1
- ],
+ "size": 20,
"line": {
"color": "orange",
"width": 1.5
}
},
"text": [
- "marker symbol: circle-open",
- "marker symbol: square-open",
- "marker symbol: diamond-open",
- "marker symbol: cross-open",
- "marker symbol: x-open",
- "marker symbol: triangle-up-open",
- "marker symbol: triangle-down-open",
- "marker symbol: triangle-left-open",
- "marker symbol: triangle-right-open",
- "marker symbol: triangle-ne-open",
- "marker symbol: triangle-se-open",
- "marker symbol: triangle-sw-open",
- "marker symbol: triangle-nw-open",
- "marker symbol: pentagon-open",
- "marker symbol: hexagon-open",
- "marker symbol: hexagon2-open",
- "marker symbol: octagon-open
NOT AVAILABLE",
- "marker symbol: star-open",
- "marker symbol: hexagram-open
NOT AVAILABLE",
- "marker symbol: star-triangle-up-open
NOT AVAILABLE",
- "marker symbol: star-triangle-down-open
NOT AVAILABLE",
- "marker symbol: star-square-open
NOT AVAILABLE",
- "marker symbol: star-diamond-open
NOT AVAILABLE",
- "marker symbol: diamond-tall-open",
- "marker symbol: diamond-wide-open
NOT AVAILABLE",
- "marker symbol: hourglass-open
NOT AVAILABLE",
- "marker symbol: bowtie-open",
- "marker symbol: circle-cross-open",
- "marker symbol: circle-x-open",
- "marker symbol: square-cross-open",
- "marker symbol: square-x-open",
- "marker symbol: diamond-cross-open
NOT AVAILABLE",
- "marker symbol: diamond-x-open
NOT AVAILABLE",
- "marker symbol: cross-thin-open",
- "marker symbol: x-thin-open
NOT AVAILABLE",
- "marker symbol: asterisk-open",
- "marker symbol: hash-open
NOT AVAILABLE",
- "marker symbol: y-up-open",
- "marker symbol: y-down-open",
- "marker symbol: y-left-open
NOT AVAILABLE",
- "marker symbol: y-right-open
NOT AVAILABLE",
- "marker symbol: line-ew-open",
- "marker symbol: line-ns-open",
- "marker symbol: line-ne-open
NOT AVAILABLE",
- "marker symbol: line-nw-open
NOT AVAILABLE"
+ "marker symbol: circle-open
number: 100",
+ "marker symbol: square-open
number: 101",
+ "marker symbol: diamond-open
number: 102",
+ "marker symbol: cross-open
number: 103",
+ "marker symbol: x-open
number: 104",
+ "marker symbol: triangle-up-open
number: 105",
+ "marker symbol: triangle-down-open
number: 106",
+ "marker symbol: triangle-left-open
number: 107",
+ "marker symbol: triangle-right-open
number: 108",
+ "marker symbol: triangle-ne-open
number: 109",
+ "marker symbol: triangle-se-open
number: 110",
+ "marker symbol: triangle-sw-open
number: 111",
+ "marker symbol: triangle-nw-open
number: 112",
+ "marker symbol: pentagon-open
number: 113",
+ "marker symbol: hexagon-open
number: 114",
+ "marker symbol: hexagon2-open
number: 115",
+ "marker symbol: octagon-open
number: 116",
+ "marker symbol: star-open
number: 117",
+ "marker symbol: hexagram-open
number: 118",
+ "marker symbol: star-triangle-up-open
number: 119",
+ "marker symbol: star-triangle-down-open
number: 120",
+ "marker symbol: star-square-open
number: 121",
+ "marker symbol: star-diamond-open
number: 122",
+ "marker symbol: diamond-tall-open
number: 123",
+ "marker symbol: diamond-wide-open
number: 124",
+ "marker symbol: hourglass-open
number: 125",
+ "marker symbol: bowtie-open
number: 126",
+ "marker symbol: circle-cross-open
number: 127",
+ "marker symbol: circle-x-open
number: 128",
+ "marker symbol: square-cross-open
number: 129",
+ "marker symbol: square-x-open
number: 130",
+ "marker symbol: diamond-cross-open
number: 131",
+ "marker symbol: diamond-x-open
number: 132",
+ "marker symbol: cross-thin-open
number: 133",
+ "marker symbol: x-thin-open
number: 134",
+ "marker symbol: asterisk-open
number: 135",
+ "marker symbol: hash-open
number: 136",
+ "marker symbol: y-up-open
number: 137",
+ "marker symbol: y-down-open
number: 138",
+ "marker symbol: y-left-open
number: 139",
+ "marker symbol: y-right-open
number: 140",
+ "marker symbol: line-ew-open
number: 141",
+ "marker symbol: line-ns-open
number: 142",
+ "marker symbol: line-ne-open
number: 143",
+ "marker symbol: line-nw-open
number: 144"
],
"hoverinfo": "text"
},
@@ -498,98 +246,18 @@
"type": "scattergl",
"mode": "markers",
"x": [
- 10,
- 10,
- 10,
- 10,
- 10,
- 10,
- 10,
- 10,
- 10,
- 11,
- 11,
- 11,
- 11,
- 11,
- 11,
- 11,
- 11,
- 11,
- 12,
- 12,
- 12,
- 12,
- 12,
- 12,
- 12,
- 12,
- 12,
- 13,
- 13,
- 13,
- 13,
- 13,
- 13,
- 13,
- 13,
- 13,
- 14,
- 14,
- 14,
- 14,
- 14,
- 14,
- 14,
- 14,
- 14
+ 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14
],
"y": [
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8
],
"marker": {
"symbol": [
@@ -640,104 +308,58 @@
"line-nw-dot"
],
"color": "blue",
- "size": [
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1
- ],
+ "size": 20,
"line": {
"color": "orange",
"width": 1.5
}
},
"text": [
- "marker symbol: circle-dot
NOT AVAILABLE",
- "marker symbol: square-dot
NOT AVAILABLE",
- "marker symbol: diamond-dot
NOT AVAILABLE",
- "marker symbol: cross-dot
NOT AVAILABLE",
- "marker symbol: x-dot
NOT AVAILABLE",
- "marker symbol: triangle-up-dot
NOT AVAILABLE",
- "marker symbol: triangle-down-dot
NOT AVAILABLE",
- "marker symbol: triangle-left-dot
NOT AVAILABLE",
- "marker symbol: triangle-right-dot
NOT AVAILABLE",
- "marker symbol: triangle-ne-dot
NOT AVAILABLE",
- "marker symbol: triangle-se-dot
NOT AVAILABLE",
- "marker symbol: triangle-sw-dot
NOT AVAILABLE",
- "marker symbol: triangle-nw-dot
NOT AVAILABLE",
- "marker symbol: pentagon-dot
NOT AVAILABLE",
- "marker symbol: hexagon-dot
NOT AVAILABLE",
- "marker symbol: hexagon2-dot
NOT AVAILABLE",
- "marker symbol: octagon-dot
NOT AVAILABLE",
- "marker symbol: star-dot
NOT AVAILABLE",
- "marker symbol: hexagram-dot
NOT AVAILABLE",
- "marker symbol: star-triangle-up-dot
NOT AVAILABLE",
- "marker symbol: star-triangle-down-dot
NOT AVAILABLE",
- "marker symbol: star-square-dot
NOT AVAILABLE",
- "marker symbol: star-diamond-dot
NOT AVAILABLE",
- "marker symbol: diamond-tall-dot
NOT AVAILABLE",
- "marker symbol: diamond-wide-dot
NOT AVAILABLE",
- "marker symbol: hourglass-dot
NOT AVAILABLE",
- "marker symbol: bowtie-dot
NOT AVAILABLE",
- "marker symbol: circle-cross-dot
NOT AVAILABLE",
- "marker symbol: circle-x-dot
NOT AVAILABLE",
- "marker symbol: square-cross-dot
NOT AVAILABLE",
- "marker symbol: square-x-dot
NOT AVAILABLE",
- "marker symbol: diamond-cross-dot
NOT AVAILABLE",
- "marker symbol: diamond-x-dot
NOT AVAILABLE",
- "marker symbol: cross-thin-dot
NOT AVAILABLE",
- "marker symbol: x-thin-dot
NOT AVAILABLE",
- "marker symbol: asterisk-dot
NOT AVAILABLE",
- "marker symbol: hash-dot
NOT AVAILABLE",
- "marker symbol: y-up-dot
NOT AVAILABLE",
- "marker symbol: y-down-dot
NOT AVAILABLE",
- "marker symbol: y-left-dot
NOT AVAILABLE",
- "marker symbol: y-right-dot
NOT AVAILABLE",
- "marker symbol: line-ew-dot
NOT AVAILABLE",
- "marker symbol: line-ns-dot
NOT AVAILABLE",
- "marker symbol: line-ne-dot
NOT AVAILABLE",
- "marker symbol: line-nw-dot
NOT AVAILABLE"
+ "marker symbol: circle-dot
number: 200",
+ "marker symbol: square-dot
number: 201",
+ "marker symbol: diamond-dot
number: 202",
+ "marker symbol: cross-dot
number: 203",
+ "marker symbol: x-dot
number: 204",
+ "marker symbol: triangle-up-dot
number: 205",
+ "marker symbol: triangle-down-dot
number: 206",
+ "marker symbol: triangle-left-dot
number: 207",
+ "marker symbol: triangle-right-dot
number: 208",
+ "marker symbol: triangle-ne-dot
number: 209",
+ "marker symbol: triangle-se-dot
number: 210",
+ "marker symbol: triangle-sw-dot
number: 211",
+ "marker symbol: triangle-nw-dot
number: 212",
+ "marker symbol: pentagon-dot
number: 213",
+ "marker symbol: hexagon-dot
number: 214",
+ "marker symbol: hexagon2-dot
number: 215",
+ "marker symbol: octagon-dot
number: 216",
+ "marker symbol: star-dot
number: 217",
+ "marker symbol: hexagram-dot
number: 218",
+ "marker symbol: star-triangle-up-dot
number: 219",
+ "marker symbol: star-triangle-down-dot
number: 220",
+ "marker symbol: star-square-dot
number: 221",
+ "marker symbol: star-diamond-dot
number: 222",
+ "marker symbol: diamond-tall-dot
number: 223",
+ "marker symbol: diamond-wide-dot
number: 224",
+ "marker symbol: hourglass-dot
number: 225",
+ "marker symbol: bowtie-dot
number: 226",
+ "marker symbol: circle-cross-dot
number: 227",
+ "marker symbol: circle-x-dot
number: 228",
+ "marker symbol: square-cross-dot
number: 229",
+ "marker symbol: square-x-dot
number: 230",
+ "marker symbol: diamond-cross-dot
number: 231",
+ "marker symbol: diamond-x-dot
number: 232",
+ "marker symbol: cross-thin-dot
number: 233",
+ "marker symbol: x-thin-dot
number: 234",
+ "marker symbol: asterisk-dot
number: 235",
+ "marker symbol: hash-dot
number: 236",
+ "marker symbol: y-up-dot
number: 237",
+ "marker symbol: y-down-dot
number: 238",
+ "marker symbol: y-left-dot
number: 239",
+ "marker symbol: y-right-dot
number: 240",
+ "marker symbol: line-ew-dot
number: 241",
+ "marker symbol: line-ns-dot
number: 242",
+ "marker symbol: line-ne-dot
number: 243",
+ "marker symbol: line-nw-dot
number: 244"
],
"hoverinfo": "text"
},
@@ -745,98 +367,18 @@
"type": "scattergl",
"mode": "markers",
"x": [
- 15,
- 15,
- 15,
- 15,
- 15,
- 15,
- 15,
- 15,
- 15,
- 16,
- 16,
- 16,
- 16,
- 16,
- 16,
- 16,
- 16,
- 16,
- 17,
- 17,
- 17,
- 17,
- 17,
- 17,
- 17,
- 17,
- 17,
- 18,
- 18,
- 18,
- 18,
- 18,
- 18,
- 18,
- 18,
- 18,
- 19,
- 19,
- 19,
- 19,
- 19,
- 19,
- 19,
- 19,
- 19
+ 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19
],
"y": [
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- 8,
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8
],
"marker": {
"symbol": [
@@ -887,104 +429,58 @@
"line-nw-open-dot"
],
"color": "blue",
- "size": [
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1
- ],
+ "size": 20,
"line": {
"color": "orange",
"width": 1.5
}
},
"text": [
- "marker symbol: circle-open-dot
NOT AVAILABLE",
- "marker symbol: square-open-dot
NOT AVAILABLE",
- "marker symbol: diamond-open-dot
NOT AVAILABLE",
- "marker symbol: cross-open-dot
NOT AVAILABLE",
- "marker symbol: x-open-dot
NOT AVAILABLE",
- "marker symbol: triangle-up-open-dot
NOT AVAILABLE",
- "marker symbol: triangle-down-open-dot
NOT AVAILABLE",
- "marker symbol: triangle-left-open-dot
NOT AVAILABLE",
- "marker symbol: triangle-right-open-dot
NOT AVAILABLE",
- "marker symbol: triangle-ne-open-dot
NOT AVAILABLE",
- "marker symbol: triangle-se-open-dot
NOT AVAILABLE",
- "marker symbol: triangle-sw-open-dot
NOT AVAILABLE",
- "marker symbol: triangle-nw-open-dot
NOT AVAILABLE",
- "marker symbol: pentagon-open-dot
NOT AVAILABLE",
- "marker symbol: hexagon-open-dot
NOT AVAILABLE",
- "marker symbol: hexagon2-open-dot
NOT AVAILABLE",
- "marker symbol: octagon-open-dot
NOT AVAILABLE",
- "marker symbol: star-open-dot
NOT AVAILABLE",
- "marker symbol: hexagram-open-dot
NOT AVAILABLE",
- "marker symbol: star-triangle-up-open-dot
NOT AVAILABLE",
- "marker symbol: star-triangle-down-open-dot
NOT AVAILABLE",
- "marker symbol: star-square-open-dot
NOT AVAILABLE",
- "marker symbol: star-diamond-open-dot
NOT AVAILABLE",
- "marker symbol: diamond-tall-open-dot
NOT AVAILABLE",
- "marker symbol: diamond-wide-open-dot
NOT AVAILABLE",
- "marker symbol: hourglass-open-dot
NOT AVAILABLE",
- "marker symbol: bowtie-open-dot
NOT AVAILABLE",
- "marker symbol: circle-cross-open-dot
NOT AVAILABLE",
- "marker symbol: circle-x-open-dot
NOT AVAILABLE",
- "marker symbol: square-cross-open-dot
NOT AVAILABLE",
- "marker symbol: square-x-open-dot
NOT AVAILABLE",
- "marker symbol: diamond-cross-open-dot
NOT AVAILABLE",
- "marker symbol: diamond-x-open-dot
NOT AVAILABLE",
- "marker symbol: cross-thin-open-dot
NOT AVAILABLE",
- "marker symbol: x-thin-open-dot
NOT AVAILABLE",
- "marker symbol: asterisk-open-dot
NOT AVAILABLE",
- "marker symbol: hash-open-dot
NOT AVAILABLE",
- "marker symbol: y-up-open-dot
NOT AVAILABLE",
- "marker symbol: y-down-open-dot
NOT AVAILABLE",
- "marker symbol: y-left-open-dot
NOT AVAILABLE",
- "marker symbol: y-right-open-dot
NOT AVAILABLE",
- "marker symbol: line-ew-open-dot
NOT AVAILABLE",
- "marker symbol: line-ns-open-dot
NOT AVAILABLE",
- "marker symbol: line-ne-open-dot
NOT AVAILABLE",
- "marker symbol: line-nw-open-dot
NOT AVAILABLE"
+ "marker symbol: circle-open-dot
number: 300",
+ "marker symbol: square-open-dot
number: 301",
+ "marker symbol: diamond-open-dot
number: 302",
+ "marker symbol: cross-open-dot
number: 303",
+ "marker symbol: x-open-dot
number: 304",
+ "marker symbol: triangle-up-open-dot
number: 305",
+ "marker symbol: triangle-down-open-dot
number: 306",
+ "marker symbol: triangle-left-open-dot
number: 307",
+ "marker symbol: triangle-right-open-dot
number: 308",
+ "marker symbol: triangle-ne-open-dot
number: 309",
+ "marker symbol: triangle-se-open-dot
number: 310",
+ "marker symbol: triangle-sw-open-dot
number: 311",
+ "marker symbol: triangle-nw-open-dot
number: 312",
+ "marker symbol: pentagon-open-dot
number: 313",
+ "marker symbol: hexagon-open-dot
number: 314",
+ "marker symbol: hexagon2-open-dot
number: 315",
+ "marker symbol: octagon-open-dot
number: 316",
+ "marker symbol: star-open-dot
number: 317",
+ "marker symbol: hexagram-open-dot
number: 318",
+ "marker symbol: star-triangle-up-open-dot
number: 319",
+ "marker symbol: star-triangle-down-open-dot
number: 320",
+ "marker symbol: star-square-open-dot
number: 321",
+ "marker symbol: star-diamond-open-dot
number: 322",
+ "marker symbol: diamond-tall-open-dot
number: 323",
+ "marker symbol: diamond-wide-open-dot
number: 324",
+ "marker symbol: hourglass-open-dot
number: 325",
+ "marker symbol: bowtie-open-dot
number: 326",
+ "marker symbol: circle-cross-open-dot
number: 327",
+ "marker symbol: circle-x-open-dot
number: 328",
+ "marker symbol: square-cross-open-dot
number: 329",
+ "marker symbol: square-x-open-dot
number: 330",
+ "marker symbol: diamond-cross-open-dot
number: 331",
+ "marker symbol: diamond-x-open-dot
number: 332",
+ "marker symbol: cross-thin-open-dot
number: 333",
+ "marker symbol: x-thin-open-dot
number: 334",
+ "marker symbol: asterisk-open-dot
number: 335",
+ "marker symbol: hash-open-dot
number: 336",
+ "marker symbol: y-up-open-dot
number: 337",
+ "marker symbol: y-down-open-dot
number: 338",
+ "marker symbol: y-left-open-dot
number: 339",
+ "marker symbol: y-right-open-dot
number: 340",
+ "marker symbol: line-ew-open-dot
number: 341",
+ "marker symbol: line-ns-open-dot
number: 342",
+ "marker symbol: line-ne-open-dot
number: 343",
+ "marker symbol: line-nw-open-dot
number: 344"
],
"hoverinfo": "text"
}
@@ -1004,26 +500,11 @@
},
"yaxis": {
"showgrid": false,
- "zeroline": false
+ "zeroline": false,
+ "autorange": "reversed"
},
"showlegend": false,
- "hovermode": "closest",
"plot_bgcolor": "#d3d3d3",
- "annotations": [
- {
- "showarrow": false,
- "xref": "paper",
- "yref": "paper",
- "x": 1,
- "xanchor": "right",
- "y": 0.5,
- "yanchor": "middle",
- "xshift": -15,
- "text": "IMPORTANT: marker symbol 'x' and 'x-open'
do not render in the imagetest container",
- "font": {
- "size": 16
- }
- }
- ]
+ "hovermode": "closest"
}
}
diff --git a/test/image/mocks/gl2d_multiple-traces-axes-labels.json b/test/image/mocks/gl2d_multiple-traces-axes-labels.json
new file mode 100644
index 00000000000..8fef3c2a7e7
--- /dev/null
+++ b/test/image/mocks/gl2d_multiple-traces-axes-labels.json
@@ -0,0 +1,64 @@
+{
+ "data": [
+ {
+ "x": [
+ 0,
+ 1,
+ 2
+ ],
+ "y": [
+ 0,
+ 1,
+ 2
+ ],
+ "mode": "lines+markers",
+ "type": "scattergl"
+ },
+ {
+ "x": [
+ 0,
+ 1,
+ 2
+ ],
+ "y": [
+ 2,
+ 1,
+ 0
+ ],
+ "mode": "lines+markers",
+ "type": "scattergl",
+ "yaxis": "y2",
+ "xaxis": "x2"
+ }
+ ],
+ "layout": {
+ "width": 700,
+ "height": 500,
+ "showlegend": false,
+ "yaxis": {
+ "side": "right",
+ "tickmode": "array",
+ "ticktext": ["RightZero", "RightOne", "RightTwo"],
+ "tickvals": [0,1,2]
+ },
+ "yaxis2": {
+ "side": "left",
+ "tickmode": "array",
+ "ticktext": ["LeftZero", "LeftOne", "LeftTwo"],
+ "tickvals": [0,1,2],
+ "overlaying": "y"
+ },
+ "xaxis": {
+ "side": "top",
+ "tickmode": "array",
+ "ticktext": ["TopZero", "TopOne", "TopTwo"],
+ "tickvals": [0,1,2]
+ },
+ "xaxis2": {
+ "side": "bottom",
+ "tickmode": "array",
+ "ticktext": ["BottomZero", "BottomOne", "BottomTwo"],
+ "tickvals": [0,1,2]
+ }
+ }
+}
diff --git a/test/image/mocks/gl2d_multiple-traces-axes.json b/test/image/mocks/gl2d_multiple-traces-axes.json
new file mode 100644
index 00000000000..4818a13964c
--- /dev/null
+++ b/test/image/mocks/gl2d_multiple-traces-axes.json
@@ -0,0 +1,45 @@
+{
+ "data": [
+ {
+ "x": [
+ 0,
+ 1,
+ 2
+ ],
+ "y": [
+ 0,
+ 1,
+ 2
+ ],
+ "mode": "lines+markers",
+ "type": "scattergl"
+ },
+ {
+ "x": [
+ 0,
+ 1,
+ 2
+ ],
+ "y": [
+ 2,
+ 1,
+ 0
+ ],
+ "mode": "lines+markers",
+ "type": "scattergl",
+ "yaxis": "y2"
+ }
+ ],
+ "layout": {
+ "width": 700,
+ "height": 500,
+ "showlegend": false,
+ "yaxis": {
+ "side": "left"
+ },
+ "yaxis2": {
+ "side": "right",
+ "overlaying": "y"
+ }
+ }
+}
diff --git a/test/image/mocks/gl2d_open_marker_line_width.json b/test/image/mocks/gl2d_open_marker_line_width.json
new file mode 100644
index 00000000000..1b85cb2d9a3
--- /dev/null
+++ b/test/image/mocks/gl2d_open_marker_line_width.json
@@ -0,0 +1,12 @@
+{
+ "data": [{
+ "y": [1, 2, 3],
+ "marker": {"symbol": "circle-open", "size": 20},
+ "type": "scattergl",
+ "mode": "markers"
+ }],
+ "layout": {
+ "height": 400,
+ "width": 480
+ }
+}
diff --git a/test/image/mocks/gl2d_scatter-colorscale-points.json b/test/image/mocks/gl2d_scatter-colorscale-points.json
new file mode 100644
index 00000000000..71610e14304
--- /dev/null
+++ b/test/image/mocks/gl2d_scatter-colorscale-points.json
@@ -0,0 +1,1237 @@
+{
+ "data": [
+ {
+ "x": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 96,
+ 97,
+ 98,
+ 99,
+ 100,
+ 101,
+ 102,
+ 103,
+ 104,
+ 105,
+ 106,
+ 107,
+ 108,
+ 109,
+ 110,
+ 111,
+ 112,
+ 113,
+ 114,
+ 115,
+ 116,
+ 117,
+ 118,
+ 119,
+ 120,
+ 121,
+ 122,
+ 123,
+ 124,
+ 125,
+ 126,
+ 127,
+ 128,
+ 129,
+ 130,
+ 131,
+ 132,
+ 133,
+ 134,
+ 135,
+ 136,
+ 137,
+ 138,
+ 139,
+ 140,
+ 141,
+ 142,
+ 143,
+ 144,
+ 145,
+ 146,
+ 147,
+ 148,
+ 149,
+ 150,
+ 151,
+ 152,
+ 153,
+ 154,
+ 155,
+ 156,
+ 157,
+ 158,
+ 159,
+ 160,
+ 161,
+ 162,
+ 163,
+ 164,
+ 165,
+ 166,
+ 167,
+ 168,
+ 169,
+ 170,
+ 171,
+ 172,
+ 173,
+ 174,
+ 175,
+ 176,
+ 177,
+ 178,
+ 179,
+ 180,
+ 181,
+ 182,
+ 183,
+ 184,
+ 185,
+ 186,
+ 187,
+ 188,
+ 189,
+ 190,
+ 191,
+ 192,
+ 193,
+ 194,
+ 195,
+ 196,
+ 197,
+ 198,
+ 199,
+ 200,
+ 201,
+ 202,
+ 203,
+ 204,
+ 205,
+ 206,
+ 207,
+ 208,
+ 209,
+ 210,
+ 211,
+ 212,
+ 213,
+ 214,
+ 215,
+ 216,
+ 217,
+ 218,
+ 219,
+ 220,
+ 221,
+ 222,
+ 223,
+ 224,
+ 225,
+ 226,
+ 227,
+ 228,
+ 229,
+ 230,
+ 231,
+ 232,
+ 233,
+ 234,
+ 235,
+ 236,
+ 237,
+ 238,
+ 239,
+ 240,
+ 241,
+ 242,
+ 243,
+ 244,
+ 245,
+ 246,
+ 247,
+ 248,
+ 249,
+ 250,
+ 251,
+ 252,
+ 253,
+ 254,
+ 255,
+ 256,
+ 257,
+ 258,
+ 259,
+ 260,
+ 261,
+ 262,
+ 263,
+ 264,
+ 265,
+ 266,
+ 267,
+ 268,
+ 269,
+ 270,
+ 271,
+ 272,
+ 273,
+ 274,
+ 275,
+ 276,
+ 277,
+ 278,
+ 279,
+ 280,
+ 281,
+ 282,
+ 283,
+ 284,
+ 285,
+ 286,
+ 287,
+ 288,
+ 289,
+ 290,
+ 291,
+ 292,
+ 293,
+ 294,
+ 295,
+ 296,
+ 297,
+ 298,
+ 299,
+ 300,
+ 301,
+ 302,
+ 303,
+ 304,
+ 305,
+ 306,
+ 307,
+ 308,
+ 309,
+ 310,
+ 311,
+ 312,
+ 313,
+ 314,
+ 315,
+ 316,
+ 317,
+ 318,
+ 319,
+ 320,
+ 321,
+ 322,
+ 323,
+ 324,
+ 325,
+ 326,
+ 327,
+ 328,
+ 329,
+ 330,
+ 331,
+ 332,
+ 333,
+ 334,
+ 335,
+ 336,
+ 337,
+ 338,
+ 339,
+ 340,
+ 341,
+ 342,
+ 343,
+ 344,
+ 345,
+ 346,
+ 347,
+ 348,
+ 349,
+ 350,
+ 351,
+ 352,
+ 353,
+ 354,
+ 355,
+ 356,
+ 357,
+ 358,
+ 359,
+ 360,
+ 361,
+ 362,
+ 363,
+ 364,
+ 365,
+ 366,
+ 367,
+ 368,
+ 369,
+ 370,
+ 371,
+ 372,
+ 373,
+ 374,
+ 375,
+ 376,
+ 377,
+ 378,
+ 379,
+ 380,
+ 381,
+ 382,
+ 383,
+ 384,
+ 385,
+ 386,
+ 387,
+ 388,
+ 389,
+ 390,
+ 391,
+ 392,
+ 393,
+ 394,
+ 395,
+ 396,
+ 397,
+ 398,
+ 399
+ ],
+ "y": [
+ 0.4616274593988976,
+ 0.6159658554953507,
+ 0.14733135643810646,
+ 0.5667641205161871,
+ 0.7354441683995987,
+ 0.09338282979231982,
+ 0.9903377749890259,
+ 0.5374308078056822,
+ 0.9277476505822664,
+ 0.08323004128218803,
+ 0.9262424431459373,
+ 0.07721861833625465,
+ 0.316806534455903,
+ 0.6905645938270328,
+ 0.37499535022676067,
+ 0.5237723768049043,
+ 0.07464909758755889,
+ 0.7077805788454765,
+ 0.45225009860017584,
+ 0.6674148981584085,
+ 0.5628508733412807,
+ 0.8018137470292497,
+ 0.343843747049178,
+ 0.9852293530378662,
+ 0.1066338394930828,
+ 0.24260373567303994,
+ 0.2581380475938495,
+ 0.057177653812069185,
+ 0.35629696373744535,
+ 0.7436452620337728,
+ 0.6692344231471397,
+ 0.5949462020755851,
+ 0.6576636129468314,
+ 0.019977683605029606,
+ 0.7754966777776147,
+ 0.3409475469762202,
+ 0.10505752857151562,
+ 0.5382664472162011,
+ 0.23422301844320104,
+ 0.23120408514083857,
+ 0.17626801625836364,
+ 0.9591028652096454,
+ 0.08931992353086238,
+ 0.3932366071090292,
+ 0.39540802372591943,
+ 0.4470022120346193,
+ 0.4082122355215174,
+ 0.28267768821700145,
+ 0.8055901137799373,
+ 0.45208617372232274,
+ 0.39706239364332907,
+ 0.631886787018654,
+ 0.14090506326963959,
+ 0.6371557878101777,
+ 0.8693697292009528,
+ 0.9103872263778481,
+ 0.07206796438983165,
+ 0.7696288091366807,
+ 0.6904741191669677,
+ 0.44478304308488803,
+ 0.29879600726642175,
+ 0.06813133964789775,
+ 0.46375344844705224,
+ 0.6361148045916376,
+ 0.3714141768131616,
+ 0.4689894633900966,
+ 0.05376791543207715,
+ 0.9582074400644287,
+ 0.14149996361590467,
+ 0.9626720891064184,
+ 0.1598460224513516,
+ 0.3109994711314612,
+ 0.4510794057508736,
+ 0.9752152356511024,
+ 0.962017602946641,
+ 0.04206549382806779,
+ 0.4271502037227095,
+ 0.7338711489031002,
+ 0.19179244410313867,
+ 0.12479799491908894,
+ 0.40058917261911997,
+ 0.10793111399724986,
+ 0.9506121571546589,
+ 0.9980834693872784,
+ 0.2616729510381006,
+ 0.19918907515056117,
+ 0.26124827064167366,
+ 0.04700351146651194,
+ 0.643077267949713,
+ 0.16204159494738213,
+ 0.9389644666328048,
+ 0.8190032324635506,
+ 0.5914276573736743,
+ 0.08259525135228696,
+ 0.48296177521703476,
+ 0.558865410234807,
+ 0.5216047222486184,
+ 0.8388268216175738,
+ 0.26564121945521646,
+ 0.2642720521826212,
+ 0.7058731057826744,
+ 0.9821568189706535,
+ 0.39951561657266943,
+ 0.9905094625707764,
+ 0.8450910732070214,
+ 0.9492521533827545,
+ 0.26888799320812673,
+ 0.911118018018567,
+ 0.10742216581354813,
+ 0.17801260994893053,
+ 0.6280583783264748,
+ 0.5385121890208695,
+ 0.9079632784981913,
+ 0.12680855373314448,
+ 0.12770805911064564,
+ 0.25995662925105845,
+ 0.4296569502097418,
+ 0.837785176224509,
+ 0.643330550187764,
+ 0.6808400004172752,
+ 0.458710827955672,
+ 0.16009454133122136,
+ 0.8202231073239015,
+ 0.9053967045598783,
+ 0.5365994711573248,
+ 0.9960075151497787,
+ 0.02510969842621913,
+ 0.35105842745514293,
+ 0.8849890732014707,
+ 0.7573538142230878,
+ 0.17956914547596736,
+ 0.08647183700547911,
+ 0.779984937808065,
+ 0.6690858604662955,
+ 0.1825514085080555,
+ 0.7359140104581448,
+ 0.4832450064132081,
+ 0.004680006424105487,
+ 0.054129657907077355,
+ 0.9182711683702454,
+ 0.17426199250373742,
+ 0.7853499017423882,
+ 0.2392366970036739,
+ 0.7045245458632703,
+ 0.7397575678970407,
+ 0.5808965620927102,
+ 0.1573642283554464,
+ 0.7838078499029744,
+ 0.022809643682487835,
+ 0.25947607091712444,
+ 0.07927158226754316,
+ 0.7572333743691615,
+ 0.3480185053274718,
+ 0.5025769378049088,
+ 0.6349254301237339,
+ 0.44220130982305283,
+ 0.2941873838636848,
+ 0.8658457980943166,
+ 0.33718988202636924,
+ 0.36399771149412774,
+ 0.2557140683022996,
+ 0.4260817100484571,
+ 0.12621985914398337,
+ 0.620518125979105,
+ 0.71987614384816,
+ 0.8003673309522548,
+ 0.9996415897476298,
+ 0.06719734135151567,
+ 0.9322866387654336,
+ 0.9283012232007972,
+ 0.08059383278114773,
+ 0.3063677423829876,
+ 0.08986664990867044,
+ 0.0975448245056838,
+ 0.7379632992176663,
+ 0.03416009401780329,
+ 0.8624901126846831,
+ 0.09334710918984412,
+ 0.6351625533840559,
+ 0.9342129690958965,
+ 0.08816460719920438,
+ 0.6500019434623974,
+ 0.13755828831488137,
+ 0.7445637838163035,
+ 0.6771472592740897,
+ 0.8693468361877688,
+ 0.28271259888642786,
+ 0.9471270953710687,
+ 0.6432180599730659,
+ 0.8881795753841952,
+ 0.7497327903558746,
+ 0.20031859209199676,
+ 0.4889183672926736,
+ 0.44223497603677986,
+ 0.07762978987423819,
+ 0.9698795565530265,
+ 0.8720673433469355,
+ 0.5848448655198397,
+ 0.6093877444520419,
+ 0.2600479448594426,
+ 0.8961071076491984,
+ 0.7827239150324312,
+ 0.03243647484491774,
+ 0.4347393417626588,
+ 0.48205770886363086,
+ 0.1407579077330765,
+ 0.8570455272102135,
+ 0.5991507866565635,
+ 0.07544671160677918,
+ 0.7653429124104552,
+ 0.6773009306766822,
+ 0.45537431330712064,
+ 0.8142623987213244,
+ 0.12005385753629261,
+ 0.6280673349705737,
+ 0.6411165107241685,
+ 0.6484334035034007,
+ 0.7662279929095923,
+ 0.37726416856525136,
+ 0.17609887569284655,
+ 0.38801140570442905,
+ 0.39754218864115765,
+ 0.9257069667188491,
+ 0.22229435308889123,
+ 0.8100035792813067,
+ 0.6308637969856226,
+ 0.3958087729357176,
+ 0.5115743574773932,
+ 0.4243398691996936,
+ 0.07883717817748748,
+ 0.15170830509978162,
+ 0.2816360723559719,
+ 0.9711659817994986,
+ 0.044461230265380625,
+ 0.821238189366148,
+ 0.5395859183099476,
+ 0.2722803990279281,
+ 0.4237742209137838,
+ 0.8492378365236639,
+ 0.07052566067182942,
+ 0.7384299618235564,
+ 0.44307968171108536,
+ 0.626851435775337,
+ 0.8141433753393437,
+ 0.7716442985320457,
+ 0.052922587778580166,
+ 0.9838041253840564,
+ 0.07522072756748854,
+ 0.09932648402162414,
+ 0.8632757907071749,
+ 0.2438048746885606,
+ 0.6994226198340694,
+ 0.17754833982132778,
+ 0.27249382866046634,
+ 0.953726012453473,
+ 0.6496793216100725,
+ 0.6595413735302542,
+ 0.6020029422536388,
+ 0.7164563260483665,
+ 0.5076768549802999,
+ 0.049402208839229855,
+ 0.8704399548068575,
+ 0.8183909638112867,
+ 0.6246196275834262,
+ 0.34055277199342293,
+ 0.6375528626944473,
+ 0.2176538874850178,
+ 0.8855950471919678,
+ 0.2729897053353294,
+ 0.922898222002597,
+ 0.34124823862742093,
+ 0.7724731409980496,
+ 0.9301356652479389,
+ 0.5069872906570465,
+ 0.8907391661563082,
+ 0.32950557196005503,
+ 0.985746097010779,
+ 0.9887326595275832,
+ 0.8708031335294233,
+ 0.4581414968403985,
+ 0.6417776426968713,
+ 0.1988895008216951,
+ 0.14201433649723483,
+ 0.2519165771331364,
+ 0.4893264293228885,
+ 0.5938184986886181,
+ 0.9915985915641636,
+ 0.07932976885305809,
+ 0.3177939359004449,
+ 0.021452758251003567,
+ 0.13933128825095897,
+ 0.5726480825059779,
+ 0.5189949016845317,
+ 0.6891035069799827,
+ 0.49304429113395964,
+ 0.6619469056212011,
+ 0.15392767997249202,
+ 0.295502756789187,
+ 0.9836316237991622,
+ 0.9852703411276889,
+ 0.5335280196070722,
+ 0.014950690276562373,
+ 0.27343049990512514,
+ 0.6808495149772484,
+ 0.9449623361180979,
+ 0.5815473574186956,
+ 0.6876907395597738,
+ 0.6074256288551354,
+ 0.6616727427389402,
+ 0.36095501815680064,
+ 0.41762697729996634,
+ 0.3068641146519695,
+ 0.333544545080694,
+ 0.2515657935855262,
+ 0.705714848144513,
+ 0.5255521635430529,
+ 0.4822159228974139,
+ 0.6217747511283676,
+ 0.08087460026706172,
+ 0.038418823857711226,
+ 0.191238850363338,
+ 0.772025062029148,
+ 0.5836617926964085,
+ 0.6257770436229244,
+ 0.3360858834698621,
+ 0.07102860301201153,
+ 0.35231606761455847,
+ 0.4395219250109519,
+ 0.29145547851709463,
+ 0.3828891018746814,
+ 0.1586315392361195,
+ 0.681625950179632,
+ 0.6390249571272832,
+ 0.18127915456338606,
+ 0.3074673692068177,
+ 0.11409699865595568,
+ 0.2084284233791489,
+ 0.97923423111305,
+ 0.39726880385758756,
+ 0.1507803451137819,
+ 0.7071508081014066,
+ 0.6789899906980974,
+ 0.7504243731249811,
+ 0.3250115192256111,
+ 0.08257633416391008,
+ 0.5806999030604296,
+ 0.7620316920198831,
+ 0.4035009404475842,
+ 0.3068822262867634,
+ 0.3445143919468354,
+ 0.5711454787289016,
+ 0.1449634076508688,
+ 0.8695309515694036,
+ 0.8570541881803591,
+ 0.898864374325179,
+ 0.8192475103851975,
+ 0.47431367407308067,
+ 0.8428434350964595,
+ 0.8701949713056438,
+ 0.5048752773887357,
+ 0.35052839245352385,
+ 0.11810761952684778,
+ 0.08778526548004928,
+ 0.6372428709171547,
+ 0.9888725923474206,
+ 0.2864261958904437,
+ 0.07213482061244814,
+ 0.15845866642053563,
+ 0.5062299144844185,
+ 0.5746856612680256,
+ 0.8659909684424811,
+ 0.8414353824886924,
+ 0.7672879096854097,
+ 0.06459741136385855,
+ 0.3604498875597726,
+ 0.6006588577364183,
+ 0.056856595390261555,
+ 0.7016467737931367,
+ 0.2123993086079614,
+ 0.7132617466759801,
+ 0.007242742044783146,
+ 0.13564612958400502,
+ 0.33005333741350995,
+ 0.736021023245836,
+ 0.9406546989427267,
+ 0.2925280225016629,
+ 0.2655802942570038,
+ 0.016877181546108178,
+ 0.15929715792991916,
+ 0.6391938328375499,
+ 0.6329167268211631,
+ 0.4985094645037693,
+ 0.7167806799705279,
+ 0.8531428725877723,
+ 0.6405531773686648,
+ 0.377705624398585,
+ 0.13785533323928845,
+ 0.33942934167686034,
+ 0.4536063371227177,
+ 0.34963259129971425
+ ],
+ "mode": "markers",
+ "marker": {
+ "size": 5,
+ "color": [
+ 0.4616274593988976,
+ 0.6159658554953507,
+ 0.14733135643810646,
+ 0.5667641205161871,
+ 0.7354441683995987,
+ 0.09338282979231982,
+ 0.9903377749890259,
+ 0.5374308078056822,
+ 0.9277476505822664,
+ 0.08323004128218803,
+ 0.9262424431459373,
+ 0.07721861833625465,
+ 0.316806534455903,
+ 0.6905645938270328,
+ 0.37499535022676067,
+ 0.5237723768049043,
+ 0.07464909758755889,
+ 0.7077805788454765,
+ 0.45225009860017584,
+ 0.6674148981584085,
+ 0.5628508733412807,
+ 0.8018137470292497,
+ 0.343843747049178,
+ 0.9852293530378662,
+ 0.1066338394930828,
+ 0.24260373567303994,
+ 0.2581380475938495,
+ 0.057177653812069185,
+ 0.35629696373744535,
+ 0.7436452620337728,
+ 0.6692344231471397,
+ 0.5949462020755851,
+ 0.6576636129468314,
+ 0.019977683605029606,
+ 0.7754966777776147,
+ 0.3409475469762202,
+ 0.10505752857151562,
+ 0.5382664472162011,
+ 0.23422301844320104,
+ 0.23120408514083857,
+ 0.17626801625836364,
+ 0.9591028652096454,
+ 0.08931992353086238,
+ 0.3932366071090292,
+ 0.39540802372591943,
+ 0.4470022120346193,
+ 0.4082122355215174,
+ 0.28267768821700145,
+ 0.8055901137799373,
+ 0.45208617372232274,
+ 0.39706239364332907,
+ 0.631886787018654,
+ 0.14090506326963959,
+ 0.6371557878101777,
+ 0.8693697292009528,
+ 0.9103872263778481,
+ 0.07206796438983165,
+ 0.7696288091366807,
+ 0.6904741191669677,
+ 0.44478304308488803,
+ 0.29879600726642175,
+ 0.06813133964789775,
+ 0.46375344844705224,
+ 0.6361148045916376,
+ 0.3714141768131616,
+ 0.4689894633900966,
+ 0.05376791543207715,
+ 0.9582074400644287,
+ 0.14149996361590467,
+ 0.9626720891064184,
+ 0.1598460224513516,
+ 0.3109994711314612,
+ 0.4510794057508736,
+ 0.9752152356511024,
+ 0.962017602946641,
+ 0.04206549382806779,
+ 0.4271502037227095,
+ 0.7338711489031002,
+ 0.19179244410313867,
+ 0.12479799491908894,
+ 0.40058917261911997,
+ 0.10793111399724986,
+ 0.9506121571546589,
+ 0.9980834693872784,
+ 0.2616729510381006,
+ 0.19918907515056117,
+ 0.26124827064167366,
+ 0.04700351146651194,
+ 0.643077267949713,
+ 0.16204159494738213,
+ 0.9389644666328048,
+ 0.8190032324635506,
+ 0.5914276573736743,
+ 0.08259525135228696,
+ 0.48296177521703476,
+ 0.558865410234807,
+ 0.5216047222486184,
+ 0.8388268216175738,
+ 0.26564121945521646,
+ 0.2642720521826212,
+ 0.7058731057826744,
+ 0.9821568189706535,
+ 0.39951561657266943,
+ 0.9905094625707764,
+ 0.8450910732070214,
+ 0.9492521533827545,
+ 0.26888799320812673,
+ 0.911118018018567,
+ 0.10742216581354813,
+ 0.17801260994893053,
+ 0.6280583783264748,
+ 0.5385121890208695,
+ 0.9079632784981913,
+ 0.12680855373314448,
+ 0.12770805911064564,
+ 0.25995662925105845,
+ 0.4296569502097418,
+ 0.837785176224509,
+ 0.643330550187764,
+ 0.6808400004172752,
+ 0.458710827955672,
+ 0.16009454133122136,
+ 0.8202231073239015,
+ 0.9053967045598783,
+ 0.5365994711573248,
+ 0.9960075151497787,
+ 0.02510969842621913,
+ 0.35105842745514293,
+ 0.8849890732014707,
+ 0.7573538142230878,
+ 0.17956914547596736,
+ 0.08647183700547911,
+ 0.779984937808065,
+ 0.6690858604662955,
+ 0.1825514085080555,
+ 0.7359140104581448,
+ 0.4832450064132081,
+ 0.004680006424105487,
+ 0.054129657907077355,
+ 0.9182711683702454,
+ 0.17426199250373742,
+ 0.7853499017423882,
+ 0.2392366970036739,
+ 0.7045245458632703,
+ 0.7397575678970407,
+ 0.5808965620927102,
+ 0.1573642283554464,
+ 0.7838078499029744,
+ 0.022809643682487835,
+ 0.25947607091712444,
+ 0.07927158226754316,
+ 0.7572333743691615,
+ 0.3480185053274718,
+ 0.5025769378049088,
+ 0.6349254301237339,
+ 0.44220130982305283,
+ 0.2941873838636848,
+ 0.8658457980943166,
+ 0.33718988202636924,
+ 0.36399771149412774,
+ 0.2557140683022996,
+ 0.4260817100484571,
+ 0.12621985914398337,
+ 0.620518125979105,
+ 0.71987614384816,
+ 0.8003673309522548,
+ 0.9996415897476298,
+ 0.06719734135151567,
+ 0.9322866387654336,
+ 0.9283012232007972,
+ 0.08059383278114773,
+ 0.3063677423829876,
+ 0.08986664990867044,
+ 0.0975448245056838,
+ 0.7379632992176663,
+ 0.03416009401780329,
+ 0.8624901126846831,
+ 0.09334710918984412,
+ 0.6351625533840559,
+ 0.9342129690958965,
+ 0.08816460719920438,
+ 0.6500019434623974,
+ 0.13755828831488137,
+ 0.7445637838163035,
+ 0.6771472592740897,
+ 0.8693468361877688,
+ 0.28271259888642786,
+ 0.9471270953710687,
+ 0.6432180599730659,
+ 0.8881795753841952,
+ 0.7497327903558746,
+ 0.20031859209199676,
+ 0.4889183672926736,
+ 0.44223497603677986,
+ 0.07762978987423819,
+ 0.9698795565530265,
+ 0.8720673433469355,
+ 0.5848448655198397,
+ 0.6093877444520419,
+ 0.2600479448594426,
+ 0.8961071076491984,
+ 0.7827239150324312,
+ 0.03243647484491774,
+ 0.4347393417626588,
+ 0.48205770886363086,
+ 0.1407579077330765,
+ 0.8570455272102135,
+ 0.5991507866565635,
+ 0.07544671160677918,
+ 0.7653429124104552,
+ 0.6773009306766822,
+ 0.45537431330712064,
+ 0.8142623987213244,
+ 0.12005385753629261,
+ 0.6280673349705737,
+ 0.6411165107241685,
+ 0.6484334035034007,
+ 0.7662279929095923,
+ 0.37726416856525136,
+ 0.17609887569284655,
+ 0.38801140570442905,
+ 0.39754218864115765,
+ 0.9257069667188491,
+ 0.22229435308889123,
+ 0.8100035792813067,
+ 0.6308637969856226,
+ 0.3958087729357176,
+ 0.5115743574773932,
+ 0.4243398691996936,
+ 0.07883717817748748,
+ 0.15170830509978162,
+ 0.2816360723559719,
+ 0.9711659817994986,
+ 0.044461230265380625,
+ 0.821238189366148,
+ 0.5395859183099476,
+ 0.2722803990279281,
+ 0.4237742209137838,
+ 0.8492378365236639,
+ 0.07052566067182942,
+ 0.7384299618235564,
+ 0.44307968171108536,
+ 0.626851435775337,
+ 0.8141433753393437,
+ 0.7716442985320457,
+ 0.052922587778580166,
+ 0.9838041253840564,
+ 0.07522072756748854,
+ 0.09932648402162414,
+ 0.8632757907071749,
+ 0.2438048746885606,
+ 0.6994226198340694,
+ 0.17754833982132778,
+ 0.27249382866046634,
+ 0.953726012453473,
+ 0.6496793216100725,
+ 0.6595413735302542,
+ 0.6020029422536388,
+ 0.7164563260483665,
+ 0.5076768549802999,
+ 0.049402208839229855,
+ 0.8704399548068575,
+ 0.8183909638112867,
+ 0.6246196275834262,
+ 0.34055277199342293,
+ 0.6375528626944473,
+ 0.2176538874850178,
+ 0.8855950471919678,
+ 0.2729897053353294,
+ 0.922898222002597,
+ 0.34124823862742093,
+ 0.7724731409980496,
+ 0.9301356652479389,
+ 0.5069872906570465,
+ 0.8907391661563082,
+ 0.32950557196005503,
+ 0.985746097010779,
+ 0.9887326595275832,
+ 0.8708031335294233,
+ 0.4581414968403985,
+ 0.6417776426968713,
+ 0.1988895008216951,
+ 0.14201433649723483,
+ 0.2519165771331364,
+ 0.4893264293228885,
+ 0.5938184986886181,
+ 0.9915985915641636,
+ 0.07932976885305809,
+ 0.3177939359004449,
+ 0.021452758251003567,
+ 0.13933128825095897,
+ 0.5726480825059779,
+ 0.5189949016845317,
+ 0.6891035069799827,
+ 0.49304429113395964,
+ 0.6619469056212011,
+ 0.15392767997249202,
+ 0.295502756789187,
+ 0.9836316237991622,
+ 0.9852703411276889,
+ 0.5335280196070722,
+ 0.014950690276562373,
+ 0.27343049990512514,
+ 0.6808495149772484,
+ 0.9449623361180979,
+ 0.5815473574186956,
+ 0.6876907395597738,
+ 0.6074256288551354,
+ 0.6616727427389402,
+ 0.36095501815680064,
+ 0.41762697729996634,
+ 0.3068641146519695,
+ 0.333544545080694,
+ 0.2515657935855262,
+ 0.705714848144513,
+ 0.5255521635430529,
+ 0.4822159228974139,
+ 0.6217747511283676,
+ 0.08087460026706172,
+ 0.038418823857711226,
+ 0.191238850363338,
+ 0.772025062029148,
+ 0.5836617926964085,
+ 0.6257770436229244,
+ 0.3360858834698621,
+ 0.07102860301201153,
+ 0.35231606761455847,
+ 0.4395219250109519,
+ 0.29145547851709463,
+ 0.3828891018746814,
+ 0.1586315392361195,
+ 0.681625950179632,
+ 0.6390249571272832,
+ 0.18127915456338606,
+ 0.3074673692068177,
+ 0.11409699865595568,
+ 0.2084284233791489,
+ 0.97923423111305,
+ 0.39726880385758756,
+ 0.1507803451137819,
+ 0.7071508081014066,
+ 0.6789899906980974,
+ 0.7504243731249811,
+ 0.3250115192256111,
+ 0.08257633416391008,
+ 0.5806999030604296,
+ 0.7620316920198831,
+ 0.4035009404475842,
+ 0.3068822262867634,
+ 0.3445143919468354,
+ 0.5711454787289016,
+ 0.1449634076508688,
+ 0.8695309515694036,
+ 0.8570541881803591,
+ 0.898864374325179,
+ 0.8192475103851975,
+ 0.47431367407308067,
+ 0.8428434350964595,
+ 0.8701949713056438,
+ 0.5048752773887357,
+ 0.35052839245352385,
+ 0.11810761952684778,
+ 0.08778526548004928,
+ 0.6372428709171547,
+ 0.9888725923474206,
+ 0.2864261958904437,
+ 0.07213482061244814,
+ 0.15845866642053563,
+ 0.5062299144844185,
+ 0.5746856612680256,
+ 0.8659909684424811,
+ 0.8414353824886924,
+ 0.7672879096854097,
+ 0.06459741136385855,
+ 0.3604498875597726,
+ 0.6006588577364183,
+ 0.056856595390261555,
+ 0.7016467737931367,
+ 0.2123993086079614,
+ 0.7132617466759801,
+ 0.007242742044783146,
+ 0.13564612958400502,
+ 0.33005333741350995,
+ 0.736021023245836,
+ 0.9406546989427267,
+ 0.2925280225016629,
+ 0.2655802942570038,
+ 0.016877181546108178,
+ 0.15929715792991916,
+ 0.6391938328375499,
+ 0.6329167268211631,
+ 0.4985094645037693,
+ 0.7167806799705279,
+ 0.8531428725877723,
+ 0.6405531773686648,
+ 0.377705624398585,
+ 0.13785533323928845,
+ 0.33942934167686034,
+ 0.4536063371227177,
+ 0.34963259129971425
+ ],
+ "mode": "markers",
+ "colorscale": [
+ [
+ 0,
+ "rgb(255, 0, 0)"
+ ],
+ [
+ 0.5,
+ "rgb(0, 255, 0)"
+ ],
+ [
+ 1,
+ "rgb(0, 0, 255)"
+ ]
+ ]
+ },
+ "type": "scattergl"
+ }
+ ],
+ "layout": {
+ "height": 400,
+ "width": 680,
+ "showlegend": false
+ }
+}
diff --git a/test/image/mocks/gl2d_scatter-subplot-panel.json b/test/image/mocks/gl2d_scatter-subplot-panel.json
new file mode 100644
index 00000000000..d393e940c16
--- /dev/null
+++ b/test/image/mocks/gl2d_scatter-subplot-panel.json
@@ -0,0 +1,7442 @@
+{
+ "data": [
+ {
+ "uid": "ab6939",
+ "yaxis": "y",
+ "ysrc": "jackp:17616:013c39",
+ "xsrc": "jackp:17616:7ad609",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "y": [
+ 1061,
+ 11380,
+ 1069,
+ 5421,
+ 3047,
+ 6670,
+ 4634,
+ 5839,
+ 8969,
+ 4022,
+ 10763,
+ 630,
+ 7780,
+ 4189,
+ 605,
+ 574,
+ 8549,
+ 1113,
+ 1056,
+ 8854,
+ 10091,
+ 5086,
+ 828,
+ 1072,
+ 4022,
+ 2515,
+ 3696,
+ 7357,
+ 698,
+ 1813,
+ 574,
+ 2100,
+ 2042,
+ 2746,
+ 868,
+ 10221,
+ 1013,
+ 666,
+ 2932,
+ 10980,
+ 2863,
+ 5329,
+ 3896,
+ 4750,
+ 11189,
+ 16336,
+ 5864,
+ 1009,
+ 5436,
+ 540,
+ 1362,
+ 12738,
+ 15217,
+ 6471,
+ 666,
+ 982,
+ 907,
+ 1059.3106836371142,
+ 11378.76484672601,
+ 1067.0389029875535,
+ 5415.541473829024,
+ 3043.126678834689,
+ 6682.202531020598,
+ 4632.764177524695,
+ 5837.135082018547,
+ 8967.108954475267,
+ 4014.6060439357625,
+ 10777.562183384925,
+ 630.0843436021011,
+ 7792.429719427687,
+ 4188.778161876925,
+ 604.6273993049891,
+ 573.6459148827832,
+ 8548.560509085333,
+ 1111.2457705740364,
+ 1056.5659908824675,
+ 8860.783498917568,
+ 10086.173456646731,
+ 5079.967861774502,
+ 826.7868758425707,
+ 1071.2667462601792,
+ 4018.764264449159,
+ 2515.9697949094284,
+ 3690.9329781712863,
+ 7356.598687202641,
+ 697.2408759881968,
+ 1815.3169858769968,
+ 574.2153777691822,
+ 2099.6659196786677,
+ 2044.8665356939257,
+ 2744.0759894866906,
+ 867.7389585808415,
+ 10240.579077960845,
+ 1012.9971626792702,
+ 667.0748525023557,
+ 2928.065494655128,
+ 10985.054394743776,
+ 2864.971318928985,
+ 5335.032998937184,
+ 3892.1668470582094,
+ 4745.210590946567,
+ 11168.340669411537,
+ 16306.636464701785,
+ 5854.627923096243,
+ 1008.9460493429467,
+ 5428.903570182665,
+ 539.5172639869355,
+ 1361.353562174305,
+ 12757.430112057562,
+ 15196.167209163692,
+ 6483.516325416377,
+ 667.2087721042134,
+ 981.4175993943619,
+ 907.9886333478165
+ ],
+ "x": [
+ 0.41,
+ 1.58,
+ 0.38,
+ 1.3,
+ 0.91,
+ 1.01,
+ 1.33,
+ 1.01,
+ 1.54,
+ 0.9,
+ 1.3,
+ 0.3,
+ 1.34,
+ 1,
+ 0.3,
+ 0.3,
+ 1.27,
+ 0.43,
+ 0.51,
+ 1.3,
+ 1.7,
+ 1.04,
+ 0.44,
+ 0.49,
+ 1.01,
+ 0.81,
+ 1.1,
+ 1.4,
+ 0.31,
+ 0.53,
+ 0.3,
+ 0.7,
+ 0.7,
+ 0.73,
+ 0.33,
+ 1.52,
+ 0.3,
+ 0.33,
+ 0.7,
+ 1.55,
+ 0.83,
+ 1.12,
+ 1.24,
+ 0.93,
+ 1.6,
+ 2.11,
+ 1.01,
+ 0.39,
+ 1.22,
+ 0.32,
+ 0.39,
+ 1.52,
+ 2.04,
+ 1.07,
+ 0.33,
+ 0.4,
+ 0.31,
+ 0.4107633943409979,
+ 1.5795268263899218,
+ 0.38072422743350887,
+ 1.2992023481094161,
+ 0.9084414288633553,
+ 1.0116025472072634,
+ 1.327444354301417,
+ 1.0110722184438945,
+ 1.540813364292889,
+ 0.9000600744887673,
+ 1.3007100475964846,
+ 0.3004194857789524,
+ 1.3376976092341328,
+ 1.0003384339498795,
+ 0.30019572959320673,
+ 0.30014256392276406,
+ 1.2684557442171318,
+ 0.430377870776487,
+ 0.5099499992096155,
+ 1.2991165485479506,
+ 1.6976184575853792,
+ 1.0411884059899226,
+ 0.44039755055311974,
+ 0.48982554697630276,
+ 1.0091428289328386,
+ 0.8095036979536122,
+ 1.0985213214003793,
+ 1.3982163328397756,
+ 0.30981488160175413,
+ 0.5299901266493092,
+ 0.30024091987167484,
+ 0.6995160214373853,
+ 0.7011595222944403,
+ 0.7313843607749203,
+ 0.330022579446216,
+ 1.5204666142287895,
+ 0.30030336921065653,
+ 0.3303750661860965,
+ 0.6993857808733479,
+ 1.5519782017466428,
+ 0.8289423384590348,
+ 1.1211663120229776,
+ 1.2423879793881645,
+ 0.9314068935133135,
+ 1.6002285766446496,
+ 2.109944716249183,
+ 1.0091686636845043,
+ 0.38987499009998666,
+ 1.2193341334210623,
+ 0.31963991664707536,
+ 0.3899022780991603,
+ 1.5193376972037451,
+ 2.0420751554671646,
+ 1.0703653709951608,
+ 0.3306395991025956,
+ 0.4004810714207143,
+ 0.3096309154770747
+ ],
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "f1cdee",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "410e1a",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "5d824e",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "94535a",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "5bcb71",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "f17ffc",
+ "yaxis": "y",
+ "ysrc": "jackp:17616:ee32d5",
+ "xsrc": "jackp:17616:0d67c1",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "y": [
+ 5452,
+ 540,
+ 7247,
+ 6648,
+ 2005,
+ 802,
+ 868,
+ 3561,
+ 906,
+ 2423,
+ 4556,
+ 2247,
+ 12255,
+ 666,
+ 559,
+ 1580,
+ 2004,
+ 891,
+ 2757,
+ 627,
+ 3089,
+ 863,
+ 8051,
+ 2375,
+ 1946,
+ 814,
+ 3536,
+ 814,
+ 4079,
+ 13135,
+ 1084,
+ 863,
+ 775,
+ 1080,
+ 1093,
+ 847,
+ 2413,
+ 8080,
+ 2133,
+ 1202,
+ 886,
+ 1306,
+ 764,
+ 1257,
+ 8728,
+ 9282,
+ 7109,
+ 1103,
+ 1229,
+ 929,
+ 9252,
+ 6465,
+ 827,
+ 6486,
+ 4044,
+ 946,
+ 974,
+ 2111,
+ 827,
+ 1056,
+ 2335,
+ 5361,
+ 12618,
+ 1348,
+ 907,
+ 14650,
+ 891,
+ 6561,
+ 794,
+ 1728,
+ 1046,
+ 6683,
+ 905,
+ 8645,
+ 6377,
+ 2533,
+ 932,
+ 9243,
+ 477,
+ 1246,
+ 7577,
+ 10378,
+ 2377,
+ 2870,
+ 1865,
+ 943,
+ 1055,
+ 5887,
+ 847,
+ 612,
+ 695,
+ 461,
+ 984,
+ 8794,
+ 8645,
+ 2271,
+ 5460.514232315189,
+ 540.6060672978252,
+ 7256.265245472035,
+ 6655.447023455413,
+ 2004.8900411818047,
+ 803.2272457475142,
+ 866.4272920672585,
+ 3555.5608027391595,
+ 905.4057653960003,
+ 2423.450247400853,
+ 4563.647658194975,
+ 2244.810176778345,
+ 12268.819633511086,
+ 665.796490791041,
+ 557.9561700986359,
+ 1580.6926540117697,
+ 2007.135148784566,
+ 890.7376213256438,
+ 2757.5133412847895,
+ 626.3684140664654,
+ 3083.2238126689845,
+ 863.9658590224391,
+ 8054.2098231461005,
+ 2371.1842450381405,
+ 1949.0958783891047,
+ 815.4099749125593,
+ 3540.7394673309614,
+ 813.503123276087,
+ 4084.1156609733484,
+ 13152.793371056214,
+ 1084.8871585739962,
+ 862.2414317058289,
+ 776.3361805510342,
+ 1078.7139986310528,
+ 1091.2887501009477,
+ 847.1809576005015,
+ 2410.9855877293326,
+ 8070.931268387648,
+ 2136.697679751855,
+ 1200.4323711991233,
+ 885.1469963465314,
+ 1304.235826806892,
+ 764.8838481570778,
+ 1255.1088546122362,
+ 8719.96020657201,
+ 9269.057767245818,
+ 7108.632766719113,
+ 1102.7567754703193,
+ 1228.4247635459587,
+ 930.3616174346655,
+ 9265.544727737326,
+ 6459.126179694332,
+ 828.4893456008689,
+ 6497.782392641875,
+ 4040.585178190286,
+ 945.7475993454485,
+ 975.5270027693304,
+ 2109.6997596171605,
+ 826.8406535505052,
+ 1057.6085391199654,
+ 2336.1553990916623,
+ 5364.313849599517,
+ 12640.212307930415,
+ 1349.633695774002,
+ 907.0386161863622,
+ 14641.42218921677,
+ 890.6239810758949,
+ 6559.3876484607,
+ 793.913053197136,
+ 1724.929285255018,
+ 1047.3114335263103,
+ 6688.270730968713,
+ 906.4834024809417,
+ 8630.737503918022,
+ 6372.725694410858,
+ 2536.0704430653595,
+ 931.6775250317295,
+ 9256.264390030623,
+ 476.53076580013993,
+ 1246.5680762017519,
+ 7563.233523707304,
+ 10370.733079595597,
+ 2380.0429180122455,
+ 2871.7319728426646,
+ 1861.5993102560928,
+ 944.7107687296119,
+ 1054.0692056848984,
+ 5895.928090272499,
+ 846.273698854019,
+ 612.3725464049963,
+ 695.2253743927627,
+ 460.18430884786017,
+ 984.9395068334029,
+ 8785.927975320888,
+ 8641.791884255083,
+ 2272.411602788348
+ ],
+ "x": [
+ 1.18,
+ 0.34,
+ 1.05,
+ 1.02,
+ 0.51,
+ 0.31,
+ 0.33,
+ 0.79,
+ 0.35,
+ 0.74,
+ 1.01,
+ 0.53,
+ 1.33,
+ 0.33,
+ 0.32,
+ 0.56,
+ 0.56,
+ 0.31,
+ 0.7,
+ 0.31,
+ 0.73,
+ 0.3,
+ 1.13,
+ 0.7,
+ 0.53,
+ 0.32,
+ 0.65,
+ 0.32,
+ 1.01,
+ 1.5,
+ 0.34,
+ 0.3,
+ 0.34,
+ 0.32,
+ 0.43,
+ 0.42,
+ 0.6,
+ 1.12,
+ 0.58,
+ 0.44,
+ 0.39,
+ 0.46,
+ 0.3,
+ 0.4,
+ 1.32,
+ 1.25,
+ 1.11,
+ 0.42,
+ 0.4,
+ 0.38,
+ 1.18,
+ 1,
+ 0.41,
+ 1.05,
+ 0.9,
+ 0.33,
+ 0.34,
+ 0.51,
+ 0.41,
+ 0.37,
+ 0.7,
+ 1.05,
+ 2.03,
+ 0.44,
+ 0.31,
+ 1.54,
+ 0.31,
+ 1.08,
+ 0.3,
+ 0.57,
+ 0.31,
+ 1.02,
+ 0.32,
+ 1.05,
+ 1,
+ 0.6,
+ 0.36,
+ 1.26,
+ 0.3,
+ 0.49,
+ 1.07,
+ 1.35,
+ 0.73,
+ 0.8,
+ 0.5,
+ 0.43,
+ 0.45,
+ 1,
+ 0.42,
+ 0.32,
+ 0.38,
+ 0.32,
+ 0.42,
+ 1.51,
+ 1.05,
+ 0.54,
+ 1.1780061569018656,
+ 0.34019906154924956,
+ 1.050291041064077,
+ 1.0193819889523505,
+ 0.5101857008071604,
+ 0.31012570662799926,
+ 0.32987999810065116,
+ 0.7911857405047632,
+ 0.3500676902101524,
+ 0.7388492676822586,
+ 1.0103594952359454,
+ 0.5305726865778144,
+ 1.3312427504773812,
+ 0.33033548350188935,
+ 0.3203175476767066,
+ 0.5609542186362863,
+ 0.5607119079376008,
+ 0.31015589985333475,
+ 0.7003245680589847,
+ 0.3105000118607063,
+ 0.7304900287597976,
+ 0.2998436406739367,
+ 1.129498593039082,
+ 0.6992181245292223,
+ 0.5293288698849064,
+ 0.319785290476097,
+ 0.6502396936869513,
+ 0.31945751824934054,
+ 1.0117271992438635,
+ 1.497072122568163,
+ 0.33972947650862756,
+ 0.2996293015653554,
+ 0.3402660465980502,
+ 0.3201663543225943,
+ 0.4291895920104291,
+ 0.4207500888240124,
+ 0.6009587468415049,
+ 1.1196065206843027,
+ 0.5809384687111587,
+ 0.44082332185656087,
+ 0.39026449881842856,
+ 0.45927289774590446,
+ 0.29989745264205814,
+ 0.39984787583859394,
+ 1.3206843722164034,
+ 1.2485929314172612,
+ 1.1098084539747521,
+ 0.42047914988763374,
+ 0.40003540311036123,
+ 0.38027346964416486,
+ 1.1814761344883558,
+ 1.001445009705241,
+ 0.4104341206319438,
+ 1.0507704520537682,
+ 0.9017249902223466,
+ 0.32998521469187597,
+ 0.3405790459844217,
+ 0.509786008415465,
+ 0.4106008776075467,
+ 0.3693497036413711,
+ 0.6989925506915445,
+ 1.0509160153892532,
+ 2.0289020309016212,
+ 0.4404142654581719,
+ 0.30971940075847304,
+ 1.539178732364313,
+ 0.30949763811252123,
+ 1.0783931896228875,
+ 0.3000341665766932,
+ 0.5698800217799176,
+ 0.3101780498103983,
+ 1.018537004143419,
+ 0.32031866648767165,
+ 1.0483455946391567,
+ 1.0007852494609037,
+ 0.5998626613470537,
+ 0.36067691071352004,
+ 1.2609639454986543,
+ 0.2999488130229284,
+ 0.49060079518448313,
+ 1.0679930392121713,
+ 1.350417480496671,
+ 0.7314060651672839,
+ 0.8000523901671874,
+ 0.5009670357606365,
+ 0.43069107615453184,
+ 0.44965982069442784,
+ 1.0000238226208142,
+ 0.4201890266004826,
+ 0.31980324678858824,
+ 0.3793050183965843,
+ 0.3201689969160442,
+ 0.41960338584979623,
+ 1.5112505003644572,
+ 1.049817781569988,
+ 0.5404896698863518
+ ],
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "14788a",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "5931cd",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "990c34",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "3e3b4d",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "14d30a",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "dace31",
+ "yaxis": "y",
+ "ysrc": "jackp:17616:3908ce",
+ "xsrc": "jackp:17616:45a03c",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "y": [
+ 1193,
+ 2277,
+ 2117,
+ 544,
+ 585,
+ 678,
+ 2274,
+ 852,
+ 541,
+ 1220,
+ 561,
+ 4712,
+ 1046,
+ 819,
+ 13337,
+ 2287,
+ 3039,
+ 625,
+ 544,
+ 431,
+ 11161,
+ 673,
+ 1838,
+ 3006,
+ 2336,
+ 2171,
+ 713,
+ 447,
+ 432,
+ 15829,
+ 3288,
+ 4714,
+ 4291,
+ 8712,
+ 4997,
+ 13596,
+ 559,
+ 1912,
+ 6998,
+ 1193.3876365931562,
+ 2272.5994017331814,
+ 2120.476250371547,
+ 544.7276944898541,
+ 585.8049310349996,
+ 679.0830540732029,
+ 2273.6876113911367,
+ 851.6658067740736,
+ 541.6088153194902,
+ 1222.364904630746,
+ 559.9926307366161,
+ 4707.50157828803,
+ 1045.3028541499064,
+ 820.4382781997845,
+ 13316.544001971582,
+ 2288.1894040806665,
+ 3038.2466612846124,
+ 625.3990473635954,
+ 544.6146688412308,
+ 430.41668161251334,
+ 11153.947817576975,
+ 672.8319791387142,
+ 1838.4136253693468,
+ 3001.1264162321445,
+ 2331.654802069871,
+ 2171.0517348908475,
+ 714.2128028747433,
+ 446.60845078345693,
+ 431.80108988686476,
+ 15828.453901656627,
+ 3284.1654911792984,
+ 4707.745817982617,
+ 4298.488296208745,
+ 8716.909810010398,
+ 4988.341606206554,
+ 13620.479855798849,
+ 559.8988175709475,
+ 1912.1301945982304,
+ 7004.688500517063
+ ],
+ "x": [
+ 0.45,
+ 0.74,
+ 0.7,
+ 0.31,
+ 0.3,
+ 0.36,
+ 0.71,
+ 0.43,
+ 0.29,
+ 0.51,
+ 0.32,
+ 1.2,
+ 0.31,
+ 0.34,
+ 1.51,
+ 0.7,
+ 0.7,
+ 0.31,
+ 0.31,
+ 0.23,
+ 1.51,
+ 0.4,
+ 0.5,
+ 0.91,
+ 0.56,
+ 0.71,
+ 0.34,
+ 0.3,
+ 0.24,
+ 1.71,
+ 0.73,
+ 1.31,
+ 1.02,
+ 1.2,
+ 1,
+ 1.5,
+ 0.31,
+ 0.6,
+ 1.07,
+ 0.4500545841868139,
+ 0.7388814618948583,
+ 0.6997529055296279,
+ 0.31012748850149074,
+ 0.3001000613528415,
+ 0.36046681208094744,
+ 0.7100010642622773,
+ 0.42930725342676873,
+ 0.28974031075134327,
+ 0.5092263179124418,
+ 0.319882621963655,
+ 1.201037838714529,
+ 0.31016700101683087,
+ 0.3396264155710481,
+ 1.5119895141174995,
+ 0.7010995490004005,
+ 0.6998043302379092,
+ 0.3097951744381917,
+ 0.30939857515606023,
+ 0.23014068982257535,
+ 1.5086008018297963,
+ 0.4004868992406772,
+ 0.4994509430074582,
+ 0.9094317685770236,
+ 0.5607455152009062,
+ 0.710446767609082,
+ 0.34023416582692473,
+ 0.3003293518892345,
+ 0.2399528981339443,
+ 1.7127774042695152,
+ 0.7309734014523372,
+ 1.3088749701633184,
+ 1.0194294657153335,
+ 1.2004316689138208,
+ 1.0015334048414977,
+ 1.5026112420740132,
+ 0.31050676069316624,
+ 0.6010486865462888,
+ 1.0699924794723807
+ ],
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "247be7",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "3c91dc",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "ee9596",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "7f1ed8",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "ff5f92",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "c6e1cb",
+ "yaxis": "y",
+ "ysrc": "jackp:17616:1e013b",
+ "xsrc": "jackp:17616:4b5447",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "y": [
+ 7572,
+ 1120,
+ 5701,
+ 4397,
+ 4485,
+ 4861,
+ 4093,
+ 1437,
+ 3941,
+ 4183,
+ 1388,
+ 7569.64952963075,
+ 1118.6105875913026,
+ 5706.382903847428,
+ 4403.2914914143175,
+ 4476.420490760296,
+ 4851.352547488572,
+ 4099.272504570691,
+ 1437.371924384714,
+ 3948.8748294224533,
+ 4183.574123983911,
+ 1389.3022525377155
+ ],
+ "x": [
+ 1,
+ 0.4,
+ 1.01,
+ 1.01,
+ 0.9,
+ 1.07,
+ 0.9,
+ 0.45,
+ 1,
+ 0.91,
+ 0.58,
+ 1.001502815405228,
+ 0.40019268849685025,
+ 1.0120114558083193,
+ 1.0105425242900785,
+ 0.9008198540913427,
+ 1.0701202290505765,
+ 0.8984569856310916,
+ 0.4498874278017571,
+ 0.9985395676165942,
+ 0.9099205870813175,
+ 0.5806506945003799
+ ],
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "d7da66",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "8563d1",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "ce18ff",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "58b45e",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "dd81de",
+ "yaxis": "y",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "c62c21",
+ "yaxis": "y",
+ "ysrc": "jackp:17616:479c89",
+ "xsrc": "jackp:17616:548eee",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "y": [
+ 1257,
+ 840,
+ 3765,
+ 1255.437898920403,
+ 840.0460713785501,
+ 3769.123318256676
+ ],
+ "x": [
+ 0.5,
+ 0.4,
+ 1.03,
+ 0.4996413954309529,
+ 0.400455934918678,
+ 1.02979273634638
+ ],
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "08893d",
+ "yaxis": "y2",
+ "ysrc": "jackp:17616:36d993",
+ "xsrc": "jackp:17616:6d7fe8",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "y": [
+ 10424,
+ 5139,
+ 4082,
+ 3984,
+ 5171,
+ 1015,
+ 1035,
+ 630,
+ 773,
+ 3775,
+ 3137,
+ 2935,
+ 6520,
+ 7006,
+ 3816,
+ 4077,
+ 7459,
+ 743,
+ 6210,
+ 4172,
+ 5364,
+ 610,
+ 1244,
+ 700,
+ 15801,
+ 828,
+ 9697,
+ 3676,
+ 765,
+ 1116,
+ 2295,
+ 11226,
+ 3629,
+ 13872,
+ 4707,
+ 14574,
+ 3141,
+ 3584,
+ 11455,
+ 12409,
+ 10534,
+ 6129,
+ 4662,
+ 1024,
+ 9768,
+ 10412.77646816203,
+ 5143.130823997301,
+ 4074.637750970314,
+ 3991.5784120824123,
+ 5161.954237735938,
+ 1016.5945814472792,
+ 1036.8033542462274,
+ 631.0097053085964,
+ 772.6159500126535,
+ 3771.2175780154507,
+ 3139.0146691143964,
+ 2933.649611180177,
+ 6527.140546752975,
+ 7002.233444396038,
+ 3809.203815012949,
+ 4077.7712321598933,
+ 7455.023850175573,
+ 742.3409562072713,
+ 6206.458991972971,
+ 4177.459829630505,
+ 5363.717726228926,
+ 610.0460915241994,
+ 1245.7579124988156,
+ 700.2289189151198,
+ 15801.74250478056,
+ 828.9851334561575,
+ 9692.88085374692,
+ 3669.365255486337,
+ 764.172932333939,
+ 1116.9579922958892,
+ 2294.320762763826,
+ 11245.350847275393,
+ 3634.6521912581165,
+ 13865.24749877891,
+ 4711.0596574712,
+ 14565.073854175265,
+ 3141.9485527330235,
+ 3581.8365468515467,
+ 11439.976031356477,
+ 12411.596103880902,
+ 10519.979526708892,
+ 6137.7342317256325,
+ 4661.872989119402,
+ 1025.916096448264,
+ 9780.25055015974
+ ],
+ "x": [
+ 2.77,
+ 1,
+ 0.9,
+ 0.95,
+ 1.02,
+ 0.53,
+ 0.4,
+ 0.35,
+ 0.32,
+ 1.07,
+ 0.72,
+ 0.8,
+ 1.32,
+ 1.39,
+ 0.93,
+ 0.92,
+ 1.31,
+ 0.33,
+ 1.28,
+ 0.97,
+ 1.03,
+ 0.33,
+ 0.47,
+ 0.38,
+ 2.19,
+ 0.32,
+ 1.5,
+ 1.01,
+ 0.34,
+ 0.32,
+ 0.75,
+ 2.26,
+ 0.9,
+ 2.21,
+ 1.01,
+ 2.02,
+ 1.02,
+ 1,
+ 1.72,
+ 1.59,
+ 1.71,
+ 1.2,
+ 1.11,
+ 0.35,
+ 1.5,
+ 2.76611807859154,
+ 1.0014172186648804,
+ 0.8998927183051715,
+ 0.9490105536815838,
+ 1.0208011121706744,
+ 0.5304188244032657,
+ 0.39941516096880725,
+ 0.3493668205399811,
+ 0.3200274684550692,
+ 1.0698092759058495,
+ 0.7192085045595243,
+ 0.8003935983866456,
+ 1.318372998395809,
+ 1.389641303212772,
+ 0.9315983619738519,
+ 0.9191181682945864,
+ 1.3121930937244446,
+ 0.33052112407632367,
+ 1.2805560458285843,
+ 0.9685861818759816,
+ 1.0282540017764927,
+ 0.3305799774805996,
+ 0.46951187328977617,
+ 0.37993345791541067,
+ 2.185965518452483,
+ 0.3200681065578067,
+ 1.5007864833560696,
+ 1.0114377893618371,
+ 0.3395561846306629,
+ 0.32062498422140706,
+ 0.7499866270530111,
+ 2.2572056862114906,
+ 0.900737007198055,
+ 2.20888986267167,
+ 1.0115799519996087,
+ 2.0222637880075047,
+ 1.020379189260676,
+ 0.9998971735101524,
+ 1.721735741546772,
+ 1.5910782290335463,
+ 1.7094456116135857,
+ 1.1978488899909912,
+ 1.1122168333727005,
+ 0.3495876676095213,
+ 1.50280867282154
+ ],
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "7fdc8c",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "ad49c4",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "90ea0d",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "aa9a84",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "84c415",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "fa9571",
+ "yaxis": "y2",
+ "ysrc": "jackp:17616:89729a",
+ "xsrc": "jackp:17616:512573",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "y": [
+ 3146,
+ 1400,
+ 1845,
+ 5384,
+ 6541,
+ 1240,
+ 776,
+ 1402,
+ 4314,
+ 754,
+ 473,
+ 573,
+ 4283,
+ 4368,
+ 5358,
+ 2040,
+ 6397,
+ 448,
+ 4249,
+ 684,
+ 554,
+ 1017,
+ 3732,
+ 4537,
+ 645,
+ 648,
+ 1664,
+ 2113,
+ 614,
+ 1668,
+ 3016,
+ 5773,
+ 743,
+ 3254,
+ 3770,
+ 462,
+ 5951,
+ 1187,
+ 1134,
+ 2006,
+ 2869,
+ 2961,
+ 1304,
+ 7821,
+ 7780,
+ 10861,
+ 1163,
+ 906,
+ 1218,
+ 579,
+ 1678,
+ 397,
+ 5143,
+ 562,
+ 5347,
+ 2398,
+ 3140.8086305808993,
+ 1397.906178857768,
+ 1843.4184402625544,
+ 5383.399868586026,
+ 6532.881409581059,
+ 1238.2891983652735,
+ 776.589524966972,
+ 1401.195711323075,
+ 4316.934634828833,
+ 754.8055185146902,
+ 472.87834001573805,
+ 572.8863954580543,
+ 4281.590323220257,
+ 4369.755732774143,
+ 5350.12101873217,
+ 2041.7567060287292,
+ 6386.09064817482,
+ 447.742917604294,
+ 4247.672553339955,
+ 684.2004316873882,
+ 553.762582443086,
+ 1017.7273848351296,
+ 3730.36942787397,
+ 4540.225660975722,
+ 644.9132539875111,
+ 647.5688774383001,
+ 1664.6452623439018,
+ 2110.442555436066,
+ 612.887516781999,
+ 1667.228394902406,
+ 3016.4582785472912,
+ 5767.418536941765,
+ 741.7267589323542,
+ 3258.565869920871,
+ 3770.100716045485,
+ 461.97795662448453,
+ 5943.07409577641,
+ 1188.5844335614718,
+ 1133.4477397574572,
+ 2003.7069087467034,
+ 2867.134628242455,
+ 2957.473678084288,
+ 1304.6641733777456,
+ 7835.480129898021,
+ 7777.493995607494,
+ 10861.554828743283,
+ 1161.5417534653106,
+ 906.6511146970864,
+ 1218.2969007753525,
+ 578.9103028361784,
+ 1680.550138673035,
+ 397.7138234740735,
+ 5136.150152476496,
+ 561.3353015928315,
+ 5352.122818906456,
+ 2401.989676116762
+ ],
+ "x": [
+ 0.71,
+ 0.5,
+ 0.55,
+ 1.13,
+ 1.22,
+ 0.54,
+ 0.3,
+ 0.55,
+ 1.07,
+ 0.38,
+ 0.3,
+ 0.31,
+ 1.03,
+ 1.2,
+ 1.09,
+ 0.63,
+ 1.7,
+ 0.26,
+ 1.21,
+ 0.37,
+ 0.3,
+ 0.4,
+ 1.19,
+ 1.1,
+ 0.32,
+ 0.32,
+ 0.55,
+ 0.7,
+ 0.35,
+ 0.55,
+ 0.9,
+ 1.22,
+ 0.41,
+ 0.74,
+ 0.9,
+ 0.28,
+ 1.23,
+ 0.41,
+ 0.55,
+ 0.71,
+ 0.72,
+ 0.72,
+ 0.57,
+ 1.07,
+ 1.51,
+ 1.51,
+ 0.51,
+ 0.35,
+ 0.43,
+ 0.33,
+ 0.53,
+ 0.26,
+ 1.06,
+ 0.31,
+ 1.1,
+ 0.72,
+ 0.7111339777607055,
+ 0.4994884904461816,
+ 0.5493512312187724,
+ 1.1321011707505835,
+ 1.2190837385700815,
+ 0.5409626951479006,
+ 0.2994550717059788,
+ 0.5504492669416847,
+ 1.070471897719336,
+ 0.3801233447656072,
+ 0.2999338201627972,
+ 0.3095583418293734,
+ 1.0315372198190234,
+ 1.2010109434121479,
+ 1.091976512742137,
+ 0.6307545361095129,
+ 1.6992661830836782,
+ 0.2604202702155868,
+ 1.212203353616784,
+ 0.36940739155978497,
+ 0.299795475600578,
+ 0.39983634145073604,
+ 1.1895328641714293,
+ 1.0990980585281178,
+ 0.31990663835236127,
+ 0.32040919153150527,
+ 0.5498289860698858,
+ 0.6990033428090267,
+ 0.350693382217959,
+ 0.5506035142868777,
+ 0.8989748463128192,
+ 1.218684651371456,
+ 0.409690047113998,
+ 0.7406522630317631,
+ 0.89932311629362,
+ 0.2799685289825418,
+ 1.2315118308088653,
+ 0.41038775652720166,
+ 0.5489356773969423,
+ 0.7111002951160296,
+ 0.7211773208520164,
+ 0.7186277856782949,
+ 0.5707868009202163,
+ 1.0714047427636404,
+ 1.5126696824438066,
+ 1.5128715779151687,
+ 0.5092340059214038,
+ 0.34948820438172357,
+ 0.42980724332218584,
+ 0.329441570151787,
+ 0.5291041086009575,
+ 0.2601948517187721,
+ 1.0591038864640532,
+ 0.3103498452537972,
+ 1.1003801925084704,
+ 0.7189529705838424
+ ],
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "e771ed",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "21e50c",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "64d2c7",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "fc938f",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "5f7fa9",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "7677a5",
+ "yaxis": "y2",
+ "ysrc": "jackp:17616:567114",
+ "xsrc": "jackp:17616:2bf765",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "y": [
+ 2779,
+ 921,
+ 552,
+ 4432,
+ 4538,
+ 2335,
+ 5456,
+ 8541,
+ 5627,
+ 8219,
+ 1389,
+ 2330,
+ 647,
+ 12686,
+ 4064,
+ 14150,
+ 1709,
+ 10608,
+ 537,
+ 5255,
+ 446,
+ 15746,
+ 2784.0891882709925,
+ 919.4394682707192,
+ 551.0255032388903,
+ 4431.402793708898,
+ 4532.074621231837,
+ 2332.3701670604687,
+ 5451.373192556821,
+ 8527.422635327583,
+ 5616.948054509229,
+ 8224.123822918935,
+ 1387.7587547065266,
+ 2331.9925803066576,
+ 647.0251053310153,
+ 12683.598824787783,
+ 4065.7841856221626,
+ 14131.082587428302,
+ 1710.6393712564948,
+ 10597.578923512478,
+ 536.7958596900687,
+ 5259.862072434795,
+ 445.1803439678226,
+ 15751.295924196802
+ ],
+ "x": [
+ 0.73,
+ 0.42,
+ 0.35,
+ 1.01,
+ 1.12,
+ 0.7,
+ 1.06,
+ 1.51,
+ 1.06,
+ 1.51,
+ 0.52,
+ 0.7,
+ 0.35,
+ 1.65,
+ 0.9,
+ 2.01,
+ 0.62,
+ 1.58,
+ 0.34,
+ 1.02,
+ 0.31,
+ 2.48,
+ 0.7296668084672592,
+ 0.4204559656223413,
+ 0.34973268668994983,
+ 1.0119182198808359,
+ 1.1221279006949385,
+ 0.6987872687759356,
+ 1.0587773120199977,
+ 1.5129104821712054,
+ 1.0594720763855323,
+ 1.5116976945998972,
+ 0.5206048179810856,
+ 0.6987743043575617,
+ 0.3497267153487859,
+ 1.6526174692366742,
+ 0.8997553281014519,
+ 2.011405506181477,
+ 0.6187712125815792,
+ 1.5804901885141154,
+ 0.3396234100568092,
+ 1.0182148468730474,
+ 0.30959402900137517,
+ 2.4802924468059957
+ ],
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "033de3",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "f6e73c",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "14dc4b",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "44b8c9",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "5f7fa1",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "59b4c9",
+ "yaxis": "y2",
+ "ysrc": "jackp:17616:42cadc",
+ "xsrc": "jackp:17616:1ea406",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "y": [
+ 3669,
+ 4475,
+ 16565,
+ 5314,
+ 15919,
+ 3193,
+ 4569,
+ 3669.100120314125,
+ 4476.889906507577,
+ 16537.846400564747,
+ 5308.750209547583,
+ 15904.305296694685,
+ 3188.583934150139,
+ 4560.655470173187
+ ],
+ "x": [
+ 0.9,
+ 1.01,
+ 2.02,
+ 1.16,
+ 2.01,
+ 0.9,
+ 1,
+ 0.9002013524445966,
+ 1.0107320724879023,
+ 2.0170503357200134,
+ 1.1596227373901677,
+ 2.0093263061134414,
+ 0.8995271327185058,
+ 0.9980620609339724
+ ],
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "33d4ca",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "b8d304",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "65e3d1",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "6c7e23",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "e4ea3c",
+ "yaxis": "y2",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "524443",
+ "yaxis": "y2",
+ "ysrc": "jackp:17616:b896d3",
+ "xsrc": "jackp:17616:0f5f52",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "y": [
+ 2293,
+ 4166,
+ 11655,
+ 2291.2579453210374,
+ 4163.061091310426,
+ 11649.610193064767
+ ],
+ "x": [
+ 1.05,
+ 1,
+ 2,
+ 1.048161417706883,
+ 0.9998849509107828,
+ 1.999517668963265
+ ],
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "0481fb",
+ "yaxis": "y3",
+ "ysrc": "jackp:17616:474ec3",
+ "xsrc": "jackp:17616:36d4e6",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "y": [
+ 18242,
+ 4746,
+ 1667,
+ 14775,
+ 12338,
+ 4719,
+ 9498,
+ 2753,
+ 17000,
+ 628,
+ 13182,
+ 16190,
+ 1073,
+ 9850,
+ 8630,
+ 1923,
+ 552,
+ 3183,
+ 473,
+ 5269,
+ 1821,
+ 537,
+ 15065,
+ 13753,
+ 4131,
+ 842,
+ 8736,
+ 4476,
+ 608,
+ 18260.24257817437,
+ 4755.466564383378,
+ 1667.6968278130844,
+ 14802.797230622908,
+ 12332.946531154392,
+ 4719.776244421079,
+ 9493.149588811244,
+ 2751.031996916293,
+ 16969.039964066902,
+ 627.8496436408922,
+ 13192.177820692472,
+ 16186.288184368308,
+ 1074.3305003765563,
+ 9848.140898542066,
+ 8645.816281907193,
+ 1925.9455417559818,
+ 551.5412558938524,
+ 3186.2492368382464,
+ 472.0951607515579,
+ 5275.220643616439,
+ 1824.5562181424898,
+ 537.563473644462,
+ 15056.802876898995,
+ 13757.002668058696,
+ 4129.388750775684,
+ 843.5495873693501,
+ 8735.038860268722,
+ 4479.908116535391,
+ 608.4425251211663
+ ],
+ "x": [
+ 3.01,
+ 1.13,
+ 0.63,
+ 2.04,
+ 2.01,
+ 1.32,
+ 1.51,
+ 0.76,
+ 2.31,
+ 0.31,
+ 2.03,
+ 2.2,
+ 0.52,
+ 2.05,
+ 1.6,
+ 0.71,
+ 0.3,
+ 1.11,
+ 0.3,
+ 1.23,
+ 0.71,
+ 0.31,
+ 2.08,
+ 2.1,
+ 1.2,
+ 0.4,
+ 1.5,
+ 1.08,
+ 0.3,
+ 3.00866603765751,
+ 1.1293281343996375,
+ 0.6307844369316802,
+ 2.0384023516122025,
+ 2.0068633382955934,
+ 1.3205287495473481,
+ 1.5123914894737311,
+ 0.7609997895950064,
+ 2.3062099106596197,
+ 0.3093868886800573,
+ 2.0309794475279808,
+ 2.2040908122100307,
+ 0.5205192560226196,
+ 2.0510789663417963,
+ 1.5984065881831886,
+ 0.7100310197384573,
+ 0.29956138260797893,
+ 1.1119834665913224,
+ 0.29968560544092815,
+ 1.2318413451957055,
+ 0.7099753164163385,
+ 0.3099803155084778,
+ 2.0768215764733498,
+ 2.097908957227755,
+ 1.2017904406022437,
+ 0.39985575489000624,
+ 1.5027728023766775,
+ 1.0785274739922557,
+ 0.3005943007678021
+ ],
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "26e520",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "e3f2c2",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "aca325",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "95a8c5",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "6b87ad",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "ea480c",
+ "yaxis": "y3",
+ "ysrc": "jackp:17616:d4eb68",
+ "xsrc": "jackp:17616:856c9d",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "y": [
+ 540,
+ 16407,
+ 626,
+ 17747,
+ 2422,
+ 5506,
+ 648,
+ 2852,
+ 449,
+ 2083,
+ 6405,
+ 1365,
+ 11255,
+ 675,
+ 463,
+ 715,
+ 2490,
+ 452,
+ 4641,
+ 11238,
+ 4602,
+ 628,
+ 1589,
+ 4511,
+ 589,
+ 692,
+ 1173,
+ 418,
+ 10907,
+ 5376,
+ 4997,
+ 1170,
+ 2715,
+ 15606,
+ 596,
+ 6381,
+ 403,
+ 9465,
+ 6511,
+ 4596,
+ 5421,
+ 539.7725159431469,
+ 16415.644417706975,
+ 625.9201105287154,
+ 17734.474151848528,
+ 2421.724018263086,
+ 5515.048981639579,
+ 648.5603397120559,
+ 2850.660342266724,
+ 448.3285656160375,
+ 2086.5848017125345,
+ 6394.930184196881,
+ 1366.8450125964907,
+ 11263.61497326674,
+ 675.9383368969148,
+ 462.2055712394157,
+ 716.2110738489611,
+ 2489.2641704036523,
+ 451.7295240779792,
+ 4634.421224995775,
+ 11220.076813934693,
+ 4602.122496280042,
+ 628.173376989635,
+ 1591.395607063416,
+ 4502.514064171004,
+ 588.491219979844,
+ 690.9805691413943,
+ 1171.3643511082464,
+ 417.4728566784541,
+ 10906.651323742877,
+ 5378.748596946066,
+ 5005.252038466077,
+ 1169.2600703095384,
+ 2719.8754596200574,
+ 15588.315203417436,
+ 596.6016201152287,
+ 6373.967581835601,
+ 402.4902128461435,
+ 9483.57559324243,
+ 6515.037754360971,
+ 4593.431407381753,
+ 5422.269201223942
+ ],
+ "x": [
+ 0.3,
+ 2,
+ 0.38,
+ 2.17,
+ 0.78,
+ 1.11,
+ 0.32,
+ 0.78,
+ 0.32,
+ 0.7,
+ 1.17,
+ 0.47,
+ 2,
+ 0.33,
+ 0.33,
+ 0.35,
+ 0.7,
+ 0.31,
+ 1.01,
+ 2.36,
+ 1,
+ 0.31,
+ 0.64,
+ 1,
+ 0.34,
+ 0.4,
+ 0.53,
+ 0.31,
+ 1.5,
+ 1.2,
+ 1.04,
+ 0.54,
+ 0.74,
+ 2.26,
+ 0.4,
+ 1.24,
+ 0.33,
+ 1.52,
+ 1.51,
+ 1.2,
+ 1.09,
+ 0.2999801143707278,
+ 2.001098364104527,
+ 0.38017679159371537,
+ 2.1712101043808825,
+ 0.7814061804341412,
+ 1.1109268461451032,
+ 0.3201287161570626,
+ 0.7810373350004609,
+ 0.31996713674067073,
+ 0.7011231689217999,
+ 1.1693914500624067,
+ 0.4698872038216249,
+ 2.0034739177846124,
+ 0.32946085821133164,
+ 0.3301183170331197,
+ 0.3493499345343906,
+ 0.6988900750677473,
+ 0.31028712898704086,
+ 1.0090075552853044,
+ 2.361358655761997,
+ 0.9993987030716112,
+ 0.3101560244651787,
+ 0.6391241852544398,
+ 0.9996067791302367,
+ 0.34064800044569965,
+ 0.3993392802654636,
+ 0.530763272619824,
+ 0.31033134801184414,
+ 1.5006607288171012,
+ 1.2021667838614023,
+ 1.0409747196572967,
+ 0.539404146432422,
+ 0.7410911199327412,
+ 2.257464456131887,
+ 0.40062251745767913,
+ 1.2404714837494788,
+ 0.33053069487200953,
+ 1.5230364058116463,
+ 1.5108006891185375,
+ 1.1981870999774435,
+ 1.09160654867685
+ ],
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "f6efae",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "783be4",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "f40f64",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "b3f280",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "d9f1d9",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "b16b7f",
+ "yaxis": "y3",
+ "ysrc": "jackp:17616:6e5c39",
+ "xsrc": "jackp:17616:f6b328",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "y": [
+ 7345,
+ 2655,
+ 2271,
+ 2414,
+ 5979,
+ 2327,
+ 850,
+ 2329,
+ 2337,
+ 4126,
+ 12221,
+ 3570,
+ 16392,
+ 1883,
+ 14489,
+ 694,
+ 3581,
+ 9925,
+ 1926,
+ 8214,
+ 383,
+ 626,
+ 7346.677684565021,
+ 2650.8651508338826,
+ 2273.7171735005018,
+ 2413.3467611955653,
+ 5981.958951306695,
+ 2327.977690141955,
+ 850.2034510756258,
+ 2327.680462558811,
+ 2335.8288230967846,
+ 4132.8069921999495,
+ 12221.8725895644,
+ 3572.7557581970905,
+ 16359.746698766015,
+ 1885.5004412264695,
+ 14493.517929580792,
+ 694.0033081154417,
+ 3577.6625599189574,
+ 9920.774354051882,
+ 1927.790871329409,
+ 8222.719401387305,
+ 382.41198590592063,
+ 626.2649608412387
+ ],
+ "x": [
+ 1.59,
+ 0.81,
+ 0.78,
+ 0.8,
+ 1.22,
+ 0.71,
+ 0.43,
+ 0.8,
+ 0.72,
+ 0.9,
+ 2,
+ 0.9,
+ 2.03,
+ 0.71,
+ 1.94,
+ 0.33,
+ 0.9,
+ 1.59,
+ 0.71,
+ 1.51,
+ 0.31,
+ 0.34,
+ 1.587413246333523,
+ 0.8093944505318844,
+ 0.7792947889080841,
+ 0.7988755864760525,
+ 1.2209031786135156,
+ 0.7111650214112349,
+ 0.4295065217821689,
+ 0.8007849837049644,
+ 0.7212283333855459,
+ 0.9004491071818032,
+ 2.000496708970912,
+ 0.9007649721135049,
+ 2.032061797051653,
+ 0.7092212731828491,
+ 1.9376138601910464,
+ 0.3295836235537146,
+ 0.8993272291180375,
+ 1.5929734670428513,
+ 0.7108383521600118,
+ 1.5072312835039463,
+ 0.3097129253084051,
+ 0.33970899408100125
+ ],
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "155d8f",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "8854fa",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "cb95c0",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "b14904",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "9fbea2",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "c6d9fa",
+ "yaxis": "y3",
+ "ysrc": "jackp:17616:b8c075",
+ "xsrc": "jackp:17616:e7d470",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "y": [
+ 9702,
+ 3696,
+ 2142,
+ 755,
+ 8975,
+ 3079,
+ 3399,
+ 2700,
+ 5054,
+ 4273,
+ 521,
+ 10184,
+ 7815,
+ 13956,
+ 2142,
+ 15147,
+ 9712.46835850596,
+ 3688.702106751374,
+ 2142.21678675203,
+ 754.9198607337196,
+ 8975.070818071235,
+ 3083.4183555000013,
+ 3403.6812388912713,
+ 2697.8749221674393,
+ 5044.650649644011,
+ 4273.0245142306085,
+ 521.8758058909739,
+ 10188.305907121061,
+ 7805.547668405433,
+ 13953.229708296907,
+ 2140.275248694395,
+ 15171.416219778084
+ ],
+ "x": [
+ 1.5,
+ 1.5,
+ 0.7,
+ 0.41,
+ 1.51,
+ 0.94,
+ 1.01,
+ 0.91,
+ 1.11,
+ 1,
+ 0.33,
+ 2.01,
+ 1.51,
+ 2.08,
+ 0.7,
+ 2.01,
+ 1.4990507930286983,
+ 1.497842616299511,
+ 0.6997722255449608,
+ 0.40924318449184616,
+ 1.5097072253472426,
+ 0.9387888155067724,
+ 1.0115644363303002,
+ 0.9096070990757399,
+ 1.1112199062258352,
+ 1.0001057928066628,
+ 0.330158170767867,
+ 2.0112904224843655,
+ 1.5128784392469679,
+ 2.084067410707246,
+ 0.7012891862703828,
+ 2.007063102306926
+ ],
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "2abad2",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "1bb905",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "355955",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "ecbc16",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "201556",
+ "yaxis": "y3",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "c631a8",
+ "yaxis": "y3",
+ "ysrc": "jackp:17616:63bc1a",
+ "xsrc": "jackp:17616:106531",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "y": [
+ 919,
+ 7912,
+ 2129,
+ 2208,
+ 1799,
+ 2666,
+ 918.4704898769342,
+ 7907.136291060538,
+ 2128.1423739982088,
+ 2208.788758644016,
+ 1802.5154943362259,
+ 2668.025260312547
+ ],
+ "x": [
+ 0.47,
+ 1.5,
+ 0.91,
+ 0.71,
+ 0.72,
+ 0.9,
+ 0.4704023297305381,
+ 1.4977863936967992,
+ 0.9084133296853414,
+ 0.7103930062458634,
+ 0.7209212404651739,
+ 0.8998394272706466
+ ],
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "b906f7",
+ "yaxis": "y4",
+ "ysrc": "jackp:17616:292289",
+ "xsrc": "jackp:17616:878a2c",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "y": [
+ 2863,
+ 2307,
+ 2705,
+ 10046,
+ 4916,
+ 1963,
+ 1845,
+ 9274,
+ 5762,
+ 5701,
+ 552,
+ 16793,
+ 1752,
+ 772,
+ 1720,
+ 1167,
+ 803,
+ 1215,
+ 1814,
+ 689,
+ 4037,
+ 1734,
+ 2251,
+ 941,
+ 593,
+ 1208,
+ 552,
+ 5206,
+ 4304,
+ 1582,
+ 2331,
+ 3048,
+ 644,
+ 404,
+ 5543,
+ 816,
+ 911,
+ 4903,
+ 1040,
+ 772,
+ 709,
+ 8108,
+ 1994,
+ 2203,
+ 851,
+ 1910,
+ 2864.5589721284523,
+ 2310.0187806754184,
+ 2703.8303484277467,
+ 10039.361388761881,
+ 4908.813784305043,
+ 1960.5394363759692,
+ 1842.0316422617161,
+ 9280.250540212272,
+ 5761.135659336807,
+ 5695.22040652117,
+ 551.1873613407281,
+ 16797.37021372704,
+ 1751.1851312032595,
+ 771.4388582041303,
+ 1718.4199648560812,
+ 1167.114098659569,
+ 802.590958072453,
+ 1214.3302580140542,
+ 1814.8757499624326,
+ 687.7640113767613,
+ 4032.5116523496285,
+ 1730.9754595973682,
+ 2252.5433615319075,
+ 942.2774857092497,
+ 593.4562663976149,
+ 1206.869071531859,
+ 551.1241213678821,
+ 5206.232955364515,
+ 4298.008944041489,
+ 1579.5840732381446,
+ 2333.110359116706,
+ 3047.686995568163,
+ 642.8744784894147,
+ 404.7766021887578,
+ 5541.1892269877,
+ 816.016916255178,
+ 912.3349622136429,
+ 4897.662113178408,
+ 1040.4998113083197,
+ 770.9130398976133,
+ 708.0534136985216,
+ 8106.382844886812,
+ 1995.560389003191,
+ 2205.036000808757,
+ 851.2062770757921,
+ 1913.4779164405904
+ ],
+ "x": [
+ 0.71,
+ 0.75,
+ 0.7,
+ 1,
+ 1.24,
+ 0.56,
+ 0.5,
+ 1,
+ 1.05,
+ 1.01,
+ 0.3,
+ 1.5,
+ 0.5,
+ 0.4,
+ 0.52,
+ 0.35,
+ 0.37,
+ 0.5,
+ 0.6,
+ 0.36,
+ 0.77,
+ 0.53,
+ 0.61,
+ 0.38,
+ 0.31,
+ 0.3,
+ 0.3,
+ 1.01,
+ 0.9,
+ 0.41,
+ 0.55,
+ 0.72,
+ 0.35,
+ 0.22,
+ 1.01,
+ 0.31,
+ 0.3,
+ 1.06,
+ 0.42,
+ 0.4,
+ 0.3,
+ 1.5,
+ 0.54,
+ 0.51,
+ 0.36,
+ 0.56,
+ 0.7095952457810268,
+ 0.7493102382520047,
+ 0.6993105454875977,
+ 1.0018097943694881,
+ 1.2400104080181733,
+ 0.559097435012193,
+ 0.4994893317079819,
+ 0.9980763245195371,
+ 1.0501376293339906,
+ 1.0115922906684707,
+ 0.3002733285948228,
+ 1.502165273044929,
+ 0.49970485820754434,
+ 0.3993573688685752,
+ 0.5201559493014003,
+ 0.3494308281482808,
+ 0.3695749338142994,
+ 0.49950144124219814,
+ 0.600804388726145,
+ 0.3595810642696111,
+ 0.7712647739646804,
+ 0.5293944132354899,
+ 0.6100420971179406,
+ 0.3803928197016165,
+ 0.30962958159511333,
+ 0.29940857916770136,
+ 0.3001940097060251,
+ 1.0082958535232003,
+ 0.8988417603040997,
+ 0.40921643628818016,
+ 0.5498768501182337,
+ 0.7207189503957052,
+ 0.34976793621809926,
+ 0.22039340558917098,
+ 1.0106201277903797,
+ 0.30956169633828223,
+ 0.3002853919703458,
+ 1.0612485142531116,
+ 0.4202931113466637,
+ 0.4000921901650729,
+ 0.30006470721243417,
+ 1.4987085824921036,
+ 0.5406675066398264,
+ 0.5100146826664943,
+ 0.3598241547900064,
+ 0.5604615113364197
+ ],
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "358fb1",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "4fc378",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "3f4a7d",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "ffd6da",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "6bfb73",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "d2a84e",
+ "yaxis": "y4",
+ "ysrc": "jackp:17616:c068e9",
+ "xsrc": "jackp:17616:0d9a13",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "y": [
+ 2867,
+ 1235,
+ 2061,
+ 917,
+ 4839,
+ 2041,
+ 4861,
+ 1103,
+ 3322,
+ 1704,
+ 552,
+ 1034,
+ 684,
+ 2575,
+ 12688,
+ 537,
+ 7220,
+ 7564,
+ 7118,
+ 1427,
+ 998,
+ 689,
+ 2954,
+ 3223,
+ 4377,
+ 636,
+ 911,
+ 891,
+ 12261,
+ 1882,
+ 10441,
+ 4932,
+ 807,
+ 803,
+ 1266,
+ 15845,
+ 893,
+ 3321,
+ 769,
+ 6250,
+ 1230,
+ 709,
+ 707,
+ 681,
+ 5694,
+ 1665,
+ 971,
+ 3035,
+ 9870,
+ 1882,
+ 2423,
+ 1787,
+ 1690,
+ 12417,
+ 663,
+ 2482,
+ 2993,
+ 689,
+ 5717,
+ 734,
+ 709,
+ 713,
+ 884,
+ 663,
+ 2421,
+ 827,
+ 2056,
+ 9625,
+ 552,
+ 2863.3073846875254,
+ 1235.0410754277873,
+ 2061.1394030167376,
+ 915.5460946470334,
+ 4840.9846383887125,
+ 2044.5735038711914,
+ 4865.148402462572,
+ 1103.191363544857,
+ 3320.779683599345,
+ 1704.7010892779192,
+ 551.8548962306251,
+ 1033.3040308505065,
+ 682.9997097438029,
+ 2579.7997552364773,
+ 12698.30467149865,
+ 537.3304689572768,
+ 7213.1034246567315,
+ 7552.605922415122,
+ 7118.707269159842,
+ 1424.2734001919348,
+ 998.4908298383382,
+ 688.9514289857805,
+ 2952.9428414578947,
+ 3220.766467597102,
+ 4375.32885504362,
+ 635.2022222747906,
+ 910.5862918571029,
+ 892.3567592817293,
+ 12257.5533002125,
+ 1881.3450320704349,
+ 10446.743428736338,
+ 4929.580388367656,
+ 805.569939905001,
+ 802.6998692137066,
+ 1268.0852528054163,
+ 15846.969660047213,
+ 894.0691627019108,
+ 3315.565390592984,
+ 769.0875218910231,
+ 6243.133909175408,
+ 1231.3364188389496,
+ 709.7742956728271,
+ 706.9069655201511,
+ 680.7050827492476,
+ 5687.610631325589,
+ 1663.7096872279442,
+ 972.5164136016865,
+ 3031.0993950104835,
+ 9874.405826360817,
+ 1878.6737842173793,
+ 2423.082094818438,
+ 1784.7823820019962,
+ 1690.458973083242,
+ 12401.487462051002,
+ 664.216597363298,
+ 2485.1778587845793,
+ 2993.0418137039082,
+ 689.6024853765649,
+ 5726.922382170822,
+ 734.3113300086499,
+ 708.8944508014835,
+ 714.2284257554941,
+ 885.3497085754199,
+ 661.7202060431199,
+ 2425.1177636878965,
+ 827.8640952398549,
+ 2055.189506639383,
+ 9619.484248129835,
+ 552.4883231960048
+ ],
+ "x": [
+ 0.7,
+ 0.44,
+ 0.56,
+ 0.4,
+ 1.03,
+ 0.54,
+ 1,
+ 0.42,
+ 0.72,
+ 0.53,
+ 0.3,
+ 0.31,
+ 0.31,
+ 0.7,
+ 1.51,
+ 0.36,
+ 1.04,
+ 1.02,
+ 1.02,
+ 0.41,
+ 0.34,
+ 0.36,
+ 0.72,
+ 0.51,
+ 0.76,
+ 0.36,
+ 0.3,
+ 0.4,
+ 1.13,
+ 0.51,
+ 1.25,
+ 1.05,
+ 0.43,
+ 0.34,
+ 0.35,
+ 1.55,
+ 0.33,
+ 0.52,
+ 0.26,
+ 1.03,
+ 0.41,
+ 0.3,
+ 0.32,
+ 0.33,
+ 1.01,
+ 0.4,
+ 0.36,
+ 0.78,
+ 1.11,
+ 0.51,
+ 0.7,
+ 0.51,
+ 0.61,
+ 1.24,
+ 0.36,
+ 0.5,
+ 0.72,
+ 0.36,
+ 0.91,
+ 0.31,
+ 0.3,
+ 0.32,
+ 0.38,
+ 0.36,
+ 0.58,
+ 0.35,
+ 0.51,
+ 1.06,
+ 0.3,
+ 0.6989623468091251,
+ 0.44015492068136575,
+ 0.558992498106414,
+ 0.3992779520495528,
+ 1.028118218451617,
+ 0.5395123197558108,
+ 1.000447007915268,
+ 0.42027486445645146,
+ 0.720756686110868,
+ 0.5298696150742593,
+ 0.29953225833437297,
+ 0.30951319547269907,
+ 0.3103490915050528,
+ 0.699056019161115,
+ 1.5084146118225819,
+ 0.3601027536915589,
+ 1.04108897947698,
+ 1.0209987652060446,
+ 1.0197083080901237,
+ 0.40964708208221423,
+ 0.33972433424752196,
+ 0.3607130175399627,
+ 0.7214324629475471,
+ 0.5094805648818637,
+ 0.7592626300409893,
+ 0.359833881185996,
+ 0.300007443355754,
+ 0.4004962206845817,
+ 1.1299763936301004,
+ 0.5093346764817639,
+ 1.2496053829670777,
+ 1.0482035538393493,
+ 0.4294321141775121,
+ 0.3399703880862411,
+ 0.3498491543749766,
+ 1.5506865396353218,
+ 0.3295000189302351,
+ 0.5209645347964528,
+ 0.26002682877117406,
+ 1.0301101594320927,
+ 0.40935360635645507,
+ 0.30024077594040544,
+ 0.32042061969909846,
+ 0.3293481742358264,
+ 1.0108083834784685,
+ 0.39956265247931133,
+ 0.35963482817250303,
+ 0.7808643364198934,
+ 1.1118227708916855,
+ 0.5095944528676186,
+ 0.6990935615569753,
+ 0.5105255611019138,
+ 0.6102585544224337,
+ 1.2420464321606084,
+ 0.3604096008981896,
+ 0.5008643651869537,
+ 0.7205925998023248,
+ 0.3602002413686343,
+ 0.9083702651943231,
+ 0.30965397753340557,
+ 0.30048250550429756,
+ 0.3197498031771598,
+ 0.37964838648217664,
+ 0.3600979132655104,
+ 0.5799034377628591,
+ 0.3495500956953886,
+ 0.5092887189411638,
+ 1.058866266124176,
+ 0.3005072830515016
+ ],
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "364998",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "542f19",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "f7264e",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "4d1ada",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "d4e245",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "732989",
+ "yaxis": "y4",
+ "ysrc": "jackp:17616:262a53",
+ "xsrc": "jackp:17616:30666d",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "y": [
+ 912,
+ 910,
+ 1616,
+ 3480,
+ 470,
+ 720,
+ 3048,
+ 700,
+ 3406,
+ 2318,
+ 6125,
+ 720,
+ 5086,
+ 462,
+ 1787,
+ 4869,
+ 2628,
+ 2677,
+ 1368,
+ 492,
+ 952,
+ 1380,
+ 4472,
+ 1990,
+ 6863,
+ 911.7571258263765,
+ 911.4501018096493,
+ 1615.472756430965,
+ 3485.4787985684948,
+ 470.029458704632,
+ 719.7160814098978,
+ 3042.0403334864905,
+ 699.7741920437832,
+ 3404.934169479795,
+ 2318.7113929737493,
+ 6124.594593191709,
+ 720.2984662869684,
+ 5095.530013638114,
+ 462.68144173408405,
+ 1784.9307118231027,
+ 4869.513391131503,
+ 2626.3476896651614,
+ 2680.739084362534,
+ 1367.3713984458125,
+ 491.7807187611099,
+ 952.6408842225588,
+ 1380.2263337012007,
+ 4467.785680864238,
+ 1992.1058219231454,
+ 6868.143239755623
+ ],
+ "x": [
+ 0.42,
+ 0.42,
+ 0.51,
+ 0.96,
+ 0.27,
+ 0.4,
+ 0.75,
+ 0.42,
+ 0.71,
+ 0.7,
+ 1.21,
+ 0.4,
+ 0.92,
+ 0.31,
+ 0.51,
+ 0.84,
+ 0.7,
+ 0.7,
+ 0.55,
+ 0.33,
+ 0.4,
+ 0.51,
+ 1.01,
+ 0.7,
+ 1.02,
+ 0.4198071647972373,
+ 0.4198591637979997,
+ 0.5099331029118354,
+ 0.9618861620618347,
+ 0.2704313844586991,
+ 0.39924110039544597,
+ 0.7494835679403926,
+ 0.4200527624738516,
+ 0.708807760979284,
+ 0.7011569105750158,
+ 1.2119519250440798,
+ 0.39960779864756396,
+ 0.9208751340219598,
+ 0.30958787738277777,
+ 0.5090276662721537,
+ 0.8390247918114567,
+ 0.6987722601252729,
+ 0.7002103356071783,
+ 0.5491438340036795,
+ 0.32953039479305485,
+ 0.40059861096045923,
+ 0.5110159931709428,
+ 1.0099122318425084,
+ 0.7012360006760092,
+ 1.02062607608907
+ ],
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "4e5ea2",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "729d16",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "2728e1",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "745982",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "e083f0",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "6a8130",
+ "yaxis": "y4",
+ "ysrc": "jackp:17616:cecf5b",
+ "xsrc": "jackp:17616:8d8322",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "y": [
+ 552,
+ 4739,
+ 589,
+ 4191,
+ 1605,
+ 3773,
+ 4672,
+ 6113,
+ 571,
+ 589,
+ 551.2096258820169,
+ 4732.222562861587,
+ 588.0936305859233,
+ 4195.275085329128,
+ 1601.9295456751415,
+ 3767.6887724443454,
+ 4678.473412888158,
+ 6120.376710154089,
+ 572.0760307506761,
+ 588.0398503500066
+ ],
+ "x": [
+ 0.3,
+ 0.9,
+ 0.32,
+ 1.04,
+ 0.52,
+ 1.02,
+ 1.01,
+ 1.01,
+ 0.31,
+ 0.32,
+ 0.30041440318281726,
+ 0.8993025185928925,
+ 0.3206203195607978,
+ 1.0379315457690532,
+ 0.5209108978358578,
+ 1.018025003889451,
+ 1.0085006430810832,
+ 1.0101443262180516,
+ 0.3104840531850404,
+ 0.3199495401743513
+ ],
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "aebf8f",
+ "yaxis": "y4",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "showlegend": false,
+ "uid": "29557f",
+ "yaxis": "y4",
+ "ysrc": "jackp:17616:1f8d2e",
+ "xsrc": "jackp:17616:1dd020",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "showlegend": false,
+ "uid": "3e367a",
+ "yaxis": "y4",
+ "ysrc": "jackp:17616:1f8d2e",
+ "xsrc": "jackp:17616:1dd020",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "showlegend": false,
+ "uid": "337db2",
+ "yaxis": "y4",
+ "ysrc": "jackp:17616:1f8d2e",
+ "xsrc": "jackp:17616:1dd020",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "showlegend": false,
+ "uid": "daacfd",
+ "yaxis": "y4",
+ "ysrc": "jackp:17616:1f8d2e",
+ "xsrc": "jackp:17616:1dd020",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "showlegend": false,
+ "uid": "ec7e38",
+ "yaxis": "y4",
+ "ysrc": "jackp:17616:1f8d2e",
+ "xsrc": "jackp:17616:1dd020",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "4c0c61",
+ "yaxis": "y5",
+ "ysrc": "jackp:17616:e2020b",
+ "xsrc": "jackp:17616:097e51",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "y": [
+ 3936,
+ 2318,
+ 2392,
+ 2491,
+ 17803,
+ 4200,
+ 706,
+ 773,
+ 1433,
+ 4134,
+ 583,
+ 421,
+ 2724,
+ 982,
+ 1010,
+ 1163,
+ 4062,
+ 5288,
+ 880,
+ 7127,
+ 574,
+ 1192,
+ 6702,
+ 8946,
+ 3218,
+ 5544,
+ 6554,
+ 802,
+ 5292,
+ 4063,
+ 2874,
+ 5942,
+ 6033,
+ 990,
+ 605,
+ 2290,
+ 576,
+ 1415,
+ 4497,
+ 4682,
+ 933,
+ 2234,
+ 3158,
+ 3931.837708030491,
+ 2319.699422315125,
+ 2390.062813733005,
+ 2493.494090227297,
+ 17798.504702894414,
+ 4194.454143130031,
+ 706.4647994870666,
+ 771.6668454068943,
+ 1435.6234735072787,
+ 4141.438903500546,
+ 583.9041152004794,
+ 421.0349395584988,
+ 2724.3031939353505,
+ 983.1398188527362,
+ 1008.6027134639477,
+ 1164.6774117204175,
+ 4060.7967517406437,
+ 5298.318791505002,
+ 880.6010356863378,
+ 7118.916866791324,
+ 573.2537403169265,
+ 1192.900853313141,
+ 6705.594880031928,
+ 8952.039106546421,
+ 3217.3226110976234,
+ 5544.582586219176,
+ 6542.950615156624,
+ 800.4542157076876,
+ 5296.577853667223,
+ 4056.9083804933903,
+ 2869.1349213892913,
+ 5948.7399079809165,
+ 6028.28084119197,
+ 989.6854945471318,
+ 605.9759567958016,
+ 2288.3328474928917,
+ 574.8881561527019,
+ 1415.4727675977429,
+ 4490.227928693989,
+ 4680.324129368353,
+ 932.2692171005122,
+ 2237.0724057591005,
+ 3152.827709927717
+ ],
+ "x": [
+ 0.9,
+ 0.56,
+ 0.61,
+ 0.76,
+ 2.03,
+ 1,
+ 0.35,
+ 0.32,
+ 0.5,
+ 1.11,
+ 0.35,
+ 0.32,
+ 0.72,
+ 0.4,
+ 0.39,
+ 0.4,
+ 0.9,
+ 1.01,
+ 0.34,
+ 1.01,
+ 0.34,
+ 0.41,
+ 1.01,
+ 1.04,
+ 0.77,
+ 1,
+ 1.52,
+ 0.31,
+ 1,
+ 0.97,
+ 0.7,
+ 1.06,
+ 1.14,
+ 0.32,
+ 0.3,
+ 0.56,
+ 0.25,
+ 0.55,
+ 1.01,
+ 0.95,
+ 0.38,
+ 0.7,
+ 1.06,
+ 0.9009796560684872,
+ 0.5592132566863012,
+ 0.6104504350348424,
+ 0.7605709762454774,
+ 2.0307821742516885,
+ 1.0009342687462592,
+ 0.3493498568845443,
+ 0.32061982696181046,
+ 0.5001642403039719,
+ 1.1100730307750273,
+ 0.34945757393641713,
+ 0.3200454105306684,
+ 0.7189488997252828,
+ 0.40017756174158015,
+ 0.39003018683452495,
+ 0.3998666910295283,
+ 0.8992521344047488,
+ 1.0110641019784592,
+ 0.339898866480955,
+ 1.0092814011281794,
+ 0.3394471883114631,
+ 0.41036293316604955,
+ 1.008668649220819,
+ 1.0382033070976184,
+ 0.77110350357629,
+ 1.0016037883546938,
+ 1.51861229729931,
+ 0.30955512273164554,
+ 1.0005159102324452,
+ 0.970899305661036,
+ 0.6992740675910675,
+ 1.059523326403535,
+ 1.1421594290895956,
+ 0.3200213935232487,
+ 0.3004145188239654,
+ 0.5596716812883158,
+ 0.2504291299059961,
+ 0.5507217384509376,
+ 1.01186180914583,
+ 0.9500947756409788,
+ 0.3805198320484217,
+ 0.6994693063063538,
+ 1.06107419306477
+ ],
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "3f9f46",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "2f6286",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "6661f8",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "f6820a",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "fab8c9",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "0224d9",
+ "yaxis": "y5",
+ "ysrc": "jackp:17616:7a9127",
+ "xsrc": "jackp:17616:0baf91",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "y": [
+ 802,
+ 2841,
+ 1085,
+ 4591,
+ 2525,
+ 3531,
+ 1041,
+ 1629,
+ 9996,
+ 1451,
+ 8486,
+ 3018,
+ 1131,
+ 880,
+ 3248,
+ 865,
+ 985,
+ 858,
+ 863,
+ 2087,
+ 2504,
+ 3404,
+ 3945,
+ 2491,
+ 7654,
+ 1142,
+ 906,
+ 8958,
+ 977,
+ 870,
+ 1168,
+ 16513,
+ 625,
+ 1340,
+ 4412,
+ 3713,
+ 572,
+ 4458,
+ 5894,
+ 3405,
+ 906,
+ 1021,
+ 1305,
+ 6360,
+ 1122,
+ 3524,
+ 901,
+ 1196,
+ 814,
+ 1806,
+ 1915,
+ 828,
+ 821,
+ 873,
+ 1908,
+ 3066,
+ 7589,
+ 1080,
+ 1666,
+ 9257,
+ 1221,
+ 914,
+ 3293,
+ 426,
+ 963,
+ 3879,
+ 9881,
+ 7602,
+ 801.8474226736259,
+ 2843.533820734616,
+ 1083.8040490910673,
+ 4584.375315720565,
+ 2530.0491864706514,
+ 3526.4469417212895,
+ 1041.1604499152845,
+ 1627.4335736810858,
+ 10004.86570031459,
+ 1452.5339514475966,
+ 8474.824207317666,
+ 3012.113476820919,
+ 1129.4064086525898,
+ 880.771298663351,
+ 3247.1698460237963,
+ 865.1654802002445,
+ 984.000708622825,
+ 857.0818405209352,
+ 862.7400230139052,
+ 2086.773982544986,
+ 2501.17401395372,
+ 3406.2508044034103,
+ 3943.395918142712,
+ 2495.467025522719,
+ 7667.467733471126,
+ 1142.0501611568695,
+ 904.6978645715419,
+ 8946.950883521036,
+ 976.322720414314,
+ 869.8924795778994,
+ 1168.7505709406078,
+ 16483.14285816954,
+ 623.9516709082503,
+ 1337.8212923410697,
+ 4406.40050075415,
+ 3713.6890660065305,
+ 572.4218010211939,
+ 4451.375824246316,
+ 5901.825540934005,
+ 3405.237771810646,
+ 906.6763614534037,
+ 1022.3535939186175,
+ 1306.3054040898544,
+ 6355.1785034089835,
+ 1121.0690913225824,
+ 3528.731506665465,
+ 902.7482185124352,
+ 1195.14106611502,
+ 813.1550026082033,
+ 1805.5055266342133,
+ 1916.495774650391,
+ 828.5667287789233,
+ 819.7380355303768,
+ 872.7004265779482,
+ 1906.0541103611608,
+ 3066.2712269169515,
+ 7578.229245192539,
+ 1079.6791822361645,
+ 1665.2484416675534,
+ 9261.973067891313,
+ 1223.0209703397654,
+ 914.0661974289,
+ 3291.473018208659,
+ 425.75806543224076,
+ 962.7509534114408,
+ 3884.2319710408947,
+ 9898.629592854317,
+ 7602.982252117563
+ ],
+ "x": [
+ 0.31,
+ 0.52,
+ 0.41,
+ 1.05,
+ 0.71,
+ 0.78,
+ 0.37,
+ 0.52,
+ 1.5,
+ 0.52,
+ 1.2,
+ 0.71,
+ 0.3,
+ 0.34,
+ 0.61,
+ 0.38,
+ 0.31,
+ 0.34,
+ 0.41,
+ 0.73,
+ 0.52,
+ 0.71,
+ 1.01,
+ 0.71,
+ 1.02,
+ 0.42,
+ 0.34,
+ 1,
+ 0.31,
+ 0.41,
+ 0.4,
+ 1.8,
+ 0.31,
+ 0.56,
+ 0.81,
+ 0.8,
+ 0.24,
+ 1.01,
+ 1.23,
+ 0.71,
+ 0.35,
+ 0.33,
+ 0.5,
+ 0.92,
+ 0.31,
+ 0.73,
+ 0.31,
+ 0.44,
+ 0.3,
+ 0.52,
+ 0.56,
+ 0.3,
+ 0.39,
+ 0.3,
+ 0.53,
+ 0.71,
+ 1.12,
+ 0.4,
+ 0.58,
+ 1.05,
+ 0.59,
+ 0.31,
+ 0.8,
+ 0.34,
+ 0.24,
+ 0.74,
+ 1.03,
+ 1.01,
+ 0.30954994652519724,
+ 0.5208032566044443,
+ 0.4095967887970371,
+ 1.048061887713359,
+ 0.7087092382320656,
+ 0.7785665698142189,
+ 0.37043046492809606,
+ 0.5210399194069976,
+ 1.4984718564634394,
+ 0.5195351243763988,
+ 1.199990919104789,
+ 0.7096586301000417,
+ 0.299579794050352,
+ 0.34066082057393476,
+ 0.6107481367389077,
+ 0.3799796464644953,
+ 0.3098558299018244,
+ 0.33967695544089865,
+ 0.4099123904073333,
+ 0.7291295943004695,
+ 0.5198624390822058,
+ 0.7100630526312683,
+ 1.0108265669806162,
+ 0.7101544089530725,
+ 1.0186251728286808,
+ 0.4205436946006773,
+ 0.3400266446995739,
+ 0.9983076956814654,
+ 0.3102882252437644,
+ 0.41033615196824,
+ 0.4000340535477765,
+ 1.796992877466342,
+ 0.3103140548369838,
+ 0.5591828883942883,
+ 0.809121287578271,
+ 0.8005488478457026,
+ 0.2403822173493155,
+ 1.0083262901776855,
+ 1.231438522374149,
+ 0.7093562066012159,
+ 0.34931124848568634,
+ 0.3297726065481198,
+ 0.5003700542505818,
+ 0.920151213840957,
+ 0.30939407564251603,
+ 0.730548433099732,
+ 0.30985726210289327,
+ 0.44033934134464586,
+ 0.30002098406116245,
+ 0.5190041520981057,
+ 0.5610522625439187,
+ 0.30007177322138245,
+ 0.3893728789013147,
+ 0.30014145505530004,
+ 0.5310226281555821,
+ 0.710446506954066,
+ 1.1202002277591714,
+ 0.3994691323887583,
+ 0.5789970620924505,
+ 1.0517354943020338,
+ 0.5893605356638563,
+ 0.3098142813172692,
+ 0.7988049819714432,
+ 0.34054372155118495,
+ 0.23992379133725777,
+ 0.740616112816685,
+ 1.0304172815589203,
+ 1.0090599821290713
+ ],
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "dc8094",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "54591c",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "ed48ac",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "7611cd",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "a10b4e",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "631b1f",
+ "yaxis": "y5",
+ "ysrc": "jackp:17616:8e2b9c",
+ "xsrc": "jackp:17616:87a56a",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "y": [
+ 4088,
+ 792,
+ 5988,
+ 832,
+ 2274,
+ 4617,
+ 3471,
+ 8922,
+ 4373,
+ 1940,
+ 530,
+ 2230,
+ 657,
+ 3950,
+ 518,
+ 3420,
+ 2161,
+ 1338,
+ 3356,
+ 3692,
+ 10650,
+ 608,
+ 2808,
+ 10173,
+ 4399,
+ 6061,
+ 2812,
+ 4082,
+ 2041,
+ 3457,
+ 3104,
+ 5491,
+ 7037,
+ 4498,
+ 2914,
+ 3854,
+ 4091.770619905916,
+ 791.8788152924913,
+ 5998.39969636659,
+ 832.8714517237546,
+ 2275.131637346825,
+ 4616.819165396445,
+ 3476.2955005463364,
+ 8912.77689339611,
+ 4366.100837007636,
+ 1937.894842803201,
+ 529.6517426062028,
+ 2231.746589191861,
+ 657.7648220730073,
+ 3950.411051414913,
+ 518.3856456521538,
+ 3426.7978358521314,
+ 2162.7536391200597,
+ 1339.627878286515,
+ 3359.537441057553,
+ 3689.663295742099,
+ 10659.724832252119,
+ 606.8528159815402,
+ 2812.2656439797756,
+ 10169.829600305939,
+ 4396.512692389016,
+ 6072.326325002493,
+ 2816.519249887763,
+ 4077.7254471800475,
+ 2040.8879260021874,
+ 3460.5973784232256,
+ 3099.504700844642,
+ 5498.246022664184,
+ 7050.921451852076,
+ 4502.138714803353,
+ 2910.913199404449,
+ 3861.1658736012314
+ ],
+ "x": [
+ 1,
+ 0.43,
+ 1.01,
+ 0.39,
+ 0.75,
+ 0.9,
+ 0.8,
+ 1.01,
+ 1.02,
+ 0.6,
+ 0.23,
+ 0.7,
+ 0.26,
+ 0.9,
+ 0.27,
+ 0.93,
+ 0.7,
+ 0.56,
+ 0.89,
+ 0.71,
+ 1.23,
+ 0.24,
+ 0.7,
+ 1.2,
+ 0.77,
+ 1.07,
+ 0.7,
+ 1,
+ 0.51,
+ 0.9,
+ 0.71,
+ 1.06,
+ 1.01,
+ 0.9,
+ 0.8,
+ 0.92,
+ 1.0003035426970706,
+ 0.4295109142819016,
+ 1.0107488989296045,
+ 0.38982412875121975,
+ 0.7485760271588692,
+ 0.8991887231312831,
+ 0.7996952088228714,
+ 1.0100519962121524,
+ 1.020542362047063,
+ 0.6011621118392716,
+ 0.22990015122688792,
+ 0.6996961098579478,
+ 0.26043509120756186,
+ 0.9008026447369735,
+ 0.270306912152565,
+ 0.9285262018613064,
+ 0.7010417352789942,
+ 0.5600026627313066,
+ 0.8908166154810649,
+ 0.7113268763995968,
+ 1.2286815775462263,
+ 0.23991792007518498,
+ 0.6986845887263227,
+ 1.2016528890195273,
+ 0.7694426417218985,
+ 1.072120652172668,
+ 0.7002418782913061,
+ 1.0017451301179852,
+ 0.5101388127166598,
+ 0.9015531870984818,
+ 0.7093694663125639,
+ 1.0600599894089113,
+ 1.010360923484627,
+ 0.9007818255124138,
+ 0.8009325806511676,
+ 0.9198594783578563
+ ],
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "39c683",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "989bc9",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "50519f",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "d92979",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "a7b6f1",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "92020c",
+ "yaxis": "y5",
+ "ysrc": "jackp:17616:d23bb6",
+ "xsrc": "jackp:17616:b1d52c",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "y": [
+ 2098,
+ 6332,
+ 1182,
+ 2313,
+ 1563,
+ 6446,
+ 1406,
+ 4678,
+ 3532,
+ 645,
+ 3445,
+ 2130,
+ 4899,
+ 2281,
+ 2094.728777840808,
+ 6338.591957753566,
+ 1182.9184017402188,
+ 2317.471584183058,
+ 1562.4000576664196,
+ 6451.7835090991,
+ 1406.0335701822944,
+ 4670.846873956501,
+ 3530.875314246411,
+ 645.324403427794,
+ 3441.931964132381,
+ 2129.4262064945306,
+ 4897.635831583063,
+ 2277.0287810459713
+ ],
+ "x": [
+ 1,
+ 1.01,
+ 0.49,
+ 0.7,
+ 0.54,
+ 1.01,
+ 0.51,
+ 1.02,
+ 1.01,
+ 0.32,
+ 0.7,
+ 0.71,
+ 1.01,
+ 0.53,
+ 0.9980571099735377,
+ 1.0091673563802186,
+ 0.49056167950757007,
+ 0.6995485812259165,
+ 0.5400468359947491,
+ 1.010325110140703,
+ 0.5100215591615811,
+ 1.0200657900929562,
+ 1.009896322010345,
+ 0.32023712619894307,
+ 0.7005182318299936,
+ 0.7107101623313072,
+ 1.00877267630766,
+ 0.5297233084986743
+ ],
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "c9fbf7",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "0f85c8",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "cfbf7e",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "120f88",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "d9a8e8",
+ "yaxis": "y5",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "537fed",
+ "yaxis": "y5",
+ "ysrc": "jackp:17616:3c7520",
+ "xsrc": "jackp:17616:b91412",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "y": [
+ 2691,
+ 16280,
+ 810,
+ 613,
+ 1158,
+ 1974,
+ 4561,
+ 3688,
+ 13622,
+ 2695.4766957642546,
+ 16258.216833453082,
+ 808.4758077845083,
+ 613.3897000366561,
+ 1159.0920608061306,
+ 1970.6879983168462,
+ 4566.461330167714,
+ 3691.1995207916834,
+ 13603.894418813674
+ ],
+ "x": [
+ 0.72,
+ 2.03,
+ 0.36,
+ 0.5,
+ 0.7,
+ 0.7,
+ 1.01,
+ 0.96,
+ 1.72,
+ 0.7206387693237523,
+ 2.029408151693385,
+ 0.35977063423793854,
+ 0.500216241272243,
+ 0.7008310300098876,
+ 0.6996785953510553,
+ 1.0103142588592704,
+ 0.9612923697382663,
+ 1.7167738455757051
+ ],
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "f44104",
+ "yaxis": "y6",
+ "ysrc": "jackp:17616:3c2a0b",
+ "xsrc": "jackp:17616:19613b",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "y": [
+ 553,
+ 17175,
+ 4077,
+ 2433,
+ 1851,
+ 3450,
+ 842,
+ 1005,
+ 5485,
+ 7670,
+ 792,
+ 658,
+ 9900,
+ 14882,
+ 544,
+ 6875,
+ 1613,
+ 698,
+ 2854,
+ 1116,
+ 1097,
+ 2673,
+ 4044,
+ 2064,
+ 1028,
+ 11644,
+ 3662,
+ 956,
+ 1037,
+ 9072,
+ 1079,
+ 964,
+ 816,
+ 1294,
+ 1079,
+ 17552,
+ 1000,
+ 1003,
+ 4334,
+ 3133,
+ 4027,
+ 1746,
+ 4853,
+ 2629,
+ 1708,
+ 552.320766463179,
+ 17177.169117874604,
+ 4080.8276363802984,
+ 2432.5985426744555,
+ 1849.7000496150404,
+ 3453.6583981820963,
+ 842.0315796959627,
+ 1006.7838099735794,
+ 5487.181653665482,
+ 7658.597309279918,
+ 792.7549738545077,
+ 657.1490495084415,
+ 9891.747771988723,
+ 14881.610133341625,
+ 544.5462006344087,
+ 6870.911647595399,
+ 1610.5324184305398,
+ 697.1248936820117,
+ 2858.554912933277,
+ 1117.8199343265728,
+ 1097.5692547502435,
+ 2669.8774155178576,
+ 4039.155009583268,
+ 2064.514504146819,
+ 1029.71067411172,
+ 11627.073532009625,
+ 3654.919171151088,
+ 957.5069548972714,
+ 1036.1474456326698,
+ 9081.215452610659,
+ 1079.0344968284244,
+ 963.6257008560758,
+ 816.5646731532389,
+ 1294.0845065305014,
+ 1076.8537774408392,
+ 17585.43484438099,
+ 1000.6654631204958,
+ 1002.4006442667917,
+ 4330.404471012981,
+ 3128.161073621237,
+ 4032.1007163784816,
+ 1748.2312151354295,
+ 4856.939699017142,
+ 2627.4390729771785,
+ 1705.0485634883596
+ ],
+ "x": [
+ 0.24,
+ 1.57,
+ 1,
+ 0.66,
+ 0.57,
+ 1,
+ 0.32,
+ 0.48,
+ 1.06,
+ 1.07,
+ 0.43,
+ 0.3,
+ 1.5,
+ 1.71,
+ 0.31,
+ 1.24,
+ 0.57,
+ 0.31,
+ 0.7,
+ 0.35,
+ 0.3,
+ 0.7,
+ 1.01,
+ 0.63,
+ 0.44,
+ 1.41,
+ 0.9,
+ 0.34,
+ 0.52,
+ 1.5,
+ 0.41,
+ 0.41,
+ 0.31,
+ 0.46,
+ 0.41,
+ 1.59,
+ 0.38,
+ 0.44,
+ 0.9,
+ 0.74,
+ 0.94,
+ 0.5,
+ 1.01,
+ 0.71,
+ 0.66,
+ 0.240082383608907,
+ 1.5677747059252893,
+ 1.0013592402614278,
+ 0.6591117043824954,
+ 0.5698849183015202,
+ 1.0018252160221826,
+ 0.3197349568953318,
+ 0.4796179070735658,
+ 1.061165388911516,
+ 1.070473045335228,
+ 0.4303683726855205,
+ 0.29946392074051287,
+ 1.5027492694547653,
+ 1.7091398772825894,
+ 0.310198594201264,
+ 1.2400441113281861,
+ 0.5701497640764086,
+ 0.31021567520090665,
+ 0.7012437010052769,
+ 0.3494795597792197,
+ 0.3003389643664923,
+ 0.7002414149073978,
+ 1.0105928275040212,
+ 0.6294736070883389,
+ 0.44032727665148874,
+ 1.4087212639024023,
+ 0.9000761921266145,
+ 0.3403859347526661,
+ 0.5190013243443063,
+ 1.4986404798251245,
+ 0.40991088090262656,
+ 0.4092035401248669,
+ 0.3103234684003706,
+ 0.45939365923818676,
+ 0.41020448033079704,
+ 1.590047612075604,
+ 0.38052940601089924,
+ 0.4393354374982491,
+ 0.8997379629481208,
+ 0.7413346610234965,
+ 0.9395712103213891,
+ 0.5009865084170507,
+ 1.0114866363328459,
+ 0.7113134668075434,
+ 0.6598192258765629
+ ],
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "8b57ac",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "a14450",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "2d9c83",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "deb670",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "c63123",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "8fb1ff",
+ "yaxis": "y6",
+ "ysrc": "jackp:17616:aca112",
+ "xsrc": "jackp:17616:1f9da8",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "y": [
+ 1724,
+ 4199,
+ 1675,
+ 911,
+ 6048,
+ 7631,
+ 1613,
+ 1609,
+ 7198,
+ 866,
+ 865,
+ 4832,
+ 1069,
+ 2491,
+ 3381,
+ 4504,
+ 787,
+ 3729,
+ 766,
+ 7088,
+ 723,
+ 723,
+ 1668,
+ 975,
+ 487,
+ 3553,
+ 1755,
+ 792,
+ 881,
+ 1781,
+ 956,
+ 1104,
+ 5599,
+ 702,
+ 1819,
+ 956,
+ 1074,
+ 3330,
+ 698,
+ 435,
+ 658,
+ 1746,
+ 516,
+ 741,
+ 427,
+ 1205,
+ 904,
+ 8413,
+ 702,
+ 16507,
+ 1094,
+ 702,
+ 11642,
+ 2952,
+ 3510,
+ 4205,
+ 5534,
+ 6328,
+ 1197,
+ 987,
+ 621,
+ 1754,
+ 16650,
+ 1847,
+ 1883,
+ 649,
+ 2656,
+ 1041,
+ 1177,
+ 625,
+ 3941,
+ 10104,
+ 530,
+ 3620,
+ 781,
+ 5372,
+ 1722.8901803752985,
+ 4199.875579890047,
+ 1674.9853723739323,
+ 910.8769283050219,
+ 6056.986989880234,
+ 7624.59624956712,
+ 1612.3315019369463,
+ 1610.895406150162,
+ 7197.992588690986,
+ 867.3805766982041,
+ 865.3552837119032,
+ 4826.152964286931,
+ 1070.1254852366874,
+ 2488.2513345177667,
+ 3375.944211083391,
+ 4497.222395726983,
+ 785.4913907587396,
+ 3732.614190908278,
+ 767.4485201967035,
+ 7087.272150495703,
+ 723.8631674059392,
+ 723.0704518337116,
+ 1666.9162502489662,
+ 976.7674538362112,
+ 486.5147121395696,
+ 3554.050375522784,
+ 1758.4336664991376,
+ 792.1071818211401,
+ 881.1870748214133,
+ 1782.3696839491074,
+ 957.5566901054617,
+ 1102.5263309892848,
+ 5606.1964737770295,
+ 702.5445235570187,
+ 1822.1282557654602,
+ 957.705904498667,
+ 1074.7143773948137,
+ 3325.3790823290587,
+ 699.2111343796319,
+ 435.45920606339007,
+ 659.0993380680658,
+ 1745.4106253468112,
+ 516.6916008396566,
+ 741.9793264984147,
+ 427.0124593404038,
+ 1205.8064502006291,
+ 902.314924188603,
+ 8412.571143152316,
+ 701.6902992890869,
+ 16503.287086499324,
+ 1094.7943956128338,
+ 702.3847974482447,
+ 11659.257380972997,
+ 2947.8390967002647,
+ 3504.5153048739726,
+ 4200.133702797785,
+ 5530.01223138437,
+ 6317.239129159934,
+ 1194.6504982266056,
+ 985.2869126397331,
+ 622.0818219260613,
+ 1754.6384783217818,
+ 16626.22674083621,
+ 1850.0078920503545,
+ 1885.9988564477771,
+ 649.7115284704144,
+ 2654.720445895572,
+ 1043.0001653236757,
+ 1177.410495688278,
+ 625.9605249156893,
+ 3936.9743640674014,
+ 10085.61610690339,
+ 529.285576750833,
+ 3617.590103542725,
+ 779.5338805029787,
+ 5381.705324989795
+ ],
+ "x": [
+ 0.5,
+ 1.03,
+ 0.55,
+ 0.3,
+ 1,
+ 1.27,
+ 0.54,
+ 0.55,
+ 1.01,
+ 0.38,
+ 0.31,
+ 1.01,
+ 0.38,
+ 0.57,
+ 0.71,
+ 1.01,
+ 0.28,
+ 1.13,
+ 0.3,
+ 1.21,
+ 0.33,
+ 0.33,
+ 0.52,
+ 0.4,
+ 0.28,
+ 0.71,
+ 0.59,
+ 0.33,
+ 0.34,
+ 0.51,
+ 0.3,
+ 0.5,
+ 1.01,
+ 0.32,
+ 0.57,
+ 0.34,
+ 0.31,
+ 0.7,
+ 0.31,
+ 0.31,
+ 0.3,
+ 0.5,
+ 0.32,
+ 0.33,
+ 0.32,
+ 0.51,
+ 0.4,
+ 1.06,
+ 0.32,
+ 1.62,
+ 0.36,
+ 0.32,
+ 1.52,
+ 0.7,
+ 0.73,
+ 0.7,
+ 1.01,
+ 1.18,
+ 0.35,
+ 0.31,
+ 0.3,
+ 0.54,
+ 2,
+ 0.54,
+ 0.59,
+ 0.37,
+ 0.7,
+ 0.37,
+ 0.42,
+ 0.28,
+ 0.92,
+ 1.07,
+ 0.23,
+ 0.73,
+ 0.33,
+ 1.01,
+ 0.49900484807230416,
+ 1.0299805043073862,
+ 0.5506604648878496,
+ 0.3003800591808506,
+ 0.9996492274662403,
+ 1.2714178004710106,
+ 0.5398442217352499,
+ 0.5501429259689692,
+ 1.0119923083139604,
+ 0.37929081745711807,
+ 0.3100542075183445,
+ 1.0096110003524488,
+ 0.37985413637523524,
+ 0.5693254753624232,
+ 0.7104405587103362,
+ 1.0086621742026696,
+ 0.280488060323646,
+ 1.128699017472166,
+ 0.30028118152764033,
+ 1.2118649535577726,
+ 0.32997638333472157,
+ 0.3304415795482866,
+ 0.5204102791159161,
+ 0.3999846438520429,
+ 0.2801618903283543,
+ 0.7099987408614844,
+ 0.5902688662100554,
+ 0.32947218542016465,
+ 0.3400801425514219,
+ 0.5101483821145416,
+ 0.2998254996456135,
+ 0.5007180759103517,
+ 1.00990923322329,
+ 0.3195487052571707,
+ 0.5689386690040519,
+ 0.339921679176885,
+ 0.3100781254441127,
+ 0.7012708172480682,
+ 0.30964833117288687,
+ 0.31041195683799716,
+ 0.2994424437701638,
+ 0.50034058278844,
+ 0.3205205800066817,
+ 0.330230338079349,
+ 0.31957283796630276,
+ 0.5091914545658371,
+ 0.4000600213594887,
+ 1.0610214791497647,
+ 0.3205533838922689,
+ 1.6221064949120607,
+ 0.35961984082180826,
+ 0.3198128057980894,
+ 1.5225734461355696,
+ 0.700340479818071,
+ 0.7287532567434658,
+ 0.6989176631692738,
+ 1.0108829992990223,
+ 1.1777240511175244,
+ 0.35031872370426365,
+ 0.3103325311205659,
+ 0.3001418655636086,
+ 0.5406142289751227,
+ 1.9984601086678988,
+ 0.5402987461284409,
+ 0.5904882411711434,
+ 0.37039817138892833,
+ 0.6989943104001308,
+ 0.36940623476358003,
+ 0.42043426564428055,
+ 0.2799901748947451,
+ 0.9211514780582396,
+ 1.0688836132683857,
+ 0.22987285585108314,
+ 0.7296406368104583,
+ 0.3304154873110362,
+ 1.00910336278114
+ ],
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "3c5552",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "52c2dc",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "0d1561",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "3c4552",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "088474",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "e676c7",
+ "yaxis": "y6",
+ "ysrc": "jackp:17616:24335b",
+ "xsrc": "jackp:17616:2f0d1f",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "y": [
+ 13015,
+ 811,
+ 653,
+ 4170,
+ 879,
+ 2310,
+ 3358,
+ 1629,
+ 6300,
+ 16064,
+ 3374,
+ 4011,
+ 705,
+ 2894,
+ 698,
+ 2793,
+ 2043,
+ 2516,
+ 3886,
+ 1883,
+ 15840,
+ 622,
+ 772,
+ 13892,
+ 7306,
+ 2040,
+ 2967,
+ 9475,
+ 2757,
+ 1362,
+ 11460,
+ 485,
+ 707,
+ 995,
+ 2363,
+ 737,
+ 1175,
+ 7677,
+ 13025.75829910102,
+ 809.8451977189434,
+ 651.7192249334846,
+ 4172.7321773727745,
+ 878.6387169281485,
+ 2307.8077616829205,
+ 3354.2018667353773,
+ 1631.8146389411634,
+ 6297.359370406381,
+ 16063.23619902139,
+ 3376.107672913597,
+ 4007.7542798577397,
+ 704.4385021505707,
+ 2898.056201620157,
+ 696.8331849406733,
+ 2790.5601910406112,
+ 2046.0018332523427,
+ 2516.2939395273384,
+ 3890.2020341521174,
+ 1886.3764379503073,
+ 15819.499439411098,
+ 621.101812781229,
+ 772.2540295633265,
+ 13883.716383093695,
+ 7300.4304217164845,
+ 2043.9810455598906,
+ 2968.9553049332,
+ 9490.416013516326,
+ 2758.1947480683543,
+ 1361.9103862987956,
+ 11452.692502115951,
+ 485.24263989902187,
+ 707.9471990848626,
+ 993.663277742166,
+ 2362.9576836171645,
+ 737.0585439266869,
+ 1175.2883456415364,
+ 7686.848864815678
+ ],
+ "x": [
+ 1.2,
+ 0.37,
+ 0.42,
+ 1.11,
+ 0.4,
+ 0.7,
+ 0.7,
+ 0.5,
+ 1.5,
+ 2,
+ 0.72,
+ 0.92,
+ 0.41,
+ 0.81,
+ 0.31,
+ 0.7,
+ 0.53,
+ 0.71,
+ 0.94,
+ 0.57,
+ 2,
+ 0.3,
+ 0.33,
+ 1.5,
+ 1.01,
+ 0.56,
+ 0.7,
+ 1.22,
+ 0.7,
+ 0.59,
+ 1.51,
+ 0.24,
+ 0.28,
+ 0.3,
+ 0.75,
+ 0.4,
+ 0.52,
+ 1.03,
+ 1.2005349982364548,
+ 0.37028931090244405,
+ 0.4194512783808139,
+ 1.1078337782160257,
+ 0.40060158708129534,
+ 0.6989616132300857,
+ 0.6994770029241004,
+ 0.4999956507923215,
+ 1.498897632045621,
+ 1.9996306399897568,
+ 0.7185990276393558,
+ 0.9215716038135582,
+ 0.4100256751279456,
+ 0.8088526848613312,
+ 0.31034149440875736,
+ 0.7005823239146423,
+ 0.5296457659178686,
+ 0.710828133447656,
+ 0.9418661634595475,
+ 0.5698863258580035,
+ 1.9972013131045436,
+ 0.3003463902176272,
+ 0.3300024009448402,
+ 1.5020407443396695,
+ 1.0094174066629473,
+ 0.5609881936266335,
+ 0.6997748576477741,
+ 1.2223379806704078,
+ 0.6987027108771681,
+ 0.589770349648716,
+ 1.5087430292371877,
+ 0.2399652650405737,
+ 0.2804759825384551,
+ 0.30000323431241654,
+ 0.7505818934272024,
+ 0.40070291502091443,
+ 0.5199751531429737,
+ 1.0279595744053134
+ ],
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "28ccac",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "e0c904",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "f8cc43",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "80ec78",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "2f9354",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "0df67e",
+ "yaxis": "y6",
+ "ysrc": "jackp:17616:ab87d8",
+ "xsrc": "jackp:17616:5cf5f8",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "y": [
+ 1554,
+ 5226,
+ 2777,
+ 1224,
+ 18236,
+ 2020,
+ 1336,
+ 588,
+ 16582,
+ 1906,
+ 818,
+ 2305,
+ 603,
+ 3218,
+ 4307,
+ 1395,
+ 2038,
+ 5871,
+ 2573,
+ 1554.82679634372,
+ 5229.637262409208,
+ 2776.556266746367,
+ 1226.3428644712444,
+ 18225.29149999851,
+ 2016.3363500299324,
+ 1338.0192597944567,
+ 587.8559859298695,
+ 16598.40152269338,
+ 1909.1776224636033,
+ 818.9306906997704,
+ 2307.9922895417158,
+ 604.0656406173046,
+ 3219.7036970836352,
+ 4307.956119607175,
+ 1393.2588074119992,
+ 2040.5793456531917,
+ 5863.881001850177,
+ 2570.820248102243
+ ],
+ "x": [
+ 0.52,
+ 1.01,
+ 0.7,
+ 0.53,
+ 2.02,
+ 0.51,
+ 0.58,
+ 0.35,
+ 2.01,
+ 0.51,
+ 0.41,
+ 0.72,
+ 0.3,
+ 0.9,
+ 1,
+ 0.5,
+ 0.7,
+ 1.68,
+ 0.71,
+ 0.520789692478644,
+ 1.0111478450077682,
+ 0.699997673113697,
+ 0.5296351634987143,
+ 2.0183020167395758,
+ 0.5100954750848816,
+ 0.5798291524507336,
+ 0.3498260154557881,
+ 2.006447247570367,
+ 0.5099278932911349,
+ 0.40997920599961973,
+ 0.720881576319888,
+ 0.29953727426899396,
+ 0.8988683873371643,
+ 0.9980367147532674,
+ 0.5008025322854965,
+ 0.6989047666651016,
+ 1.6821206422486499,
+ 0.7111415983770736
+ ],
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "9c4c87",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "e5fa55",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "a77d42",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "d56609",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "b3dc64",
+ "yaxis": "y6",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "182eac",
+ "yaxis": "y6",
+ "ysrc": "jackp:17616:601f7d",
+ "xsrc": "jackp:17616:12eb26",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "y": [
+ 2241,
+ 4140,
+ 829,
+ 818,
+ 3407,
+ 1641,
+ 2242.925253387802,
+ 4147.072830942468,
+ 830.3155842019498,
+ 817.9753582654272,
+ 3402.31278199832,
+ 1643.1965704151419
+ ],
+ "x": [
+ 0.7,
+ 1,
+ 0.47,
+ 0.41,
+ 0.92,
+ 0.58,
+ 0.6986007710827323,
+ 1.0000527453298353,
+ 0.47052746043580773,
+ 0.4101842905936925,
+ 0.9214184711784675,
+ 0.5800807083668212
+ ],
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "376ffd",
+ "yaxis": "y7",
+ "ysrc": "jackp:17616:375858",
+ "xsrc": "jackp:17616:725e8e",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "y": [
+ 15035,
+ 4347,
+ 7757,
+ 13703,
+ 1931,
+ 8770,
+ 11966,
+ 12369,
+ 4200,
+ 12369,
+ 15062.902455167796,
+ 4338.961958906902,
+ 7769.210456296972,
+ 13703.220747815232,
+ 1932.2894796404178,
+ 8755.730187476243,
+ 11965.185424809546,
+ 12352.45020984692,
+ 4204.349098242828,
+ 12392.587560058308
+ ],
+ "x": [
+ 2.09,
+ 1.15,
+ 1.71,
+ 2.22,
+ 0.74,
+ 1.51,
+ 2,
+ 2.01,
+ 1.25,
+ 2.01,
+ 2.086005047884031,
+ 1.1516691656148632,
+ 1.7127093010205887,
+ 2.2204492059573364,
+ 0.7409341289336699,
+ 1.510592768848777,
+ 2.0022666903811523,
+ 2.0063055978129785,
+ 1.2515511924834368,
+ 2.011281381954683
+ ],
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "611cdd",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "713024",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "6bc46f",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "3c8aac",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "6c6bf7",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "5d7bed",
+ "yaxis": "y7",
+ "ysrc": "jackp:17616:a2b0f6",
+ "xsrc": "jackp:17616:9cbb59",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "y": [
+ 1843,
+ 706,
+ 8687,
+ 2850,
+ 4361,
+ 601,
+ 3048,
+ 2139,
+ 5083,
+ 3922,
+ 4860,
+ 7550,
+ 1899,
+ 4092,
+ 1841.3601040191468,
+ 705.0089045819386,
+ 8700.662967375847,
+ 2846.8969096114097,
+ 4352.502914491186,
+ 600.010558662529,
+ 3043.745239213812,
+ 2136.0156869435637,
+ 5079.6071077225915,
+ 3922.5938784664722,
+ 4868.644673061462,
+ 7542.439807411715,
+ 1901.6944864928223,
+ 4095.667245305671
+ ],
+ "x": [
+ 0.7,
+ 0.43,
+ 1.52,
+ 0.75,
+ 1.09,
+ 0.37,
+ 0.9,
+ 0.72,
+ 1.23,
+ 1.03,
+ 1.26,
+ 1.53,
+ 0.71,
+ 1.11,
+ 0.6986172379787887,
+ 0.43060540251016755,
+ 1.51802673647325,
+ 0.7504261062807371,
+ 1.0892754392423503,
+ 0.36977360758923017,
+ 0.8991605153201632,
+ 0.7211999010546872,
+ 1.2305311529218212,
+ 1.0305125681710885,
+ 1.2604320890615313,
+ 1.5274280662291178,
+ 0.7106160170944144,
+ 1.1091913541364666
+ ],
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "f77a23",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "31c19e",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "bb8e17",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x2",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "506be4",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "fb235a",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "1b9a1f",
+ "yaxis": "y7",
+ "ysrc": "jackp:17616:93c145",
+ "xsrc": "jackp:17616:4bf754",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "y": [
+ 3576,
+ 731,
+ 3534,
+ 5029,
+ 6316,
+ 3112,
+ 13693,
+ 17920,
+ 5759,
+ 2774,
+ 12342,
+ 3576.0816876163076,
+ 731.8450534184641,
+ 3538.3881629269017,
+ 5019.916592161721,
+ 6318.027848339106,
+ 3116.588720689764,
+ 13671.827147967186,
+ 17946.88177845104,
+ 5752.4720331142635,
+ 2772.283520765185,
+ 12342.948879100728
+ ],
+ "x": [
+ 0.93,
+ 0.43,
+ 1.02,
+ 1.22,
+ 1.45,
+ 0.91,
+ 2.02,
+ 2.39,
+ 1.35,
+ 1.17,
+ 2,
+ 0.9314646758862032,
+ 0.42984234969015706,
+ 1.0182413961916694,
+ 1.2210483932827825,
+ 1.4493372013514345,
+ 0.9084700243314493,
+ 2.0211261895508548,
+ 2.3888521722984284,
+ 1.3489145458927079,
+ 1.170069082769639,
+ 1.9987036510530596
+ ],
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "e4c450",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "765cbc",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x3",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "a67094",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "0f1cf4",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "633596",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "26c716",
+ "yaxis": "y7",
+ "ysrc": "jackp:17616:ec6fcf",
+ "xsrc": "jackp:17616:6fd863",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "y": [
+ 4824,
+ 1959,
+ 3000,
+ 15231,
+ 3285,
+ 5096,
+ 10666,
+ 4831.47446349996,
+ 1956.9411648180162,
+ 3000.162971265123,
+ 15248.028051785392,
+ 3290.3892755081297,
+ 5106.18019222679,
+ 10646.73696276632
+ ],
+ "x": [
+ 1.21,
+ 0.72,
+ 0.93,
+ 2.56,
+ 1.04,
+ 1.21,
+ 2.02,
+ 1.2112145980970856,
+ 0.720411584031692,
+ 0.9305587282798337,
+ 2.558684517116645,
+ 1.041797811331994,
+ 1.2115245981725518,
+ 2.0225361219537636
+ ],
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "56b479",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x4",
+ "type": "scattergl",
+ "name": "Fair"
+ },
+ {
+ "uid": "d8c533",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(31, 119, 180)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Premium"
+ },
+ {
+ "uid": "fae6ca",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(255, 127, 14)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Ideal"
+ },
+ {
+ "uid": "9d702c",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(44, 160, 44)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Very Good"
+ },
+ {
+ "uid": "d2e073",
+ "yaxis": "y7",
+ "marker": {
+ "color": "rgb(214, 39, 40)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "type": "scattergl",
+ "name": "Good"
+ },
+ {
+ "uid": "db52b5",
+ "yaxis": "y7",
+ "ysrc": "jackp:17616:e406b3",
+ "xsrc": "jackp:17616:1f1b53",
+ "marker": {
+ "color": "rgb(148, 103, 189)",
+ "line": {
+ "color": "black",
+ "width": 0.1
+ },
+ "size": 4
+ },
+ "mode": "markers",
+ "xaxis": "x5",
+ "y": [
+ 15824,
+ 15845.340584731564
+ ],
+ "x": [
+ 2.4,
+ 2.402684126513055
+ ],
+ "type": "scattergl",
+ "name": "Fair"
+ }
+ ],
+ "layout": {
+ "width": 700,
+ "height": 700,
+ "showlegend": true,
+ "xaxis4": {
+ "domain": [
+ 0.609,
+ 0.7969999999999999
+ ],
+ "ticklen": 0,
+ "dtick": 0,
+ "range": [
+ -0.2,
+ 4.21
+ ],
+ "zeroline": false,
+ "position": 0,
+ "type": "linear",
+ "anchor": "free"
+ },
+ "yaxis6": {
+ "domain": [
+ 0.14500000000000002,
+ 0.275
+ ],
+ "ticklen": 0,
+ "dtick": 3942,
+ "range": [
+ -511.95000000000005,
+ 19199.6475
+ ],
+ "zeroline": false,
+ "position": 0,
+ "type": "linear",
+ "anchor": "free"
+ },
+ "yaxis": {
+ "domain": [
+ 0.8700000000000001,
+ 1
+ ],
+ "ticklen": 0,
+ "dtick": 3942,
+ "range": [
+ -511.95000000000005,
+ 19199.6475
+ ],
+ "zeroline": false,
+ "position": 0,
+ "type": "linear",
+ "anchor": "free"
+ },
+ "paper_bgcolor": "rgb(251, 251, 251)",
+ "xaxis5": {
+ "domain": [
+ 0.812,
+ 1
+ ],
+ "ticklen": 0,
+ "dtick": 0,
+ "range": [
+ -0.2,
+ 4.21
+ ],
+ "zeroline": false,
+ "position": 0,
+ "type": "linear",
+ "anchor": "free"
+ },
+ "dragmode": "select",
+ "xaxis3": {
+ "domain": [
+ 0.406,
+ 0.5940000000000001
+ ],
+ "ticklen": 0,
+ "dtick": 0,
+ "range": [
+ -0.2,
+ 4.21
+ ],
+ "zeroline": false,
+ "position": 0,
+ "type": "linear",
+ "anchor": "free"
+ },
+ "autosize": true,
+ "xaxis2": {
+ "domain": [
+ 0.203,
+ 0.391
+ ],
+ "ticklen": 0,
+ "dtick": 0,
+ "range": [
+ -0.2,
+ 4.21
+ ],
+ "zeroline": false,
+ "position": 0,
+ "type": "linear",
+ "anchor": "free"
+ },
+ "yaxis2": {
+ "domain": [
+ 0.7250000000000001,
+ 0.8550000000000001
+ ],
+ "ticklen": 0,
+ "dtick": 3942,
+ "range": [
+ -511.95000000000005,
+ 19199.6475
+ ],
+ "zeroline": false,
+ "position": 0,
+ "type": "linear",
+ "anchor": "free"
+ },
+ "yaxis3": {
+ "domain": [
+ 0.5800000000000001,
+ 0.7100000000000001
+ ],
+ "ticklen": 0,
+ "dtick": 3942,
+ "range": [
+ -511.95000000000005,
+ 19199.6475
+ ],
+ "zeroline": false,
+ "position": 0,
+ "type": "linear",
+ "anchor": "free"
+ },
+ "yaxis4": {
+ "domain": [
+ 0.43500000000000005,
+ 0.5650000000000001
+ ],
+ "ticklen": 0,
+ "dtick": 3942,
+ "range": [
+ -511.95000000000005,
+ 19199.6475
+ ],
+ "zeroline": false,
+ "position": 0,
+ "type": "linear",
+ "anchor": "free"
+ },
+ "yaxis5": {
+ "domain": [
+ 0.29000000000000004,
+ 0.42000000000000004
+ ],
+ "ticklen": 0,
+ "dtick": 3942,
+ "range": [
+ -511.95000000000005,
+ 19199.6475
+ ],
+ "zeroline": false,
+ "position": 0,
+ "type": "linear",
+ "anchor": "free"
+ },
+ "xaxis": {
+ "domain": [
+ 0,
+ 0.188
+ ],
+ "ticklen": 0,
+ "dtick": 0,
+ "range": [
+ -0.2,
+ 4.21
+ ],
+ "zeroline": false,
+ "type": "linear",
+ "anchor": "y7"
+ },
+ "yaxis7": {
+ "domain": [
+ 0,
+ 0.13
+ ],
+ "ticklen": 0,
+ "dtick": 3942,
+ "range": [
+ -511.95000000000005,
+ 19199.6475
+ ],
+ "zeroline": false,
+ "type": "linear",
+ "anchor": "x"
+ },
+ "title": "",
+ "hovermode": "closest",
+ "annotations": [
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "Premium",
+ "textangle": 0,
+ "y": 1.03,
+ "x": 0.094,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "Ideal",
+ "textangle": 0,
+ "y": 1.03,
+ "x": 0.29700000000000004,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "Very Good",
+ "textangle": 0,
+ "y": 1.03,
+ "x": 0.5,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "Good",
+ "textangle": 0,
+ "y": 1.03,
+ "x": 0.703,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "Fair",
+ "textangle": 0,
+ "y": 1.03,
+ "x": 0.906,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "G",
+ "textangle": 90,
+ "y": 0.935,
+ "x": 1.03,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "H",
+ "textangle": 90,
+ "y": 0.79,
+ "x": 1.03,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "I",
+ "textangle": 90,
+ "y": 0.645,
+ "x": 1.03,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "D",
+ "textangle": 90,
+ "y": 0.5,
+ "x": 1.03,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "F",
+ "textangle": 90,
+ "y": 0.35500000000000004,
+ "x": 1.03,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "E",
+ "textangle": 90,
+ "y": 0.21000000000000002,
+ "x": 1.03,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "J",
+ "textangle": 90,
+ "y": 0.065,
+ "x": 1.03,
+ "font": {
+ "color": "#0f0f0f",
+ "size": 13
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "carat",
+ "textangle": 0,
+ "y": -0.1,
+ "x": 0.5,
+ "font": {
+ "color": "#000000",
+ "size": 12
+ },
+ "showarrow": false
+ },
+ {
+ "yanchor": "middle",
+ "xref": "paper",
+ "xanchor": "center",
+ "yref": "paper",
+ "text": "price",
+ "textangle": 270,
+ "y": 0.5,
+ "x": -0.1,
+ "font": {
+ "color": "#000000",
+ "size": 12
+ },
+ "showarrow": false
+ }
+ ],
+ "legend": {
+ "y": 1,
+ "x": 1.05,
+ "yanchor": "top",
+ "borderwidth": 1,
+ "bgcolor": "#efefef"
+ }
+ }
+}
diff --git a/test/image/mocks/gl2d_scatter_fill_self_next.json b/test/image/mocks/gl2d_scatter_fill_self_next.json
new file mode 100644
index 00000000000..5fee62ccc61
--- /dev/null
+++ b/test/image/mocks/gl2d_scatter_fill_self_next.json
@@ -0,0 +1,28 @@
+{
+ "data":[
+ {
+ "x": [1, 2, 3, 1, null, 4, 5, 6],
+ "y": [2, 3, 2, 2, null, 3, 4, 3],
+ "fill": "tonext",
+ "line":{"shape": "spline"},
+ "type": "scattergl"
+ },
+ {
+ "x": [-1, 4, 9, null, 0, 1, 2],
+ "y": [1, 6, 1, null, 5, 6, 5],
+ "fill": "tonext",
+ "type": "scattergl"
+ },
+ {
+ "x": [6, 7, 8],
+ "y": [5, 6, 5],
+ "fill": "toself",
+ "type": "scattergl"
+ }
+ ],
+ "layout":{
+ "title": "Fill toself and tonext",
+ "width": 400,
+ "height": 400
+ }
+}
diff --git a/test/image/mocks/gl2d_shapes_below_traces.json b/test/image/mocks/gl2d_shapes_below_traces.json
new file mode 100644
index 00000000000..b2989a0a06b
--- /dev/null
+++ b/test/image/mocks/gl2d_shapes_below_traces.json
@@ -0,0 +1,149 @@
+{
+ "data": [
+ {
+ "type": "scattergl",
+ "y": [
+ 1,
+ 2,
+ 1,
+ 0,
+ -1,
+ 2,
+ 3,
+ 5
+ ]
+ },
+ {
+ "type": "scattergl",
+ "xaxis": "x2",
+ "y": [
+ 7.071067811865475,
+ 10,
+ 7.071067811865475,
+ 0,
+ -7.071067811865475,
+ 10,
+ 7.0710678118654755,
+ -7.071067811865475
+ ]
+ },
+ {
+ "type": "scattergl",
+ "y": [
+ 7.0710678118654755,
+ 6.123233995736766e-16,
+ 7.0710678118654755,
+ 10,
+ 7.0710678118654755,
+ 6.123233995736766e-16,
+ -7.071067811865475,
+ -7.071067811865477
+ ],
+ "yaxis": "y2"
+ },
+ {
+ "type": "scattergl",
+ "xaxis": "x2",
+ "y": [
+ 2,
+ 1.6666666666666667,
+ 2,
+ 2.5,
+ 3.3333333333333335,
+ 1.6666666666666667,
+ 1.4285714285714286,
+ 1.1111111111111112
+ ],
+ "yaxis": "y2"
+ }
+ ],
+ "layout": {
+ "dragmode": "pan",
+ "shapes": [
+ {
+ "fillcolor": "#c7eae5",
+ "layer": "below",
+ "type": "rect",
+ "x0": 3.5,
+ "x1": 4.5,
+ "xref": "x",
+ "y0": 0,
+ "y1": 1,
+ "yref": "paper"
+ },
+ {
+ "fillcolor": "#c7eae5",
+ "layer": "above",
+ "opacity": 0.5,
+ "type": "rect",
+ "x0": 5.5,
+ "x1": 6.5,
+ "xref": "x2",
+ "y0": 0,
+ "y1": 1,
+ "yref": "paper"
+ },
+ { "visible": false },
+ {
+ "fillcolor": "#f6e8c3",
+ "layer": "below",
+ "type": "rect",
+ "x0": 0,
+ "x1": 1,
+ "xref": "paper",
+ "y0": 0,
+ "y1": 3,
+ "yref": "y"
+ },
+ {
+ "fillcolor": "#f6e8c3",
+ "layer": "above",
+ "opacity": 0.5,
+ "type": "rect",
+ "x0": 0,
+ "x1": 1,
+ "xref": "paper",
+ "y0": 1,
+ "y1": 4,
+ "yref": "y2"
+ },
+ {
+ "fillcolor": "#d3d3d3",
+ "layer": "below",
+ "type": "rect",
+ "x0": 0.3,
+ "x1": 0.7,
+ "xref": "paper",
+ "y0": 0.3,
+ "y1": 0.7,
+ "yref": "paper"
+ }
+ ],
+ "showlegend": false,
+ "title": "shape shading a region",
+ "xaxis": {
+ "domain": [
+ 0,
+ 0.45
+ ]
+ },
+ "xaxis2": {
+ "domain": [
+ 0.55,
+ 1
+ ]
+ },
+ "yaxis": {
+ "domain": [
+ 0,
+ 0.45
+ ]
+ },
+ "yaxis2": {
+ "domain": [
+ 0.55,
+ 1
+ ]
+ }
+ }
+}
diff --git a/test/image/mocks/gl2d_subplots_anchor.json b/test/image/mocks/gl2d_subplots_anchor.json
new file mode 100644
index 00000000000..020b10c2d35
--- /dev/null
+++ b/test/image/mocks/gl2d_subplots_anchor.json
@@ -0,0 +1,39 @@
+{
+ "data": [
+ {
+ "x": ["2007-01-03", "2007-01-04", "2007-01-05", "2007-01-08", "2007-01-09", "2007-01-10", "2007-01-11", "2007-01-12", "2007-01-16", "2007-01-17", "2007-01-18", "2007-01-19", "2007-01-22", "2007-01-23", "2007-01-24"],
+ "y": [309579900, 211815100, 208685400, 199276700, 837324600, 738220000, 360063200, 328172600, 311019100, 411565000, 591151400, 341118400, 363506500, 301856100, 231953400],
+ "mode": "lines",
+ "name": "volume",
+ "type": "scattergl",
+ "xaxis": "x",
+ "yaxis": "y"
+ },
+ {
+ "x": ["2007-01-03", "2007-01-04", "2007-01-05", "2007-01-08", "2007-01-09", "2007-01-10", "2007-01-11", "2007-01-12", "2007-01-16", "2007-01-17", "2007-01-18", "2007-01-19", "2007-01-22", "2007-01-23", "2007-01-24"],
+ "y": [10.812461, 11.05245, 10.973744, 11.027936, 11.944027, 12.515616, 12.360785, 12.208533, 12.528519, 12.251111, 11.492433, 11.418888, 11.198251, 11.057612, 11.186639],
+ "mode": "lines",
+ "name": "adjusted",
+ "type": "scattergl",
+ "xaxis": "x",
+ "yaxis": "y2"
+ }
+ ],
+ "layout": {
+ "width": 710,
+ "height": 400,
+ "showlegend": false,
+ "xaxis": {
+ "domain": [0, 1],
+ "anchor": "y2"
+ },
+ "yaxis2": {
+ "domain": [0, 0.45],
+ "anchor": "x"
+ },
+ "yaxis": {
+ "domain": [0.55, 1],
+ "anchor": "x"
+ }
+ }
+}
diff --git a/test/image/mocks/gl2d_tick-labels.json b/test/image/mocks/gl2d_tick-labels.json
new file mode 100644
index 00000000000..201ed9c89d3
--- /dev/null
+++ b/test/image/mocks/gl2d_tick-labels.json
@@ -0,0 +1,22 @@
+{
+ "data": [
+ {
+ "x": [0, 1, 2],
+ "y": ["long long long string", "long long long string 2", "long long longstring 3"],
+ "mode": "markers",
+ "type": "scattergl"
+ }
+ ],
+ "layout": {
+ "width": 600,
+ "height": 500,
+ "xaxis": {
+ "ticklen": 2,
+ "linecolor": "#d3d3d3", "mirror": true, "zeroline": false
+ },
+ "yaxis": {
+ "ticklen": 2,
+ "linecolor": "#d3d3d3", "mirror": true, "zeroline": false
+ }
+ }
+}
diff --git a/test/image/mocks/gl2d_ultra_zoom.json b/test/image/mocks/gl2d_ultra_zoom.json
new file mode 100644
index 00000000000..ecb7f0f02dd
--- /dev/null
+++ b/test/image/mocks/gl2d_ultra_zoom.json
@@ -0,0 +1,53 @@
+{
+ "data": [
+ {
+ "x": [
+ 1.0e-2,
+ 1.0000001e-2,
+ 1.0000002e-2,
+ 1.0000003e-2,
+ 1.0000004e-2,
+ 1.0000005e-2,
+ 1.0000006e-2,
+ 1.0000007e-2,
+ 1.0000008e-2,
+ 1.0000009e-2,
+ 1.0000010e-2
+ ],
+ "y": [
+ 1.0e-2,
+ 1.0000001e-2,
+ 1.0000002e-2,
+ 1.0000003e-2,
+ 1.0000004e-2,
+ 1.0000005e-2,
+ 1.0000006e-2,
+ 1.0000007e-2,
+ 1.0000008e-2,
+ 1.0000009e-2,
+ 1.0000010e-2
+ ],
+ "mode": "markers",
+ "type": "scatter"
+ }
+ ],
+ "layout": {
+ "autosize": true,
+ "xaxis": {
+ "range": [
+ 1.0e-2,
+ 1.0000010e-2
+ ],
+ "type": "linear",
+ "autorange": false
+ },
+ "yaxis": {
+ "range": [
+ 1.0e-2,
+ 1.0000010e-2
+ ],
+ "type": "linear",
+ "autorange": false
+ }
+ }
+}
diff --git a/test/image/mocks/glpolar_scatter.json b/test/image/mocks/glpolar_scatter.json
new file mode 100644
index 00000000000..fdf8472c0f3
--- /dev/null
+++ b/test/image/mocks/glpolar_scatter.json
@@ -0,0 +1,858 @@
+{
+ "data": [
+ {
+ "type": "scatterpolargl",
+ "r": [
+ 6.80498578527,
+ 3.38959601061,
+ 5.38147211075,
+ 8.05954021942,
+ 5.31822922787,
+ 2.98509993563,
+ 1.96658700238,
+ 6.76926540821,
+ 4.07340189872,
+ 6.50437182527,
+ 7.556369819,
+ 4.04745609407,
+ 7.38666249607,
+ 5.41362473698,
+ 7.47071653116,
+ 7.98211021694,
+ 4.73781408009,
+ 4.20645304293,
+ 5.47860480459,
+ 4.8245202807,
+ 5.5996006099,
+ 6.86679521708,
+ 3.08567136626,
+ 7.77181094323,
+ 3.6877944351,
+ 5.36035668519,
+ 5.1404467393,
+ 6.04544568093,
+ 6.83392094019,
+ 3.62076946254,
+ 3.9894305834,
+ 5.3118244995,
+ 4.60821348028,
+ 6.64058471615,
+ 3.05518885448,
+ 7.49256416375,
+ 5.48507817779,
+ 3.89779499662,
+ 5.97624511403,
+ 5.44706156091,
+ 5.37703411681,
+ 4.69080578773,
+ 4.71164049118,
+ 3.62991932939,
+ 5.95766807637,
+ 5.35712128439,
+ 3.84923528282,
+ 6.25050713632,
+ 7.12224335715,
+ 3.39940423384,
+ 3.51055667227,
+ 4.10099760366,
+ 4.0963821002,
+ 6.23358307481,
+ 3.93948852677,
+ 3.9254450774,
+ 6.11813250146,
+ 3.94045034629,
+ 7.58301557326,
+ 3.51320214534
+ ],
+ "theta": [
+ -30.3529443619,
+ -25.6114598545,
+ -12.4252274527,
+ 13.9613805187,
+ -4.95093284067,
+ -25.6922741909,
+ 12.4687641616,
+ -4.91376410703,
+ -10.9673802876,
+ 30.8141940549,
+ 2.47495943114,
+ 17.9755437524,
+ 0.771130593362,
+ 6.13748848563,
+ -14.451963574,
+ 28.1845341129,
+ 12.538680066,
+ -8.98323033713,
+ 5.23128516476,
+ -64.4890025358,
+ 11.3574866818,
+ 3.45407479151,
+ 13.9243466131,
+ -25.3640020468,
+ -16.818006386,
+ -10.2600510306,
+ -13.2121341256,
+ 2.5793388653,
+ 8.71757496585,
+ -10.6754987192,
+ -2.92636601252,
+ 25.1958807548,
+ 40.5903293216,
+ -9.12143363019,
+ -24.2973623813,
+ -3.17694450569,
+ 10.8504984192,
+ -31.3320597474,
+ 4.84956746221,
+ 15.0482769541,
+ 3.29510469926,
+ -6.19709187313,
+ -8.77857413578,
+ 29.5491741194,
+ -5.13744879288,
+ 23.0268604879,
+ -6.63481657837,
+ 2.75501499186,
+ 21.7332501137,
+ -24.8169949601,
+ -7.83054706253,
+ 28.3257962102,
+ 12.3009774678,
+ -21.56315724,
+ -19.3355162838,
+ 26.1464431708,
+ -1.70607120268,
+ 16.071723695,
+ 2.05326630285,
+ -5.09791161233
+ ],
+ "mode": "markers",
+ "name": "Trial 1",
+ "marker": {
+ "color": "rgb(27,158,119)",
+ "size": 15,
+ "line": {
+ "color": "white"
+ },
+ "opacity": 0.7
+ },
+ "cliponaxis": false
+ },
+ {
+ "type": "scatterpolargl",
+ "r": [
+ 3.48804392301,
+ 2.91847857636,
+ 4.20182735997,
+ 8.22732460685,
+ 4.77669042724,
+ 3.04191230311,
+ 4.78994771908,
+ 5.66388078036,
+ 3.85826239317,
+ 8.26021288114,
+ 6.86862448643,
+ 5.74019759967,
+ 6.59497928246,
+ 5.69270377821,
+ 5.33791657446,
+ 9.28360418518,
+ 5.76459089314,
+ 4.02886455205,
+ 5.66234474837,
+ 0.422837231101,
+ 6.20126646393,
+ 6.43926538132,
+ 5.09675851306,
+ 4.63208190873,
+ 3.42184613631,
+ 4.36940470335,
+ 4.02833441941,
+ 5.80576719754,
+ 6.84818992143,
+ 3.80929551278,
+ 4.38526818383,
+ 6.98332684555,
+ 7.39627318603,
+ 5.21512500314,
+ 3.08614877924,
+ 6.33539449149,
+ 6.09041471406,
+ 2.4480560069,
+ 5.94278402031,
+ 6.37312988559,
+ 5.45420534118,
+ 4.39333761656,
+ 4.20594467998,
+ 6.15554228796,
+ 5.11908717116,
+ 6.86986083083,
+ 4.10459986058,
+ 5.95434812558,
+ 8.09233287715,
+ 2.96176970545,
+ 3.97401218758,
+ 6.37338412891,
+ 5.41540914318,
+ 3.87689091998,
+ 3.26144694742,
+ 6.1458085297,
+ 5.50245198719,
+ 5.57155329531,
+ 6.85304926109,
+ 4.14035507494
+ ],
+ "theta": [
+ 14.8066257809,
+ 79.0063403726,
+ 49.0220655413,
+ 49.699083136,
+ 54.1374910829,
+ 86.4193210205,
+ 96.9523919357,
+ 41.4634882636,
+ 67.1376916934,
+ 68.0610394397,
+ 42.6819303227,
+ 76.3986566081,
+ 42.1947934722,
+ 59.5778889746,
+ 27.5108667993,
+ 60.7534448323,
+ 68.3708327991,
+ 65.7480281495,
+ 58.5330083721,
+ -176.744106458,
+ 61.17401858,
+ 47.451508589,
+ 84.4266531858,
+ 12.4793465505,
+ 72.4808027618,
+ 50.5788317578,
+ 51.5602282402,
+ 52.4378561813,
+ 51.5868279921,
+ 73.8729447773,
+ 70.2170569279,
+ 70.7142991543,
+ 82.2343944264,
+ 38.935390447,
+ 84.7093666702,
+ 38.1658284365,
+ 61.7040536538,
+ 70.1969562924,
+ 54.4542925901,
+ 64.3348949686,
+ 58.2738931466,
+ 60.4998223904,
+ 59.155232539,
+ 83.8656184676,
+ 47.8734098973,
+ 69.2826015659,
+ 71.1899104287,
+ 51.048396463,
+ 59.4275824152,
+ 78.5987369617,
+ 75.7558645152,
+ 79.9704837232,
+ 73.8937802463,
+ 31.7334111317,
+ 68.084751177,
+ 80.4110799786,
+ 48.9242507089,
+ 76.6502557554,
+ 42.1828643629,
+ 76.0333358945
+ ],
+ "mode": "markers",
+ "name": "Trial 2",
+ "marker": {
+ "color": "rgb(217,95,2)",
+ "size": 20,
+ "line": {
+ "color": "white"
+ },
+ "opacity": 0.7
+ },
+ "cliponaxis": false
+ },
+ {
+ "type": "scatterpolargl",
+ "r": [
+ 1.85587083503,
+ 5.28696206204,
+ 3.88601339194,
+ 6.282863313,
+ 4.45341484774,
+ 5.68800805076,
+ 7.33086428261,
+ 3.82566059479,
+ 4.98960417696,
+ 7.89743146977,
+ 4.65669311302,
+ 6.66715369631,
+ 4.43100628714,
+ 5.34611325338,
+ 2.47994569588,
+ 8.11347734853,
+ 6.08131168231,
+ 4.96821689621,
+ 5.24445392063,
+ 5.42220788417,
+ 5.79277461602,
+ 4.78758059223,
+ 6.78431863718,
+ 1.10893690948,
+ 5.13891110524,
+ 4.04292965729,
+ 4.02289202968,
+ 4.82842879131,
+ 5.41737837431,
+ 5.37863521067,
+ 5.42109717546,
+ 7.12056197886,
+ 8.3493085399,
+ 3.41048558832,
+ 5.62837847088,
+ 3.91493697614,
+ 5.76394026236,
+ 4.7643741068,
+ 5.0762362679,
+ 6.1655581832,
+ 5.10557651628,
+ 4.76103637693,
+ 4.59624954094,
+ 7.50418841135,
+ 4.10703141792,
+ 6.92042229938,
+ 5.34912894956,
+ 4.79806571939,
+ 7.0232515323,
+ 5.28368096546,
+ 5.56907115243,
+ 7.38379490845,
+ 6.26923321044,
+ 2.65652964501,
+ 4.8439843388,
+ 7.24799236156,
+ 4.37295939441,
+ 6.57098108136,
+ 4.60247924389,
+ 5.67005205083
+ ],
+ "theta": [
+ 151.294255181,
+ 147.188025028,
+ 125.282157112,
+ 87.0672979717,
+ 119.627898357,
+ 147.740824147,
+ 139.564598145,
+ 101.391497102,
+ 134.56018428,
+ 104.024444705,
+ 89.3931429448,
+ 123.1940314,
+ 91.4743405152,
+ 113.332373614,
+ 96.1499255673,
+ 93.2807345226,
+ 118.215565226,
+ 132.322937378,
+ 112.941186391,
+ -179.746233138,
+ 110.303513559,
+ 97.7508361661,
+ 131.608089257,
+ 115.496919231,
+ 140.58118216,
+ 123.396662119,
+ 128.342009045,
+ 107.608810398,
+ 97.9046897875,
+ 137.128447975,
+ 130.431244912,
+ 112.227084481,
+ 118.630202246,
+ 106.05822559,
+ 146.908109706,
+ 90.2773495582,
+ 111.505282363,
+ 151.089742536,
+ 107.721394157,
+ 111.300854997,
+ 114.680277936,
+ 126.569379493,
+ 128.218952233,
+ 125.354857195,
+ 112.418068253,
+ 111.797355679,
+ 133.418052258,
+ 105.184116842,
+ 97.2310361206,
+ 146.668036804,
+ 136.239315201,
+ 121.791844193,
+ 123.911327971,
+ 129.86224497,
+ 141.34395085,
+ 123.270967749,
+ 108.458821723,
+ 124.412377056,
+ 89.0271107387,
+ 134.876701145
+ ],
+ "mode": "markers",
+ "name": "Trial 3",
+ "marker": {
+ "color": "rgb(117,112,179)",
+ "size": 12,
+ "line": {
+ "color": "white"
+ },
+ "opacity": 0.7
+ },
+ "cliponaxis": false
+ },
+ {
+ "type": "scatterpolargl",
+ "r": [
+ 5.37247092432,
+ 7.09635557204,
+ 4.8838239032,
+ 2.92013544124,
+ 4.72396304568,
+ 7.42369395093,
+ 8.0909460754,
+ 3.30684459137,
+ 6.05082848252,
+ 5.53023207444,
+ 2.47230695264,
+ 6.27567053686,
+ 2.61589617379,
+ 4.65353994458,
+ 3.33544001388,
+ 4.79588360487,
+ 5.47271134648,
+ 5.88193049095,
+ 4.57158707205,
+ 9.0398611698,
+ 4.6429075999,
+ 3.1727677358,
+ 7.04424813882,
+ 4.46633651411,
+ 6.5573302898,
+ 4.82084943725,
+ 5.13191551521,
+ 3.97001223705,
+ 3.40632381283,
+ 6.476722964,
+ 6.01921850933,
+ 5.66450153495,
+ 7.15875852255,
+ 3.60071266167,
+ 7.32412716876,
+ 2.55294615625,
+ 4.72713386039,
+ 6.97175520718,
+ 4.07657836107,
+ 4.94622340701,
+ 4.64215544904,
+ 5.36057486441,
+ 5.39171906736,
+ 7.0725243051,
+ 4.10111157028,
+ 5.48573262102,
+ 6.19253528611,
+ 3.76871139184,
+ 4.29031138976,
+ 7.06019536969,
+ 6.53969184418,
+ 6.67974440649,
+ 6.0608253587,
+ 4.78657404093,
+ 6.41668652967,
+ 6.70328133339,
+ 3.88884781048,
+ 6.30859108119,
+ 2.4370447709,
+ 6.5081863479
+ ],
+ "theta": [
+ -140.203327641,
+ -168.084245433,
+ -166.285141329,
+ 138.248866753,
+ -174.424386436,
+ -169.960482759,
+ 176.991822687,
+ -169.901416249,
+ -172.641581594,
+ 142.951668814,
+ 172.415746367,
+ 168.519359196,
+ 177.822053694,
+ 172.855190349,
+ -146.014521701,
+ 128.177293024,
+ 169.167072781,
+ -173.588573789,
+ 173.726992705,
+ -151.206104772,
+ 166.260477163,
+ 172.507566082,
+ 173.949183904,
+ -131.806840938,
+ -170.635273831,
+ -168.577085483,
+ -166.765503421,
+ 176.070487348,
+ 162.297501498,
+ -174.055746313,
+ -178.060929857,
+ 156.47126885,
+ 155.239142145,
+ -163.000526394,
+ -170.116713265,
+ -170.639272487,
+ 167.383143694,
+ -163.098817056,
+ 172.880737006,
+ 163.386007682,
+ 176.182541977,
+ -174.579680174,
+ -172.335844882,
+ 165.338025694,
+ -172.525664261,
+ 157.542877739,
+ -175.881511093,
+ 175.427643994,
+ 142.069674723,
+ -168.340734019,
+ -175.805831123,
+ 163.063745419,
+ 171.720974997,
+ -151.403904569,
+ -168.27136909,
+ 165.045327878,
+ -177.315336665,
+ 170.042412897,
+ 173.59919661,
+ -177.250656746
+ ],
+ "mode": "markers",
+ "name": "Trial 4",
+ "marker": {
+ "color": "rgb(231,41,138)",
+ "size": 22,
+ "line": {
+ "color": "white"
+ },
+ "opacity": 0.7
+ },
+ "cliponaxis": false
+ },
+ {
+ "type": "scatterpolargl",
+ "r": [
+ 7.93755787138,
+ 7.30274649152,
+ 5.92930222144,
+ 2.40717871317,
+ 5.27092188706,
+ 7.40059612754,
+ 6.81082033836,
+ 4.96775903442,
+ 6.19022937045,
+ 2.15851865795,
+ 4.00412589387,
+ 4.77661732163,
+ 4.23225045181,
+ 4.30765487269,
+ 6.20027517286,
+ 0.727513848534,
+ 4.37800680381,
+ 6.00496493944,
+ 4.34193170292,
+ 10.2379829353,
+ 3.8021588887,
+ 3.96928117014,
+ 5.75898014247,
+ 7.67417906914,
+ 6.69995353301,
+ 5.73431038813,
+ 6.0442759153,
+ 4.31294306609,
+ 3.37754528241,
+ 6.36766672727,
+ 5.73724418155,
+ 3.39635147199,
+ 4.21646748139,
+ 5.46488501672,
+ 7.31113557753,
+ 4.74540076936,
+ 3.91646853189,
+ 7.60297299033,
+ 4.12520482944,
+ 3.67679494965,
+ 4.55123578852,
+ 5.60696053152,
+ 5.79484425749,
+ 5.03052815569,
+ 5.10958624099,
+ 3.40544020796,
+ 6.02630612539,
+ 4.22110926364,
+ 1.90978293658,
+ 7.25466939392,
+ 6.26887587203,
+ 4.56258056659,
+ 4.91805796544,
+ 6.83656096253,
+ 6.78648654914,
+ 4.75101433449,
+ 4.71992634764,
+ 4.92780521518,
+ 4.05919058739,
+ 6.12833898429
+ ],
+ "theta": [
+ -101.833785776,
+ -127.478391579,
+ -112.244284997,
+ -82.3259108712,
+ -114.688855621,
+ -130.537863362,
+ -145.010264976,
+ -98.7488450072,
+ -124.441748821,
+ -152.45411927,
+ -89.2942365523,
+ -139.832451718,
+ -91.5435951844,
+ -119.442163004,
+ -92.4558385274,
+ -129.659924316,
+ -131.051235099,
+ -123.852917454,
+ -118.086739004,
+ -121.979217138,
+ -121.915029968,
+ -99.3618475777,
+ -141.467701997,
+ -93.5662631891,
+ -126.336901405,
+ -112.834944178,
+ -114.386479929,
+ -109.796072327,
+ -102.743264712,
+ -128.246728907,
+ -127.792092643,
+ -142.473629745,
+ -161.587294187,
+ -99.9406107796,
+ -130.163117326,
+ -90.2288120096,
+ -122.650491214,
+ -123.267750572,
+ -111.997308801,
+ -127.528316806,
+ -117.931295338,
+ -120.391634245,
+ -119.386871479,
+ -149.674695492,
+ -107.850517506,
+ -138.989931341,
+ -127.595470214,
+ -107.32083544,
+ -117.573807423,
+ -127.481660968,
+ -129.912033166,
+ -148.495211671,
+ -135.33164137,
+ -104.421659276,
+ -123.875440211,
+ -146.816826618,
+ -107.058485424,
+ -138.902564873,
+ -88.8968825195,
+ -130.754467356
+ ],
+ "mode": "markers",
+ "name": "Trial 5",
+ "marker": {
+ "color": "rgb(102,166,30)",
+ "size": 19,
+ "line": {
+ "color": "white"
+ },
+ "opacity": 0.7
+ },
+ "cliponaxis": false
+ },
+ {
+ "type": "scatterpolargl",
+ "r": [
+ 8.46918052789,
+ 5.82199756737,
+ 6.14091832822,
+ 5.83172428479,
+ 5.54675447186,
+ 5.6274877092,
+ 3.94832897602,
+ 6.49018461461,
+ 5.32061824515,
+ 3.24359304149,
+ 6.44408533158,
+ 3.36377810065,
+ 6.46311681051,
+ 4.73094492578,
+ 7.79657841111,
+ 4.57012782992,
+ 3.926206816,
+ 5.25434813987,
+ 4.83841110661,
+ 8.69452399898,
+ 4.39953181822,
+ 5.85648390518,
+ 3.62157703921,
+ 8.89491237311,
+ 5.49454283608,
+ 5.96898089085,
+ 6.0478995736,
+ 5.38467139672,
+ 5.3812200182,
+ 5.11157462274,
+ 4.77056110506,
+ 3.09833088263,
+ 1.66508317194,
+ 6.74025853333,
+ 5.59449492888,
+ 6.87963082567,
+ 4.38279246628,
+ 6.41084361649,
+ 5.15420431777,
+ 4.01515851866,
+ 4.93914886826,
+ 5.29829731449,
+ 5.49041717695,
+ 2.62375125938,
+ 5.95358866167,
+ 3.30147937192,
+ 4.9548890011,
+ 5.50005366961,
+ 4.45051234955,
+ 5.78662451335,
+ 4.90683442406,
+ 2.62996947345,
+ 3.76970360805,
+ 7.3967357155,
+ 5.76448190196,
+ 2.79458519588,
+ 5.78203326982,
+ 3.48535191762,
+ 6.50065359862,
+ 4.74864071013
+ ],
+ "theta": [
+ -66.5358363273,
+ -84.5144226769,
+ -63.3397416996,
+ -24.1468127442,
+ -59.7012453226,
+ -88.06537268,
+ -98.4442045353,
+ -49.1583968172,
+ -73.636223312,
+ -17.9238746786,
+ -38.4123994546,
+ -66.3403623779,
+ -40.8888387392,
+ -52.46063321,
+ -52.6104625591,
+ -7.03935105091,
+ -57.2354586922,
+ -71.642203502,
+ -52.3453961691,
+ -92.7830386735,
+ -47.187163055,
+ -41.9692084629,
+ -82.1442282499,
+ -59.4391656032,
+ -79.1948225932,
+ -62.2999085353,
+ -65.5379040394,
+ -48.9060554476,
+ -37.748311038,
+ -78.0533334583,
+ -71.8731176631,
+ -41.8910928259,
+ -53.1154554855,
+ -52.9976280973,
+ -87.0843610179,
+ -43.6119048384,
+ -48.7979984056,
+ -82.5668031571,
+ -47.9099629957,
+ -46.5704855853,
+ -54.5004832176,
+ -65.9007271268,
+ -66.8733174636,
+ -75.4808072521,
+ -54.7776938669,
+ -42.5983345914,
+ -74.5081662691,
+ -47.1102184434,
+ -22.3568731833,
+ -84.192986745,
+ -78.5052847562,
+ -65.0363717923,
+ -66.5137336813,
+ -63.5267765618,
+ -77.8090785513,
+ -68.5101797401,
+ -51.2968693109,
+ -68.3399130277,
+ -38.6317330684,
+ -77.8518485851
+ ],
+ "mode": "markers",
+ "name": "Trial 6",
+ "marker": {
+ "color": "rgb(230,171,2)",
+ "size": 10,
+ "line": {
+ "color": "white"
+ },
+ "opacity": 0.7
+ },
+ "cliponaxis": false
+ }
+ ],
+ "layout": {
+ "title": "Hobbs-Pearson Trials",
+ "font": {
+ "size": 15
+ },
+ "showlegend": false,
+ "polar": {
+ "bgcolor": "rgb(223, 223, 223)",
+ "angularaxis": {
+ "tickwidth": 2,
+ "linewidth": 3,
+ "layer": "below traces"
+ },
+ "radialaxis": {
+ "side": "counterclockwise",
+ "showline": true,
+ "linewidth": 2,
+ "tickwidth": 2,
+ "gridcolor": "white",
+ "gridwidth": 2
+ }
+ },
+ "paper_bgcolor": "rgb(223, 223, 223)",
+ "width": 450,
+ "height": 450
+ }
+}
diff --git a/test/image/mocks/glpolar_style.json b/test/image/mocks/glpolar_style.json
new file mode 100644
index 00000000000..eb111f1a7de
--- /dev/null
+++ b/test/image/mocks/glpolar_style.json
@@ -0,0 +1,74 @@
+{
+ "data": [{
+ "type": "scatterpolargl",
+ "r": [1, 2, 3],
+ "theta": [50, 100, 200],
+ "marker": {"symbol": "square"}
+ }, {
+ "type": "scatterpolargl",
+ "r": [1, 2, 3],
+ "theta": [1, 2, 3],
+ "thetaunit": "radians"
+ }, {
+ "type": "scatterpolargl",
+ "r": ["a", "b", "c", "b"],
+ "theta": ["D", "C", "B", "A"],
+ "subplot": "polar2"
+ }, {
+ "type": "scatterpolargl",
+ "r": [50, 300, 900],
+ "theta": [0, 90, 180],
+ "subplot": "polar3"
+ }, {
+ "type": "scatterpolargl",
+ "mode": "lines",
+ "r": [3, 3, 4, 3],
+ "theta": [0, 45, 90, 270],
+ "fill": "toself",
+ "subplot": "polar4"
+ }],
+ "layout": {
+ "polar": {
+ "domain": {
+ "x": [0, 0.46],
+ "y": [0.56, 1]
+ },
+ "radialaxis": {
+ "range": [1, 4]
+ },
+ "angularaxis": {
+ "thetaunit": "radians"
+ }
+ },
+ "polar2": {
+ "domain": {
+ "x": [0, 0.46],
+ "y": [0, 0.42]
+ }
+ },
+ "polar3": {
+ "domain": {
+ "x": [0.54, 1],
+ "y": [0.56, 1]
+ },
+ "radialaxis": {
+ "type": "log",
+ "tickangle": 45
+ },
+ "sector": [0, 180]
+ },
+ "polar4": {
+ "domain": {
+ "x": [0.54, 1],
+ "y": [0, 0.44]
+ },
+ "radialaxis": {
+ "visible": false,
+ "range": [0, 6]
+ }
+ },
+ "showlegend": false,
+ "width": 600,
+ "height": 500
+ }
+}
diff --git a/test/jasmine/assets/drag.js b/test/jasmine/assets/drag.js
index 72190e4fd43..35b628e0e07 100644
--- a/test/jasmine/assets/drag.js
+++ b/test/jasmine/assets/drag.js
@@ -7,18 +7,26 @@ var getNodeCoords = require('./get_node_coords');
* optionally specify an edge ('n', 'se', 'w' etc)
* to grab it by an edge or corner (otherwise the middle is used)
*/
-module.exports = function(node, dx, dy, edge, x0, y0) {
+module.exports = function(node, dx, dy, edge, x0, y0, nsteps) {
+ nsteps = nsteps || 1;
+
var coords = getNodeCoords(node, edge);
var fromX = isNumeric(x0) ? x0 : coords.x;
var fromY = isNumeric(y0) ? y0 : coords.y;
- var toX = fromX + dx;
- var toY = fromY + dy;
mouseEvent('mousemove', fromX, fromY, {element: node});
mouseEvent('mousedown', fromX, fromY, {element: node});
var promise = waitForDragCover().then(function(dragCoverNode) {
- mouseEvent('mousemove', toX, toY, {element: dragCoverNode});
+ var toX;
+ var toY;
+
+ for(var i = 1; i <= nsteps; i++) {
+ toX = fromX + i * dx / nsteps;
+ toY = fromY + i * dy / nsteps;
+ mouseEvent('mousemove', toX, toY, {element: dragCoverNode});
+ }
+
mouseEvent('mouseup', toX, toY, {element: dragCoverNode});
return waitForDragCoverRemoval();
});
diff --git a/test/jasmine/assets/read_pixel.js b/test/jasmine/assets/read_pixel.js
new file mode 100644
index 00000000000..fadc705079c
--- /dev/null
+++ b/test/jasmine/assets/read_pixel.js
@@ -0,0 +1,13 @@
+'use strict';
+
+module.exports = function(canvas, x, y) {
+ if(!canvas) return null;
+
+ var gl = canvas.getContext('webgl');
+
+ var pixels = new Uint8Array(4);
+
+ gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+
+ return pixels;
+};
diff --git a/test/jasmine/tests/gl2d_click_test.js b/test/jasmine/tests/gl2d_click_test.js
index 70609851a15..25c6abb6532 100644
--- a/test/jasmine/tests/gl2d_click_test.js
+++ b/test/jasmine/tests/gl2d_click_test.js
@@ -194,6 +194,85 @@ describe('Test hover and click interactions', function() {
}
};
_mock.data[0].hoverinfo = _mock.data[0].x.map(function(_, i) { return i % 2 ? 'y' : 'x'; });
+
+ _mock.data[0].hoverlabel = {
+ bgcolor: 'blue',
+ bordercolor: _mock.data[0].x.map(function(_, i) { return i % 2 ? 'red' : 'green'; })
+ };
+
+ var run = makeRunner([634, 321], {
+ x: 15.772,
+ y: 0.387,
+ label: ['0.387', null],
+ curveNumber: 0,
+ pointNumber: 33,
+ bgcolor: 'rgb(0, 0, 255)',
+ bordercolor: 'rgb(255, 0, 0)',
+ fontSize: 20,
+ fontFamily: 'Arial',
+ fontColor: 'rgb(255, 255, 0)'
+ }, {
+ msg: 'scattergl'
+ });
+
+ Plotly.plot(gd, _mock)
+ .then(run)
+ .catch(fail)
+ .then(done);
+ });
+
+ it('should output correct event data for scattergl in *select* dragmode', function(done) {
+ var _mock = Lib.extendDeep({}, mock1);
+
+ _mock.layout.dragmode = 'select';
+
+ _mock.layout.hoverlabel = {
+ font: {
+ size: 20,
+ color: 'yellow'
+ }
+ };
+ _mock.data[0].hoverinfo = _mock.data[0].x.map(function(_, i) { return i % 2 ? 'y' : 'x'; });
+
+ _mock.data[0].hoverlabel = {
+ bgcolor: 'blue',
+ bordercolor: _mock.data[0].x.map(function(_, i) { return i % 2 ? 'red' : 'green'; })
+ };
+
+ var run = makeRunner([634, 321], {
+ x: 15.772,
+ y: 0.387,
+ label: ['0.387', null],
+ curveNumber: 0,
+ pointNumber: 33,
+ bgcolor: 'rgb(0, 0, 255)',
+ bordercolor: 'rgb(255, 0, 0)',
+ fontSize: 20,
+ fontFamily: 'Arial',
+ fontColor: 'rgb(255, 255, 0)'
+ }, {
+ msg: 'scattergl'
+ });
+
+ Plotly.plot(gd, _mock)
+ .then(run)
+ .catch(fail)
+ .then(done);
+ });
+
+ it('should output correct event data for scattergl in *lasso* dragmode', function(done) {
+ var _mock = Lib.extendDeep({}, mock1);
+
+ _mock.layout.dragmode = 'lasso';
+
+ _mock.layout.hoverlabel = {
+ font: {
+ size: 20,
+ color: 'yellow'
+ }
+ };
+ _mock.data[0].hoverinfo = _mock.data[0].x.map(function(_, i) { return i % 2 ? 'y' : 'x'; });
+
_mock.data[0].hoverlabel = {
bgcolor: 'blue',
bordercolor: _mock.data[0].x.map(function(_, i) { return i % 2 ? 'red' : 'green'; })
@@ -464,9 +543,10 @@ describe('@noCI Test gl2d lasso/select:', function() {
});
var gd;
- var selectPath = [[93, 193], [143, 193]];
+ var selectPath = [[98, 193], [108, 193]];
+ var selectPath2 = [[118, 193], [128, 193]];
var lassoPath = [[316, 171], [318, 239], [335, 243], [328, 169]];
- var lassoPath2 = [[93, 193], [143, 193], [143, 500], [93, 500], [93, 193]];
+ var lassoPath2 = [[98, 193], [108, 193], [108, 500], [98, 500], [98, 193]];
afterEach(function() {
Plotly.purge(gd);
@@ -508,9 +588,6 @@ describe('@noCI Test gl2d lasso/select:', function() {
});
}
- function countGlObjects() {
- return gd._fullLayout._plots.xy._scene2d.glplot.objects.length;
- }
it('should work under fast mode with *select* dragmode', function(done) {
var _mock = Lib.extendDeep({}, mockFast);
@@ -520,19 +597,20 @@ describe('@noCI Test gl2d lasso/select:', function() {
Plotly.plot(gd, _mock)
.then(delay(100))
.then(function() {
- expect(countGlObjects()).toBe(1, 'has on gl-scatter2d object');
+ expect(gd._fullLayout._plots.xy._scene.select2d).not.toBe(undefined, 'scatter2d renderer');
return select(selectPath);
})
+ .then(delay(100))
.then(function(eventData) {
assertEventData(eventData, {
points: [
- {x: 3.911, y: 0.401},
- {x: 5.34, y: 0.403},
- {x: 6.915, y: 0.411}
+ {pointNumber: 25, x: 1.425, y: 0.538},
+ {pointNumber: 26, x: 1.753, y: 0.5},
+ {pointNumber: 27, x: 2.22, y: 0.45}
]
});
- expect(countGlObjects()).toBe(2, 'adds a dimmed gl-scatter2d objects');
+
})
.catch(fail)
.then(done);
@@ -546,19 +624,17 @@ describe('@noCI Test gl2d lasso/select:', function() {
Plotly.plot(gd, _mock)
.then(delay(100))
.then(function() {
- expect(countGlObjects()).toBe(1);
-
return select(lassoPath2);
})
+ .then(delay(100))
.then(function(eventData) {
assertEventData(eventData, {
points: [
- {x: 3.911, y: 0.401},
- {x: 5.34, y: 0.403},
- {x: 6.915, y: 0.411}
+ {pointNumber: 25, x: 1.425, y: 0.538},
+ {pointNumber: 26, x: 1.753, y: 0.5},
+ {pointNumber: 27, x: 2.22, y: 0.45}
]
});
- expect(countGlObjects()).toBe(2);
})
.catch(fail)
.then(done);
@@ -572,15 +648,13 @@ describe('@noCI Test gl2d lasso/select:', function() {
Plotly.plot(gd, _mock)
.then(delay(100))
.then(function() {
- expect(countGlObjects()).toBe(2, 'has a gl-line2d and a gl-scatter2d-sdf');
-
- return select(selectPath);
+ return select(selectPath2);
})
+ .then(delay(100))
.then(function(eventData) {
assertEventData(eventData, {
points: [{x: 0.004, y: 12.5}]
});
- expect(countGlObjects()).toBe(2, 'only changes colors of gl-scatter2d-sdf object');
})
.catch(fail)
.then(done);
@@ -594,15 +668,12 @@ describe('@noCI Test gl2d lasso/select:', function() {
Plotly.plot(gd, _mock)
.then(delay(100))
.then(function() {
- expect(countGlObjects()).toBe(2, 'has a gl-line2d and a gl-scatter2d-sdf');
-
return select(lassoPath);
})
.then(function(eventData) {
assertEventData(eventData, {
points: [{ x: 0.099, y: 2.75 }]
});
- expect(countGlObjects()).toBe(2, 'only changes colors of gl-scatter2d-sdf object');
})
.catch(fail)
.then(done);
diff --git a/test/jasmine/tests/gl2d_date_axis_render_test.js b/test/jasmine/tests/gl2d_date_axis_render_test.js
index 7a7f5d8a173..d3eff9200e3 100644
--- a/test/jasmine/tests/gl2d_date_axis_render_test.js
+++ b/test/jasmine/tests/gl2d_date_axis_render_test.js
@@ -31,12 +31,13 @@ describe('date axis', function() {
expect(gd._fullLayout.xaxis.type).toBe('date');
expect(gd._fullLayout.yaxis.type).toBe('linear');
expect(gd._fullData[0].type).toBe('scattergl');
- expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d');
+ expect(gd._fullData[0]._module.basePlotModule.name).toBe('cartesian');
- // one way of check which renderer - fancy vs not - we're using
- var objs = gd._fullLayout._plots.xy._scene2d.glplot.objects;
- expect(objs.length).toEqual(2);
- expect(objs[1].points.length).toEqual(4);
+ // one way of check which renderer - fancy vs not - we're
+ var scene = gd._fullLayout._plots.xy._scene;
+ expect(scene.scatter2d).toBeDefined();
+ expect(scene.markerOptions[0].positions.length).toEqual(4);
+ expect(scene.line2d).not.toBeUndefined();
});
it('should use the fancy gl-vis/gl-scatter2d once again', function() {
@@ -57,18 +58,18 @@ describe('date axis', function() {
expect(gd._fullLayout.xaxis.type).toBe('date');
expect(gd._fullLayout.yaxis.type).toBe('linear');
expect(gd._fullData[0].type).toBe('scattergl');
- expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d');
+ expect(gd._fullData[0]._module.basePlotModule.name).toBe('cartesian');
- // one way of check which renderer - fancy vs not - we're using
- var objs = gd._fullLayout._plots.xy._scene2d.glplot.objects;
- expect(objs.length).toEqual(2);
- expect(objs[1].points.length).toEqual(4);
+ var scene = gd._fullLayout._plots.xy._scene;
+ expect(scene.scatter2d).toBeDefined();
+ expect(scene.markerOptions[0].positions.length).toEqual(4);
+ expect(scene.line2d).toBeDefined();
});
it('should now use the non-fancy gl-vis/gl-scatter2d', function() {
Plotly.plot(gd, [{
type: 'scattergl',
- mode: 'markers', // important, as otherwise lines are assumed (which needs fancy)
+ mode: 'markers',
x: [new Date('2016-10-10'), new Date('2016-10-11')],
y: [15, 16]
}]);
@@ -76,17 +77,18 @@ describe('date axis', function() {
expect(gd._fullLayout.xaxis.type).toBe('date');
expect(gd._fullLayout.yaxis.type).toBe('linear');
expect(gd._fullData[0].type).toBe('scattergl');
- expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d');
+ expect(gd._fullData[0]._module.basePlotModule.name).toBe('cartesian');
- var objs = gd._fullLayout._plots.xy._scene2d.glplot.objects;
- expect(objs.length).toEqual(1);
- expect(objs[0].pointCount).toEqual(2);
+ var scene = gd._fullLayout._plots.xy._scene;
+ expect(scene.scatter2d).toBeDefined();
+ expect(scene.markerOptions[0].positions.length).toEqual(4);
+ expect(scene.line2d).toBeDefined();
});
it('should use the non-fancy gl-vis/gl-scatter2d with string dates', function() {
Plotly.plot(gd, [{
type: 'scattergl',
- mode: 'markers', // important, as otherwise lines are assumed (which needs fancy)
+ mode: 'markers',
x: ['2016-10-10', '2016-10-11'],
y: [15, 16]
}]);
@@ -94,10 +96,11 @@ describe('date axis', function() {
expect(gd._fullLayout.xaxis.type).toBe('date');
expect(gd._fullLayout.yaxis.type).toBe('linear');
expect(gd._fullData[0].type).toBe('scattergl');
- expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d');
+ expect(gd._fullData[0]._module.basePlotModule.name).toBe('cartesian');
- var objs = gd._fullLayout._plots.xy._scene2d.glplot.objects;
- expect(objs.length).toEqual(1);
- expect(objs[0].pointCount).toEqual(2);
+ var scene = gd._fullLayout._plots.xy._scene;
+ expect(scene.scatter2d).toBeDefined();
+ expect(scene.markerOptions[0].positions.length).toEqual(4);
+ expect(scene.line2d).toBeDefined();
});
});
diff --git a/test/jasmine/tests/gl_plot_interact_test.js b/test/jasmine/tests/gl_plot_interact_test.js
index 69b0f93a62b..099200dd0e9 100644
--- a/test/jasmine/tests/gl_plot_interact_test.js
+++ b/test/jasmine/tests/gl_plot_interact_test.js
@@ -9,8 +9,10 @@ var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var fail = require('../assets/fail_test');
var mouseEvent = require('../assets/mouse_event');
+var drag = require('../assets/drag');
var selectButton = require('../assets/modebar_button');
var delay = require('../assets/delay');
+var readPixel = require('../assets/read_pixel');
var customAssertions = require('../assets/custom_assertions');
var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;
@@ -832,11 +834,9 @@ describe('Test gl3d relayout calls', function() {
});
});
-describe('Test gl2d plots', function() {
+describe('Test gl3d annotations', function() {
var gd;
- var mock = require('@mocks/gl2d_10.json');
-
beforeEach(function() {
gd = createGraphDiv();
});
@@ -846,274 +846,369 @@ describe('Test gl2d plots', function() {
destroyGraphDiv();
});
- function mouseTo(p0, p1) {
- mouseEvent('mousemove', p0[0], p0[1]);
- mouseEvent('mousedown', p0[0], p0[1], { buttons: 1 });
- mouseEvent('mousemove', p1[0], p1[1], { buttons: 1 });
- mouseEvent('mouseup', p1[0], p1[1]);
- }
-
- it('should respond to drag interactions', function(done) {
- var _mock = Lib.extendDeep({}, mock);
- var relayoutCallback = jasmine.createSpy('relayoutCallback');
+ function assertAnnotationText(expectations, msg) {
+ var anns = d3.selectAll('g.annotation-text-g');
- var originalX = [-0.3037383177570093, 5.303738317757009];
- var originalY = [-0.5532219548705213, 6.191112269783224];
- var newX = [-0.5373831775700935, 5.070093457943925];
- var newY = [-1.7575673521301187, 4.986766872523626];
- var precision = 5;
+ expect(anns.size()).toBe(expectations.length, msg);
- Plotly.plot(gd, _mock)
- .then(delay(20))
- .then(function() {
- expect(gd.layout.xaxis.autorange).toBe(true);
- expect(gd.layout.yaxis.autorange).toBe(true);
- expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
- expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
+ anns.each(function(_, i) {
+ var tx = d3.select(this).select('text').text();
+ expect(tx).toEqual(expectations[i], msg + ' - ann ' + i);
+ });
+ }
- // Switch to pan mode
- var buttonPan = selectButton(gd._fullLayout._modeBar, 'pan2d');
- expect(buttonPan.isActive()).toBe(false, 'initially, zoom is active');
- buttonPan.click();
- expect(buttonPan.isActive()).toBe(true, 'switched on dragmode');
+ function assertAnnotationsXY(expectations, msg) {
+ var TOL = 2.5;
+ var anns = d3.selectAll('g.annotation-text-g');
- // Switching mode must not change visible range
- expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
- expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
- })
- .then(delay(200))
- .then(function() {
- gd.on('plotly_relayout', relayoutCallback);
+ expect(anns.size()).toBe(expectations.length, msg);
- // Drag scene along the X axis
- mouseTo([200, 200], [220, 200]);
+ anns.each(function(_, i) {
+ var ann = d3.select(this).select('g');
+ var translate = Drawing.getTranslate(ann);
- expect(gd.layout.xaxis.autorange).toBe(false);
- expect(gd.layout.yaxis.autorange).toBe(false);
+ expect(translate.x).toBeWithin(expectations[i][0], TOL, msg + ' - ann ' + i + ' x');
+ expect(translate.y).toBeWithin(expectations[i][1], TOL, msg + ' - ann ' + i + ' y');
+ });
+ }
- expect(gd.layout.xaxis.range).toBeCloseToArray(newX, precision);
- expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
+ // more robust (especially on CI) than update camera via mouse events
+ function updateCamera(x, y, z) {
+ var scene = gd._fullLayout.scene._scene;
+ var camera = scene.getCamera();
- // Drag scene back along the X axis
- mouseTo([220, 200], [200, 200]);
+ camera.eye = {x: x, y: y, z: z};
+ scene.setCamera(camera);
+ // need a fairly long delay to let the camera update here
+ // 200 was not robust for me (AJ), 300 seems to be.
+ return delay(300)();
+ }
- expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
- expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
+ it('should move with camera', function(done) {
+ Plotly.plot(gd, [{
+ type: 'scatter3d',
+ x: [1, 2, 3],
+ y: [1, 2, 3],
+ z: [1, 2, 1]
+ }], {
+ scene: {
+ camera: {eye: {x: 2.1, y: 0.1, z: 0.9}},
+ annotations: [{
+ text: 'hello',
+ x: 1, y: 1, z: 1
+ }, {
+ text: 'sup?',
+ x: 1, y: 1, z: 2
+ }, {
+ text: 'look!',
+ x: 2, y: 2, z: 1
+ }]
+ }
+ })
+ .then(function() {
+ assertAnnotationsXY([[262, 199], [257, 135], [325, 233]], 'base 0');
- // Drag scene along the Y axis
- mouseTo([200, 200], [200, 150]);
+ return updateCamera(1.5, 2.5, 1.5);
+ })
+ .then(function() {
+ assertAnnotationsXY([[340, 187], [341, 142], [325, 221]], 'after camera update');
- expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
- expect(gd.layout.yaxis.range).toBeCloseToArray(newY, precision);
+ return updateCamera(2.1, 0.1, 0.9);
+ })
+ .then(function() {
+ assertAnnotationsXY([[262, 199], [257, 135], [325, 233]], 'base 0');
+ })
+ .catch(fail)
+ .then(done);
+ });
- // Drag scene back along the Y axis
- mouseTo([200, 150], [200, 200]);
+ it('should be removed when beyond the scene axis ranges', function(done) {
+ var mock = Lib.extendDeep({}, require('@mocks/gl3d_annotations'));
- expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
- expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
+ // replace text with something easier to identify
+ mock.layout.scene.annotations.forEach(function(ann, i) { ann.text = String(i); });
- // Drag scene along both the X and Y axis
- mouseTo([200, 200], [220, 150]);
+ Plotly.plot(gd, mock).then(function() {
+ assertAnnotationText(['0', '1', '2', '3', '4', '5', '6'], 'base');
- expect(gd.layout.xaxis.range).toBeCloseToArray(newX, precision);
- expect(gd.layout.yaxis.range).toBeCloseToArray(newY, precision);
+ return Plotly.relayout(gd, 'scene.yaxis.range', [0.5, 1.5]);
+ })
+ .then(function() {
+ assertAnnotationText(['1', '4', '5', '6'], 'after yaxis range relayout');
- // Drag scene back along the X and Y axis
- mouseTo([220, 150], [200, 200]);
+ return Plotly.relayout(gd, 'scene.yaxis.range', null);
+ })
+ .then(function() {
+ assertAnnotationText(['0', '1', '2', '3', '4', '5', '6'], 'back to base after yaxis range relayout');
- expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
- expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
+ return Plotly.relayout(gd, 'scene.zaxis.range', [0, 3]);
})
- .then(delay(200))
.then(function() {
- // callback count expectation: X and back; Y and back; XY and back
- expect(relayoutCallback).toHaveBeenCalledTimes(6);
+ assertAnnotationText(['0', '4', '5', '6'], 'after zaxis range relayout');
- // a callback value structure and contents check
- expect(relayoutCallback).toHaveBeenCalledWith(jasmine.objectContaining({
- lastInputTime: jasmine.any(Number),
- xaxis: [jasmine.any(Number), jasmine.any(Number)],
- yaxis: [jasmine.any(Number), jasmine.any(Number)]
- }));
+ return Plotly.relayout(gd, 'scene.zaxis.range', null);
+ })
+ .then(function() {
+ assertAnnotationText(['0', '1', '2', '3', '4', '5', '6'], 'back to base after zaxis range relayout');
})
+ .catch(fail)
.then(done);
});
- it('should be able to toggle visibility', function(done) {
- var _mock = Lib.extendDeep({}, mock);
+ it('should be able to add/remove and hide/unhide themselves via relayout', function(done) {
+ var mock = Lib.extendDeep({}, require('@mocks/gl3d_annotations'));
- // a line object + scatter fancy
- var OBJECT_PER_TRACE = 2;
+ // replace text with something easier to identify
+ mock.layout.scene.annotations.forEach(function(ann, i) { ann.text = String(i); });
- var objects = function() {
- try {
- return gd._fullLayout._plots.xy._scene2d.glplot.objects;
- }
- catch(e) {
- return [];
- }
+ var annNew = {
+ x: '2017-03-01',
+ y: 'C',
+ z: 3,
+ text: 'new!'
};
- Plotly.plot(gd, _mock)
- .then(delay(20))
- .then(function() {
- expect(objects().length).toEqual(OBJECT_PER_TRACE);
+ Plotly.plot(gd, mock).then(function() {
+ assertAnnotationText(['0', '1', '2', '3', '4', '5', '6'], 'base');
- return Plotly.restyle(gd, 'visible', 'legendonly');
+ return Plotly.relayout(gd, 'scene.annotations[1].visible', false);
})
.then(function() {
- expect(objects().length).toEqual(OBJECT_PER_TRACE);
- expect(objects()[0].data.length).toEqual(0);
+ assertAnnotationText(['0', '2', '3', '4', '5', '6'], 'after [1].visible:false');
- return Plotly.restyle(gd, 'visible', true);
+ return Plotly.relayout(gd, 'scene.annotations[1].visible', true);
})
.then(function() {
- expect(objects().length).toEqual(OBJECT_PER_TRACE);
- expect(objects()[0].data.length).not.toEqual(0);
+ assertAnnotationText(['0', '1', '2', '3', '4', '5', '6'], 'back to base (1)');
- return Plotly.restyle(gd, 'visible', false);
+ return Plotly.relayout(gd, 'scene.annotations[0]', null);
})
.then(function() {
- expect(objects().length).toBe(0);
+ assertAnnotationText(['1', '2', '3', '4', '5', '6'], 'after [0] null');
- return Plotly.restyle(gd, 'visible', true);
+ return Plotly.relayout(gd, 'scene.annotations[0]', annNew);
})
.then(function() {
- expect(objects().length).toEqual(OBJECT_PER_TRACE);
- expect(objects()[0].data.length).not.toEqual(0);
- })
- .catch(fail)
- .then(done);
- });
+ assertAnnotationText(['new!', '1', '2', '3', '4', '5', '6'], 'after add new (1)');
- it('should clear orphan cartesian subplots on addTraces', function(done) {
- Plotly.newPlot(gd, [], {
- xaxis: { title: 'X' },
- yaxis: { title: 'Y' }
+ return Plotly.relayout(gd, 'scene.annotations', null);
})
.then(function() {
- return Plotly.addTraces(gd, [{
- type: 'scattergl',
- x: [1, 2, 3, 4, 5, 6, 7],
- y: [0, 5, 8, 9, 8, 5, 0]
- }]);
+ assertAnnotationText([], 'after rm all');
+
+ return Plotly.relayout(gd, 'scene.annotations[0]', annNew);
})
.then(function() {
- expect(d3.select('.xtitle').size()).toEqual(0);
- expect(d3.select('.ytitle').size()).toEqual(0);
+ assertAnnotationText(['new!'], 'after add new (2)');
})
+ .catch(fail)
.then(done);
});
- it('supports 1D and 2D Zoom', function(done) {
- var centerX, centerY;
- Plotly.newPlot(gd,
- [{type: 'scattergl', x: [1, 15], y: [1, 15]}],
- {
- width: 400,
- height: 400,
- margin: {t: 100, b: 100, l: 100, r: 100},
- xaxis: {range: [0, 16]},
- yaxis: {range: [0, 16]}
+ it('should work across multiple scenes', function(done) {
+ function assertAnnotationCntPerScene(id, cnt) {
+ expect(d3.selectAll('g.annotation-' + id).size()).toEqual(cnt);
+ }
+
+ Plotly.plot(gd, [{
+ type: 'scatter3d',
+ x: [1, 2, 3],
+ y: [1, 2, 3],
+ z: [1, 2, 1]
+ }, {
+ type: 'scatter3d',
+ x: [1, 2, 3],
+ y: [1, 2, 3],
+ z: [2, 1, 2],
+ scene: 'scene2'
+ }], {
+ scene: {
+ annotations: [{
+ text: 'hello',
+ x: 1, y: 1, z: 1
+ }]
+ },
+ scene2: {
+ annotations: [{
+ text: 'sup?',
+ x: 1, y: 1, z: 2
+ }, {
+ text: 'look!',
+ x: 2, y: 2, z: 1
+ }]
}
- )
+ })
.then(function() {
- var bBox = gd.getBoundingClientRect();
- centerX = bBox.left + 200;
- centerY = bBox.top + 200;
-
- // 2D
- mouseTo([centerX - 50, centerY], [centerX + 50, centerY + 50]);
- expect(gd.layout.xaxis.range).toBeCloseToArray([4, 12], 3);
- expect(gd.layout.yaxis.range).toBeCloseToArray([4, 8], 3);
-
- // x only
- mouseTo([centerX - 50, centerY], [centerX, centerY + 5]);
- expect(gd.layout.xaxis.range).toBeCloseToArray([6, 8], 3);
- expect(gd.layout.yaxis.range).toBeCloseToArray([4, 8], 3);
+ assertAnnotationCntPerScene('scene', 1);
+ assertAnnotationCntPerScene('scene2', 2);
- // y only
- mouseTo([centerX, centerY - 50], [centerX - 5, centerY + 50]);
- expect(gd.layout.xaxis.range).toBeCloseToArray([6, 8], 3);
- expect(gd.layout.yaxis.range).toBeCloseToArray([5, 7], 3);
+ return Plotly.deleteTraces(gd, [1]);
+ })
+ .then(function() {
+ assertAnnotationCntPerScene('scene', 1);
+ assertAnnotationCntPerScene('scene2', 2);
- // no change - too small
- mouseTo([centerX, centerY], [centerX - 5, centerY + 5]);
- expect(gd.layout.xaxis.range).toBeCloseToArray([6, 8], 3);
- expect(gd.layout.yaxis.range).toBeCloseToArray([5, 7], 3);
+ return Plotly.deleteTraces(gd, [0]);
+ })
+ .then(function() {
+ assertAnnotationCntPerScene('scene', 1);
+ assertAnnotationCntPerScene('scene2', 2);
})
.catch(fail)
.then(done);
});
- it('supports axis constraints with zoom', function(done) {
- var centerX, centerY;
- Plotly.newPlot(gd,
- [{type: 'scattergl', x: [1, 15], y: [1, 15]}],
- {
- width: 400,
- height: 400,
- margin: {t: 100, b: 100, l: 100, r: 100},
- xaxis: {range: [0, 16]},
- yaxis: {range: [0, 16]}
- }
- )
- .then(function() {
- var bBox = gd.getBoundingClientRect();
- centerX = bBox.left + 200;
- centerY = bBox.top + 200;
+ it('should contribute to scene axis autorange', function(done) {
+ function assertSceneAxisRanges(xRange, yRange, zRange) {
+ var sceneLayout = gd._fullLayout.scene;
- return Plotly.relayout(gd, {
- 'yaxis.scaleanchor': 'x',
- 'yaxis.scaleratio': 2
- });
+ expect(sceneLayout.xaxis.range).toBeCloseToArray(xRange, 1, 'xaxis range');
+ expect(sceneLayout.yaxis.range).toBeCloseToArray(yRange, 1, 'yaxis range');
+ expect(sceneLayout.zaxis.range).toBeCloseToArray(zRange, 1, 'zaxis range');
+ }
+
+ Plotly.plot(gd, [{
+ type: 'scatter3d',
+ x: [1, 2, 3],
+ y: [1, 2, 3],
+ z: [1, 2, 1]
+ }], {
+ scene: {
+ annotations: [{
+ text: 'hello',
+ x: 1, y: 1, z: 3
+ }]
+ }
})
.then(function() {
- // x range is adjusted to fit constraint
- expect(gd.layout.xaxis.range).toBeCloseToArray([-8, 24], 3);
- expect(gd.layout.yaxis.range).toBeCloseToArray([0, 16], 3);
+ assertSceneAxisRanges([0.9375, 3.0625], [0.9375, 3.0625], [0.9375, 3.0625]);
- // now there should only be 2D zooming
- // dy>>dx
- mouseTo([centerX, centerY], [centerX - 1, centerY - 50]);
- expect(gd.layout.xaxis.range).toBeCloseToArray([0, 8], 3);
- expect(gd.layout.yaxis.range).toBeCloseToArray([8, 12], 3);
+ return Plotly.relayout(gd, 'scene.annotations[0].z', 10);
+ })
+ .then(function() {
+ assertSceneAxisRanges([0.9375, 3.0625], [0.9375, 3.0625], [0.7187, 10.2813]);
+ })
+ .catch(fail)
+ .then(done);
+ });
- // dx>>dy
- mouseTo([centerX, centerY], [centerX + 50, centerY + 1]);
- expect(gd.layout.xaxis.range).toBeCloseToArray([4, 6], 3);
- expect(gd.layout.yaxis.range).toBeCloseToArray([9, 10], 3);
+ it('should allow text and tail position edits under `editable: true`', function(done) {
+ function editText(newText, expectation) {
+ return new Promise(function(resolve) {
+ gd.once('plotly_relayout', function(eventData) {
+ expect(eventData).toEqual(expectation);
+ setTimeout(resolve, 0);
+ });
- // no change - too small
- mouseTo([centerX, centerY], [centerX - 5, centerY + 5]);
- expect(gd.layout.xaxis.range).toBeCloseToArray([4, 6], 3);
- expect(gd.layout.yaxis.range).toBeCloseToArray([9, 10], 3);
+ var clickNode = d3.select('g.annotation-text-g').select('g').node();
+ clickNode.dispatchEvent(new window.MouseEvent('click'));
- return Plotly.relayout(gd, {
- 'xaxis.autorange': true,
- 'yaxis.autorange': true
+ var editNode = d3.select('.plugin-editable.editable').node();
+ editNode.dispatchEvent(new window.FocusEvent('focus'));
+
+ editNode.textContent = newText;
+ editNode.dispatchEvent(new window.FocusEvent('focus'));
+ editNode.dispatchEvent(new window.FocusEvent('blur'));
+ });
+ }
+
+ function moveArrowTail(dx, dy, expectation) {
+ var px = 243;
+ var py = 150;
+
+ return new Promise(function(resolve) {
+ gd.once('plotly_relayout', function(eventData) {
+ expect(eventData).toEqual(expectation);
+ resolve();
+ });
+
+ mouseEvent('mousemove', px, py);
+ mouseEvent('mousedown', px, py);
+ mouseEvent('mousemove', px + dx, py + dy);
+ mouseEvent('mouseup', px + dx, py + dy);
});
+ }
+
+ Plotly.plot(gd, [{
+ type: 'scatter3d',
+ x: [1, 2, 3],
+ y: [1, 2, 3],
+ z: [1, 2, 1]
+ }], {
+ scene: {
+ annotations: [{
+ text: 'hello',
+ x: 2, y: 2, z: 2,
+ font: { size: 30 }
+ }]
+ },
+ margin: {l: 0, t: 0, r: 0, b: 0},
+ width: 500,
+ height: 500
+ }, {
+ editable: true
+ })
+ .then(function() {
+ return editText('allo', {'scene.annotations[0].text': 'allo'});
})
.then(function() {
- expect(gd.layout.xaxis.range).toBeCloseToArray([-8.09195, 24.09195], 3);
- expect(gd.layout.yaxis.range).toBeCloseToArray([-0.04598, 16.04598], 3);
+ return moveArrowTail(-100, -50, {
+ 'scene.annotations[0].ax': -110,
+ 'scene.annotations[0].ay': -80
+ });
})
.catch(fail)
.then(done);
});
- it('should change plot type with incomplete data', function(done) {
- Plotly.plot(gd, [{}]);
+ it('should display hover labels and trigger *plotly_clickannotation* event', function(done) {
+ function dispatch(eventType) {
+ var target = d3.select('g.annotation-text-g').select('g').node();
+ target.dispatchEvent(new MouseEvent(eventType));
+ }
- expect(function() {
- Plotly.restyle(gd, {type: 'scattergl', x: [[1]]}, 0);
- }).not.toThrow();
+ Plotly.plot(gd, [{
+ type: 'scatter3d',
+ x: [1, 2, 3],
+ y: [1, 2, 3],
+ z: [1, 2, 1]
+ }], {
+ scene: {
+ annotations: [{
+ text: 'hello',
+ x: 2, y: 2, z: 2,
+ ax: 0, ay: -100,
+ hovertext: 'HELLO',
+ hoverlabel: {
+ bgcolor: 'red',
+ font: { size: 20 }
+ }
+ }]
+ },
+ width: 500,
+ height: 500
+ })
+ .then(function() {
+ dispatch('mouseover');
+ expect(d3.select('.hovertext').size()).toEqual(1);
+ })
+ .then(function() {
+ return new Promise(function(resolve, reject) {
+ gd.once('plotly_clickannotation', function(eventData) {
+ expect(eventData.index).toEqual(0);
+ expect(eventData.subplotId).toEqual('scene');
+ resolve();
+ });
- expect(function() {
- Plotly.restyle(gd, {y: [[1]]}, 0);
- }).not.toThrow();
+ setTimeout(function() {
+ reject('plotly_clickannotation did not get called!');
+ }, 100);
- done();
+ dispatch('click');
+ });
+ })
+ .catch(fail)
+ .then(done);
});
});
@@ -1149,10 +1244,10 @@ describe('Test removal of gl contexts', function() {
y: [2, 1, 3]
}])
.then(function() {
- expect(gd._fullLayout._plots.xy._scene2d.glplot).toBeDefined();
-
+ expect(gd._fullLayout._plots.xy._scene).toBeDefined();
Plots.cleanPlot([], {}, gd._fullData, gd._fullLayout);
- expect(gd._fullLayout._plots).toEqual({});
+
+ expect(gd._fullLayout._plots.xy._scene).toBeUndefined();
})
.then(done);
});
@@ -1210,8 +1305,8 @@ describe('Test removal of gl contexts', function() {
y: [2, 1, 3]
}])
.then(function() {
- firstGlplotObject = gd._fullLayout._plots.xy._scene2d.glplot;
- firstGlContext = firstGlplotObject.gl;
+ firstGlplotObject = gd._fullLayout._plots.xy._scene;
+ firstGlContext = firstGlplotObject.scatter2d.gl;
firstCanvas = firstGlContext.canvas;
expect(firstGlplotObject).toBeDefined();
@@ -1225,8 +1320,8 @@ describe('Test removal of gl contexts', function() {
}], {});
})
.then(function() {
- var secondGlplotObject = gd._fullLayout._plots.xy._scene2d.glplot;
- var secondGlContext = secondGlplotObject.gl;
+ var secondGlplotObject = gd._fullLayout._plots.xy._scene;
+ var secondGlContext = secondGlplotObject.scatter2d.gl;
var secondCanvas = secondGlContext.canvas;
expect(Object.keys(gd._fullLayout._plots).length === 1);
@@ -1291,27 +1386,33 @@ describe('Test gl plot side effects', function() {
y: [2, 1, 2]
}];
- Plotly.plot(gd, []).then(function() {
+ Plotly.plot(gd, [])
+ .then(function() {
countCanvases(0);
return Plotly.plot(gd, data);
- }).then(function() {
+ })
+ .then(function() {
countCanvases(3);
return Plotly.purge(gd);
- }).then(function() {
+ })
+ .then(function() {
countCanvases(0);
return Plotly.plot(gd, data);
- }).then(function() {
+ })
+ .then(function() {
countCanvases(3);
return Plotly.deleteTraces(gd, [0]);
- }).then(function() {
+ })
+ .then(function() {
countCanvases(0);
return Plotly.purge(gd);
- }).then(done);
+ })
+ .then(done);
});
it('should be able to switch trace type', function(done) {
@@ -1339,10 +1440,13 @@ describe('Test gl plot side effects', function() {
});
});
-describe('Test gl2d interactions', function() {
+describe('Test gl2d plots', function() {
var gd;
+ var mock = require('@mocks/gl2d_10.json');
+
beforeEach(function() {
+ jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
gd = createGraphDiv();
});
@@ -1351,425 +1455,339 @@ describe('Test gl2d interactions', function() {
destroyGraphDiv();
});
- it('data-referenced annotations should update on drag', function(done) {
- function drag(start, end) {
- mouseEvent('mousemove', start[0], start[1]);
- mouseEvent('mousedown', start[0], start[1], { buttons: 1 });
- mouseEvent('mousemove', end[0], end[1], { buttons: 1 });
- mouseEvent('mouseup', end[0], end[1]);
- }
+ function mouseTo(p0, p1) {
+ var node = d3.select('.nsewdrag[data-subplot="xy"]').node();
+ var dx = p1[0] - p0[0];
+ var dy = p1[1] - p0[1];
+ return drag(node, dx, dy, null, p0[0], p0[1]);
+ }
- function assertAnnotation(xy) {
- var ann = d3.select('g.annotation-text-g').select('g');
- var translate = Drawing.getTranslate(ann);
+ it('should respond to drag interactions', function(done) {
+ var _mock = Lib.extendDeep({}, mock);
- expect(translate.x).toBeWithin(xy[0], 1.5);
- expect(translate.y).toBeWithin(xy[1], 1.5);
- }
+ var relayoutCallback = jasmine.createSpy('relayoutCallback');
- Plotly.plot(gd, [{
- type: 'scattergl',
- x: [1, 2, 3],
- y: [2, 1, 2]
- }], {
- annotations: [{
- x: 2,
- y: 1,
- text: 'text'
- }],
- dragmode: 'pan'
- })
+ var originalX = [-0.3037383177570093, 5.303738317757009];
+ var originalY = [-0.5, 6.1];
+ var newX = [-0.5, 5];
+ var newY = [-1.7, 4.95];
+ var precision = 1;
+
+ Plotly.newPlot(gd, _mock)
+ .then(delay(20))
.then(function() {
- assertAnnotation([327, 315]);
+ expect(gd.layout.xaxis.autorange).toBe(true);
+ expect(gd.layout.yaxis.autorange).toBe(true);
+ expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
+ expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
- drag([250, 200], [200, 150]);
- assertAnnotation([277, 265]);
+ // Switch to pan mode
+ var buttonPan = selectButton(gd._fullLayout._modeBar, 'pan2d');
+ expect(buttonPan.isActive()).toBe(false, 'initially, zoom is active');
+ buttonPan.click();
+ expect(buttonPan.isActive()).toBe(true, 'switched on dragmode');
- return Plotly.relayout(gd, {
- 'xaxis.range': [1.5, 2.5],
- 'yaxis.range': [1, 1.5]
- });
+ // Switching mode must not change visible range
+ expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
+ expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
})
+ .then(delay(200))
.then(function() {
- assertAnnotation([327, 331]);
+ gd.on('plotly_relayout', relayoutCallback);
})
- .then(done);
- });
-});
-
-describe('Test gl3d annotations', function() {
- var gd;
-
- beforeEach(function() {
- gd = createGraphDiv();
- });
-
- afterEach(function() {
- Plotly.purge(gd);
- destroyGraphDiv();
- });
-
- function assertAnnotationText(expectations, msg) {
- var anns = d3.selectAll('g.annotation-text-g');
-
- expect(anns.size()).toBe(expectations.length, msg);
-
- anns.each(function(_, i) {
- var tx = d3.select(this).select('text').text();
- expect(tx).toEqual(expectations[i], msg + ' - ann ' + i);
- });
- }
-
- function assertAnnotationsXY(expectations, msg) {
- var TOL = 2.5;
- var anns = d3.selectAll('g.annotation-text-g');
-
- expect(anns.size()).toBe(expectations.length, msg);
-
- anns.each(function(_, i) {
- var ann = d3.select(this).select('g');
- var translate = Drawing.getTranslate(ann);
-
- expect(translate.x).toBeWithin(expectations[i][0], TOL, msg + ' - ann ' + i + ' x');
- expect(translate.y).toBeWithin(expectations[i][1], TOL, msg + ' - ann ' + i + ' y');
- });
- }
-
- // more robust (especially on CI) than update camera via mouse events
- function updateCamera(x, y, z) {
- var scene = gd._fullLayout.scene._scene;
- var camera = scene.getCamera();
-
- camera.eye = {x: x, y: y, z: z};
- scene.setCamera(camera);
- // need a fairly long delay to let the camera update here
- // 200 was not robust for me (AJ), 300 seems to be.
- return delay(300)();
- }
-
- it('should move with camera', function(done) {
- Plotly.plot(gd, [{
- type: 'scatter3d',
- x: [1, 2, 3],
- y: [1, 2, 3],
- z: [1, 2, 1]
- }], {
- scene: {
- camera: {eye: {x: 2.1, y: 0.1, z: 0.9}},
- annotations: [{
- text: 'hello',
- x: 1, y: 1, z: 1
- }, {
- text: 'sup?',
- x: 1, y: 1, z: 2
- }, {
- text: 'look!',
- x: 2, y: 2, z: 1
- }]
- }
+ .then(function() {
+ // Drag scene along the X axis
+ return mouseTo([200, 200], [220, 200]);
})
.then(function() {
- assertAnnotationsXY([[262, 199], [257, 135], [325, 233]], 'base 0');
-
- return updateCamera(1.5, 2.5, 1.5);
+ expect(gd.layout.xaxis.autorange).toBe(false);
+ expect(gd.layout.yaxis.autorange).toBe(false);
+ expect(gd.layout.xaxis.range).toBeCloseToArray(newX, precision);
+ expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
})
.then(function() {
- assertAnnotationsXY([[340, 187], [341, 142], [325, 221]], 'after camera update');
-
- return updateCamera(2.1, 0.1, 0.9);
+ // Drag scene back along the X axis
+ return mouseTo([220, 200], [200, 200]);
})
.then(function() {
- assertAnnotationsXY([[262, 199], [257, 135], [325, 233]], 'base 0');
+ expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
+ expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
})
- .catch(fail)
- .then(done);
- });
-
- it('should be removed when beyond the scene axis ranges', function(done) {
- var mock = Lib.extendDeep({}, require('@mocks/gl3d_annotations'));
-
- // replace text with something easier to identify
- mock.layout.scene.annotations.forEach(function(ann, i) { ann.text = String(i); });
-
- Plotly.plot(gd, mock).then(function() {
- assertAnnotationText(['0', '1', '2', '3', '4', '5', '6'], 'base');
-
- return Plotly.relayout(gd, 'scene.yaxis.range', [0.5, 1.5]);
+ .then(function() {
+ // Drag scene along the Y axis
+ return mouseTo([200, 200], [200, 150]);
})
.then(function() {
- assertAnnotationText(['1', '4', '5', '6'], 'after yaxis range relayout');
-
- return Plotly.relayout(gd, 'scene.yaxis.range', null);
+ expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
+ expect(gd.layout.yaxis.range).toBeCloseToArray(newY, precision);
})
.then(function() {
- assertAnnotationText(['0', '1', '2', '3', '4', '5', '6'], 'back to base after yaxis range relayout');
-
- return Plotly.relayout(gd, 'scene.zaxis.range', [0, 3]);
+ // Drag scene back along the Y axis
+ return mouseTo([200, 150], [200, 200]);
})
.then(function() {
- assertAnnotationText(['0', '4', '5', '6'], 'after zaxis range relayout');
-
- return Plotly.relayout(gd, 'scene.zaxis.range', null);
+ expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
+ expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
})
.then(function() {
- assertAnnotationText(['0', '1', '2', '3', '4', '5', '6'], 'back to base after zaxis range relayout');
+ // Drag scene along both the X and Y axis
+ return mouseTo([200, 200], [220, 150]);
+ })
+ .then(function() {
+ expect(gd.layout.xaxis.range).toBeCloseToArray(newX, precision);
+ expect(gd.layout.yaxis.range).toBeCloseToArray(newY, precision);
+ })
+ .then(function() {
+ // Drag scene back along the X and Y axis
+ return mouseTo([220, 150], [200, 200]);
+ })
+ .then(function() {
+ expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
+ expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
+ })
+ .then(delay(200))
+ .then(function() {
+ // callback count expectation: X and back; Y and back; XY and back
+ expect(relayoutCallback).toHaveBeenCalledTimes(6);
+
+ // a callback value structure and contents check
+ expect(relayoutCallback).toHaveBeenCalledWith(jasmine.objectContaining({
+ 'xaxis.range[0]': jasmine.any(Number),
+ 'xaxis.range[1]': jasmine.any(Number),
+ 'yaxis.range[0]': jasmine.any(Number),
+ 'yaxis.range[1]': jasmine.any(Number)
+ }));
})
.catch(fail)
.then(done);
});
- it('should be able to add/remove and hide/unhide themselves via relayout', function(done) {
- var mock = Lib.extendDeep({}, require('@mocks/gl3d_annotations'));
-
- // replace text with something easier to identify
- mock.layout.scene.annotations.forEach(function(ann, i) { ann.text = String(i); });
-
- var annNew = {
- x: '2017-03-01',
- y: 'C',
- z: 3,
- text: 'new!'
- };
-
- Plotly.plot(gd, mock).then(function() {
- assertAnnotationText(['0', '1', '2', '3', '4', '5', '6'], 'base');
+ it('@noCI should be able to toggle visibility', function(done) {
+ var _mock = Lib.extendDeep({}, mock);
- return Plotly.relayout(gd, 'scene.annotations[1].visible', false);
+ Plotly.plot(gd, _mock)
+ .then(delay(20))
+ .then(function() {
+ return Plotly.restyle(gd, 'visible', 'legendonly');
})
.then(function() {
- assertAnnotationText(['0', '2', '3', '4', '5', '6'], 'after [1].visible:false');
+ expect(gd.querySelector('.gl-canvas-context')).toBe(null);
- return Plotly.relayout(gd, 'scene.annotations[1].visible', true);
+ return Plotly.restyle(gd, 'visible', true);
})
.then(function() {
- assertAnnotationText(['0', '1', '2', '3', '4', '5', '6'], 'back to base (1)');
+ expect(readPixel(gd.querySelector('.gl-canvas-context'), 108, 100)[0]).not.toBe(0);
- return Plotly.relayout(gd, 'scene.annotations[0]', null);
+ return Plotly.restyle(gd, 'visible', false);
})
.then(function() {
- assertAnnotationText(['1', '2', '3', '4', '5', '6'], 'after [0] null');
+ expect(gd.querySelector('.gl-canvas-context')).toBe(null);
- return Plotly.relayout(gd, 'scene.annotations[0]', annNew);
+ return Plotly.restyle(gd, 'visible', true);
})
.then(function() {
- assertAnnotationText(['new!', '1', '2', '3', '4', '5', '6'], 'after add new (1)');
+ expect(readPixel(gd.querySelector('.gl-canvas-context'), 108, 100)[0]).not.toBe(0);
+ })
+ .catch(fail)
+ .then(done);
+ });
- return Plotly.relayout(gd, 'scene.annotations', null);
+ it('should be able to toggle from svg to gl', function(done) {
+ Plotly.plot(gd, [{
+ y: [1, 2, 1],
+ }])
+ .then(function() {
+ expect(countCanvases()).toBe(0);
+ expect(d3.selectAll('.scatterlayer > .trace').size()).toBe(1);
+
+ return Plotly.restyle(gd, 'type', 'scattergl');
})
.then(function() {
- assertAnnotationText([], 'after rm all');
+ expect(countCanvases()).toBe(3);
+ expect(d3.selectAll('.scatterlayer > .trace').size()).toBe(0);
- return Plotly.relayout(gd, 'scene.annotations[0]', annNew);
+ return Plotly.restyle(gd, 'type', 'scatter');
})
.then(function() {
- assertAnnotationText(['new!'], 'after add new (2)');
+ expect(countCanvases()).toBe(0);
+ expect(d3.selectAll('.scatterlayer > .trace').size()).toBe(1);
})
.catch(fail)
.then(done);
});
- it('should work across multiple scenes', function(done) {
- function assertAnnotationCntPerScene(id, cnt) {
- expect(d3.selectAll('g.annotation-' + id).size()).toEqual(cnt);
- }
+ it('supports 1D and 2D Zoom', function(done) {
+ var centerX;
+ var centerY;
- Plotly.plot(gd, [{
- type: 'scatter3d',
- x: [1, 2, 3],
- y: [1, 2, 3],
- z: [1, 2, 1]
- }, {
- type: 'scatter3d',
- x: [1, 2, 3],
- y: [1, 2, 3],
- z: [2, 1, 2],
- scene: 'scene2'
+ Plotly.newPlot(gd, [{
+ type: 'scattergl', x: [1, 15], y: [1, 15]
}], {
- scene: {
- annotations: [{
- text: 'hello',
- x: 1, y: 1, z: 1
- }]
- },
- scene2: {
- annotations: [{
- text: 'sup?',
- x: 1, y: 1, z: 2
- }, {
- text: 'look!',
- x: 2, y: 2, z: 1
- }]
- }
+ width: 400,
+ height: 400,
+ margin: {t: 100, b: 100, l: 100, r: 100},
+ xaxis: {range: [0, 16]},
+ yaxis: {range: [0, 16]}
})
.then(function() {
- assertAnnotationCntPerScene('scene', 1);
- assertAnnotationCntPerScene('scene2', 2);
+ var bBox = gd.getBoundingClientRect();
+ centerX = bBox.left + 200;
+ centerY = bBox.top + 200;
- return Plotly.deleteTraces(gd, [1]);
+ return mouseTo([centerX, centerY], [centerX - 5, centerY + 5]);
})
.then(function() {
- assertAnnotationCntPerScene('scene', 1);
- assertAnnotationCntPerScene('scene2', 2);
-
- return Plotly.deleteTraces(gd, [0]);
+ // no change - too small
+ expect(gd.layout.xaxis.range).toBeCloseToArray([0, 16], 3);
+ expect(gd.layout.yaxis.range).toBeCloseToArray([0, 16], 3);
})
.then(function() {
- assertAnnotationCntPerScene('scene', 1);
- assertAnnotationCntPerScene('scene2', 2);
+ return mouseTo([centerX - 50, centerY], [centerX + 50, centerY + 50]);
+ })
+ .then(function() {
+ // 2D
+ expect(gd.layout.xaxis.range).toBeCloseToArray([4, 12], 3);
+ expect(gd.layout.yaxis.range).toBeCloseToArray([4, 8], 3);
+ })
+ .then(function() {
+ return mouseTo([centerX - 50, centerY], [centerX, centerY + 5]);
+ })
+ .then(function() {
+ // x only
+ expect(gd.layout.xaxis.range).toBeCloseToArray([6, 8], 3);
+ expect(gd.layout.yaxis.range).toBeCloseToArray([4, 8], 3);
+ })
+ .then(function() {
+ return mouseTo([centerX, centerY - 50], [centerX - 5, centerY + 50]);
+ })
+ .then(function() {
+ // y only
+ expect(gd.layout.xaxis.range).toBeCloseToArray([6, 8], 3);
+ expect(gd.layout.yaxis.range).toBeCloseToArray([5, 7], 3);
})
.catch(fail)
.then(done);
});
- it('should contribute to scene axis autorange', function(done) {
- function assertSceneAxisRanges(xRange, yRange, zRange) {
- var sceneLayout = gd._fullLayout.scene;
-
- expect(sceneLayout.xaxis.range).toBeCloseToArray(xRange, 1, 'xaxis range');
- expect(sceneLayout.yaxis.range).toBeCloseToArray(yRange, 1, 'yaxis range');
- expect(sceneLayout.zaxis.range).toBeCloseToArray(zRange, 1, 'zaxis range');
- }
+ it('supports axis constraints with zoom', function(done) {
+ var centerX;
+ var centerY;
- Plotly.plot(gd, [{
- type: 'scatter3d',
- x: [1, 2, 3],
- y: [1, 2, 3],
- z: [1, 2, 1]
+ Plotly.newPlot(gd, [{
+ type: 'scattergl', x: [1, 15], y: [1, 15]
}], {
- scene: {
- annotations: [{
- text: 'hello',
- x: 1, y: 1, z: 3
- }]
- }
+ width: 400,
+ height: 400,
+ margin: {t: 100, b: 100, l: 100, r: 100},
+ xaxis: {range: [0, 16]},
+ yaxis: {range: [0, 16]}
})
.then(function() {
- assertSceneAxisRanges([0.9375, 3.0625], [0.9375, 3.0625], [0.9375, 3.0625]);
+ var bBox = gd.getBoundingClientRect();
+ centerX = bBox.left + 200;
+ centerY = bBox.top + 200;
- return Plotly.relayout(gd, 'scene.annotations[0].z', 10);
+ return Plotly.relayout(gd, {
+ 'yaxis.scaleanchor': 'x',
+ 'yaxis.scaleratio': 2
+ });
})
.then(function() {
- assertSceneAxisRanges([0.9375, 3.0625], [0.9375, 3.0625], [0.7187, 10.2813]);
+ // x range is adjusted to fit constraint
+ expect(gd.layout.xaxis.range).toBeCloseToArray([-8, 24], 3);
+ expect(gd.layout.yaxis.range).toBeCloseToArray([0, 16], 3);
+ })
+ .then(function() {
+ return mouseTo([centerX, centerY], [centerX - 5, centerY + 5]);
+ })
+ .then(function() {
+ // no change - too small
+ expect(gd.layout.xaxis.range).toBeCloseToArray([-8, 24], 3);
+ expect(gd.layout.yaxis.range).toBeCloseToArray([0, 16], 3);
+ })
+ .then(function() {
+ // now there should only be 2D zooming
+ // dy>>dx
+ return mouseTo([centerX, centerY], [centerX - 1, centerY - 50]);
+ })
+ .then(function() {
+ expect(gd.layout.xaxis.range).toBeCloseToArray([0, 8], 3);
+ expect(gd.layout.yaxis.range).toBeCloseToArray([8, 12], 3);
+ })
+ .then(function() {
+ return mouseTo([centerX, centerY], [centerX + 50, centerY + 1]);
+ })
+ .then(function() {
+ // dx>>dy
+ expect(gd.layout.xaxis.range).toBeCloseToArray([4, 6], 3);
+ expect(gd.layout.yaxis.range).toBeCloseToArray([9, 10], 3);
+ })
+ .then(function() {
+ return Plotly.relayout(gd, {
+ 'xaxis.autorange': true,
+ 'yaxis.autorange': true
+ });
+ })
+ .then(function() {
+ expect(gd.layout.xaxis.range).toBeCloseToArray([-7.6, 23.6], 1);
+ expect(gd.layout.yaxis.range).toBeCloseToArray([0.2, 15.8], 1);
})
.catch(fail)
.then(done);
});
- it('should allow text and tail position edits under `editable: true`', function(done) {
- function editText(newText, expectation) {
- return new Promise(function(resolve) {
- gd.once('plotly_relayout', function(eventData) {
- expect(eventData).toEqual(expectation);
- setTimeout(resolve, 0);
- });
-
- var clickNode = d3.select('g.annotation-text-g').select('g').node();
- clickNode.dispatchEvent(new window.MouseEvent('click'));
-
- var editNode = d3.select('.plugin-editable.editable').node();
- editNode.dispatchEvent(new window.FocusEvent('focus'));
+ it('should change plot type with incomplete data', function(done) {
+ Plotly.plot(gd, [{}]);
+ expect(function() {
+ Plotly.restyle(gd, {type: 'scattergl', x: [[1]]}, 0);
+ }).not.toThrow();
- editNode.textContent = newText;
- editNode.dispatchEvent(new window.FocusEvent('focus'));
- editNode.dispatchEvent(new window.FocusEvent('blur'));
- });
- }
+ expect(function() {
+ Plotly.restyle(gd, {y: [[1]]}, 0);
+ }).not.toThrow();
- function moveArrowTail(dx, dy, expectation) {
- var px = 243;
- var py = 150;
+ done();
+ });
- return new Promise(function(resolve) {
- gd.once('plotly_relayout', function(eventData) {
- expect(eventData).toEqual(expectation);
- resolve();
- });
+ it('data-referenced annotations should update on drag', function(done) {
+ function assertAnnotation(xy) {
+ var ann = d3.select('g.annotation-text-g').select('g');
+ var translate = Drawing.getTranslate(ann);
- mouseEvent('mousemove', px, py);
- mouseEvent('mousedown', px, py);
- mouseEvent('mousemove', px + dx, py + dy);
- mouseEvent('mouseup', px + dx, py + dy);
- });
+ expect(translate.x).toBeWithin(xy[0], 8);
+ expect(translate.y).toBeWithin(xy[1], 8);
}
- Plotly.plot(gd, [{
- type: 'scatter3d',
+ Plotly.newPlot(gd, [{
+ type: 'scattergl',
x: [1, 2, 3],
- y: [1, 2, 3],
- z: [1, 2, 1]
+ y: [2, 1, 2]
}], {
- scene: {
- annotations: [{
- text: 'hello',
- x: 2, y: 2, z: 2,
- font: { size: 30 }
- }]
- },
- margin: {l: 0, t: 0, r: 0, b: 0},
- width: 500,
- height: 500
- }, {
- editable: true
+ annotations: [{
+ x: 2,
+ y: 1,
+ text: 'text'
+ }],
+ dragmode: 'pan'
})
.then(function() {
- return editText('allo', {'scene.annotations[0].text': 'allo'});
+ assertAnnotation([327, 312]);
})
.then(function() {
- return moveArrowTail(-100, -50, {
- 'scene.annotations[0].ax': -110,
- 'scene.annotations[0].ay': -80
- });
- })
- .catch(fail)
- .then(done);
- });
-
- it('should display hover labels and trigger *plotly_clickannotation* event', function(done) {
- function dispatch(eventType) {
- var target = d3.select('g.annotation-text-g').select('g').node();
- target.dispatchEvent(new MouseEvent(eventType));
- }
-
- Plotly.plot(gd, [{
- type: 'scatter3d',
- x: [1, 2, 3],
- y: [1, 2, 3],
- z: [1, 2, 1]
- }], {
- scene: {
- annotations: [{
- text: 'hello',
- x: 2, y: 2, z: 2,
- ax: 0, ay: -100,
- hovertext: 'HELLO',
- hoverlabel: {
- bgcolor: 'red',
- font: { size: 20 }
- }
- }]
- },
- width: 500,
- height: 500
+ return mouseTo([250, 200], [200, 150]);
})
.then(function() {
- dispatch('mouseover');
- expect(d3.select('.hovertext').size()).toEqual(1);
+ assertAnnotation([277, 262]);
})
.then(function() {
- return new Promise(function(resolve, reject) {
- gd.once('plotly_clickannotation', function(eventData) {
- expect(eventData.index).toEqual(0);
- expect(eventData.subplotId).toEqual('scene');
- resolve();
- });
-
- setTimeout(function() {
- reject('plotly_clickannotation did not get called!');
- }, 100);
-
- dispatch('click');
+ return Plotly.relayout(gd, {
+ 'xaxis.range': [1.5, 2.5],
+ 'yaxis.range': [1, 1.5]
});
})
+ .then(function() {
+ assertAnnotation([327, 331]);
+ })
.catch(fail)
.then(done);
});
diff --git a/test/jasmine/tests/plots_test.js b/test/jasmine/tests/plots_test.js
index b155d65a808..af025d61ede 100644
--- a/test/jasmine/tests/plots_test.js
+++ b/test/jasmine/tests/plots_test.js
@@ -546,10 +546,11 @@ describe('Test Plots', function() {
describe('Plots.generalUpdatePerTraceModule', function() {
function _update(subplotCalcData, traceHashOld) {
+ var gd = {};
var subplot = { traceHash: traceHashOld || {} };
var calcDataPerModule = [];
- var plot = function(_, moduleCalcData) {
+ var plot = function(gd, subplot, moduleCalcData) {
calcDataPerModule.push(moduleCalcData);
};
@@ -557,7 +558,7 @@ describe('Test Plots', function() {
calcTrace[0].trace._module = { plot: plot };
});
- Plots.generalUpdatePerTraceModule(subplot, subplotCalcData, {});
+ Plots.generalUpdatePerTraceModule(gd, subplot, subplotCalcData, {});
return {
traceHash: subplot.traceHash,
diff --git a/test/jasmine/tests/polar_test.js b/test/jasmine/tests/polar_test.js
index 27a5ddb91d1..d33b989c813 100644
--- a/test/jasmine/tests/polar_test.js
+++ b/test/jasmine/tests/polar_test.js
@@ -520,6 +520,7 @@ describe('Test polar interactions:', function() {
];
beforeEach(function() {
+ jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
eventData = '';
eventCnts = {};
gd = createGraphDiv();
@@ -528,7 +529,7 @@ describe('Test polar interactions:', function() {
afterEach(destroyGraphDiv);
function _plot(fig) {
- return Plotly.plot(gd, fig).then(function() {
+ return Plotly.newPlot(gd, fig).then(function() {
eventNames.forEach(function(k) {
eventCnts[k] = 0;
gd.on(k, function(d) {
@@ -701,9 +702,12 @@ describe('Test polar interactions:', function() {
.then(done);
});
- it('should response to drag interactions on plot area', function(done) {
+ it('@noCI should response to drag interactions on plot area', function(done) {
var fig = Lib.extendDeep({}, require('@mocks/polar_scatter.json'));
+ // to avoid dragging on hover labels
+ fig.layout.hovermode = false;
+
// adjust margins so that middle of plot area is at 300x300
// with its middle at [200,200]
fig.layout.width = 400;
@@ -741,14 +745,16 @@ describe('Test polar interactions:', function() {
}
function _reset() {
- return _doubleClick(mid).then(function() {
- relayoutNumber++;
- resetNumber++;
-
- var extra = '(reset ' + resetNumber + ')';
- _assertBase(extra);
- expect(eventCnts.plotly_doubleclick).toBe(resetNumber, 'doubleclick event #' + extra);
- });
+ return delay(100)()
+ .then(function() { return _doubleClick(mid); })
+ .then(function() {
+ relayoutNumber++;
+ resetNumber++;
+
+ var extra = '(reset ' + resetNumber + ')';
+ _assertBase(extra);
+ expect(eventCnts.plotly_doubleclick).toBe(resetNumber, 'doubleclick event #' + extra);
+ });
}
_plot(fig)
@@ -787,9 +793,12 @@ describe('Test polar interactions:', function() {
.then(done);
});
- it('should response to drag interactions on radial drag area', function(done) {
+ it('@noCI should response to drag interactions on radial drag area', function(done) {
var fig = Lib.extendDeep({}, require('@mocks/polar_scatter.json'));
+ // to avoid dragging on hover labels
+ fig.layout.hovermode = false;
+
// adjust margins so that middle of plot area is at 300x300
// with its middle at [200,200]
fig.layout.width = 400;
@@ -803,18 +812,7 @@ describe('Test polar interactions:', function() {
// to activate the radial drag mode
function _drag(p0, dp) {
var node = d3.select('.polar > .draglayer > .radialdrag').node();
- var p1 = [p0[0] + dp[0] / 2, p0[1] + dp[1] / 2];
- var p2 = [p0[0] + dp[0], p0[1] + dp[1]];
-
- mouseEvent('mousemove', p0[0], p0[1], {element: node});
- mouseEvent('mousedown', p0[0], p0[1], {element: node});
-
- return delay(250)()
- .then(function() { mouseEvent('mousemove', p1[0], p1[1], {element: document}); })
- .then(delay(50))
- .then(function() { mouseEvent('mousemove', p2[0], p2[1], {element: document}); })
- .then(function() { mouseEvent('mouseup', p2[0], p2[1], {element: document}); })
- .then(delay(50));
+ return drag(node, dp[0], dp[1], null, p0[0], p0[1], 2);
}
function _assert(rng, angle, evtRng1, evtAngle, msg) {
@@ -839,13 +837,15 @@ describe('Test polar interactions:', function() {
}
function _reset() {
- return _doubleClick([200, 200]).then(function() {
- resetNumber++;
-
- var extra = '(reset ' + resetNumber + ')';
- _assertBase(extra);
- expect(eventCnts.plotly_doubleclick).toBe(resetNumber, 'doubleclick event #' + extra);
- });
+ return delay(100)()
+ .then(function() { return _doubleClick([200, 200]); })
+ .then(function() {
+ resetNumber++;
+
+ var extra = '(reset ' + resetNumber + ')';
+ _assertBase(extra);
+ expect(eventCnts.plotly_doubleclick).toBe(resetNumber, 'doubleclick event #' + extra);
+ });
}
_plot(fig)
@@ -877,9 +877,12 @@ describe('Test polar interactions:', function() {
.then(done);
});
- it('should response to drag interactions on angular drag area', function(done) {
+ it('@noCI should response to drag interactions on angular drag area', function(done) {
var fig = Lib.extendDeep({}, require('@mocks/polar_scatter.json'));
+ // to avoid dragging on hover labels
+ fig.layout.hovermode = false;
+
// adjust margins so that middle of plot area is at 300x300
// with its middle at [200,200]
fig.layout.width = 400;
@@ -909,13 +912,15 @@ describe('Test polar interactions:', function() {
}
function _reset() {
- return _doubleClick([200, 200]).then(function() {
- resetNumber++;
-
- var extra = '(reset ' + resetNumber + ')';
- _assertBase(extra);
- expect(eventCnts.plotly_doubleclick).toBe(resetNumber, 'doubleclick event #' + extra);
- });
+ return delay(100)()
+ .then(function() { return _doubleClick([200, 200]); })
+ .then(function() {
+ resetNumber++;
+
+ var extra = '(reset ' + resetNumber + ')';
+ _assertBase(extra);
+ expect(eventCnts.plotly_doubleclick).toBe(resetNumber, 'doubleclick event #' + extra);
+ });
}
_plot(fig)
diff --git a/test/jasmine/tests/scatterpolargl_test.js b/test/jasmine/tests/scatterpolargl_test.js
new file mode 100644
index 00000000000..766e2551262
--- /dev/null
+++ b/test/jasmine/tests/scatterpolargl_test.js
@@ -0,0 +1,88 @@
+var Plotly = require('@lib');
+var Lib = require('@src/lib');
+
+var createGraphDiv = require('../assets/create_graph_div');
+var destroyGraphDiv = require('../assets/destroy_graph_div');
+var fail = require('../assets/fail_test');
+var mouseEvent = require('../assets/mouse_event');
+
+var customAssertions = require('../assets/custom_assertions');
+var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
+
+describe('Test scatterpolargl hover:', function() {
+ var gd;
+
+ afterEach(function() {
+ Plotly.purge(gd);
+ destroyGraphDiv();
+ });
+
+ function run(specs) {
+ gd = createGraphDiv();
+
+ var fig = Lib.extendDeep(
+ {width: 700, height: 500},
+ specs.mock || require('@mocks/glpolar_scatter.json')
+ );
+
+ if(specs.patch) {
+ fig = specs.patch(fig);
+ }
+
+ var pos = specs.pos || [200, 200];
+
+ return Plotly.newPlot(gd, fig).then(function() {
+ mouseEvent('mousemove', pos[0], pos[1]);
+ assertHoverLabelContent(specs);
+ });
+ }
+
+ [{
+ desc: 'base',
+ nums: 'r: 2.920135\nθ: 138.2489°',
+ name: 'Trial 4'
+ }, {
+ desc: '(no labels - out of sector)',
+ patch: function(fig) {
+ fig.layout.polar.sector = [15, 75];
+ return fig;
+ },
+ pos: [144, 350],
+ nums: '',
+ name: ''
+ }, {
+ desc: 'on a `thetaunit: radians` polar subplot',
+ patch: function(fig) {
+ fig.layout.polar.angularaxis.thetaunit = 'radians';
+ return fig;
+ },
+ nums: 'r: 2.920135\nθ: 2.412898',
+ name: 'Trial 4'
+ }, {
+ desc: 'on log radial axis',
+ patch: function(fig) {
+ fig.layout.polar.radialaxis.type = 'log';
+ return fig;
+ },
+ nums: 'r: 1.108937\nθ: 115.4969°',
+ name: 'Trial 3'
+ }, {
+ desc: 'on category axes',
+ mock: require('@mocks/polar_categories.json'),
+ patch: function(fig) {
+ fig.data.forEach(function(t) {
+ t.type = 'scatterpolargl';
+ t.fill = 'none';
+ });
+ return fig;
+ },
+ pos: [470, 80],
+ nums: 'r: 4\nθ: d',
+ name: 'angular cate...'
+ }]
+ .forEach(function(specs) {
+ it('should generate correct hover labels ' + specs.desc, function(done) {
+ run(specs).catch(fail).then(done);
+ });
+ });
+});