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); + }); + }); +});