From dd563bbad152d1ab33f392e9deafd0821dbc0e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Mon, 13 Aug 2018 15:01:26 -0400 Subject: [PATCH 01/13] consider only splom dimensions on axis during axis autotype - using trace._diag, this allows to support multiple axis type in splom-generated axes --- src/plots/cartesian/type_defaults.js | 3 ++- test/jasmine/tests/splom_test.js | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plots/cartesian/type_defaults.js b/src/plots/cartesian/type_defaults.js index 5a9414054b6..aff5de345c9 100644 --- a/src/plots/cartesian/type_defaults.js +++ b/src/plots/cartesian/type_defaults.js @@ -89,9 +89,10 @@ function setAutoType(ax, data) { } else if(d0.type === 'splom') { var dimensions = d0.dimensions; + var diag = d0._diag; for(i = 0; i < dimensions.length; i++) { var dim = dimensions[i]; - if(dim.visible) { + if(dim.visible && (diag[i][0] === id || diag[i][1] === id)) { ax.type = autoType(dim.values, calendar); break; } diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js index 43e37a3b3c3..db52d7870cb 100644 --- a/test/jasmine/tests/splom_test.js +++ b/test/jasmine/tests/splom_test.js @@ -352,8 +352,10 @@ describe('Test splom trace defaults:', function() { }); var fullLayout = gd._fullLayout; - expect(fullLayout.xaxis.type).toBe('date'); - expect(fullLayout.yaxis.type).toBe('date'); + expect(fullLayout.xaxis.type).toBe('linear', 'fallbacks to linear for visible:false traces'); + expect(fullLayout.yaxis.type).toBe('linear', 'fallbacks to linear for visible:false traces'); + expect(fullLayout.xaxis2.type).toBe('date'); + expect(fullLayout.yaxis2.type).toBe('date'); }); }); From 9e1869d34ffac57ed7413cc2ca85ef5305cab983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Mon, 13 Aug 2018 15:02:23 -0400 Subject: [PATCH 02/13] copy back axes categories on axes that skipped makeCalcdata, ... to make categorical axis ticks show up correctly --- src/traces/splom/index.js | 54 ++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/traces/splom/index.js b/src/traces/splom/index.js index c5613e5844f..a076305f97e 100644 --- a/src/traces/splom/index.js +++ b/src/traces/splom/index.js @@ -36,19 +36,39 @@ function calc(gd, trace) { // only differ here for log axes, pass ldata to createMatrix as 'data' var cdata = opts.cdata = []; var ldata = opts.data = []; - var i, k, dim; + var i, k, dim, xa, ya; + + function makeCalcdata(ax, dim) { + // call makeCalcdata with fake input + var ccol = ax.makeCalcdata({ + v: dim.values, + vcalendar: trace.calendar + }, 'v'); + + for(var i = 0; i < ccol.length; i++) { + ccol[i] = ccol[i] === BADNUM ? NaN : ccol[i]; + } + cdata.push(ccol); + ldata.push(ax.type === 'log' ? Lib.simpleMap(ccol, ax.c2l) : ccol); + } for(i = 0; i < dimensions.length; i++) { dim = dimensions[i]; if(dim.visible) { - var axId = trace._diag[i][0] || trace._diag[i][1]; - var ax = AxisIDs.getFromId(gd, axId); - if(ax) { - var ccol = makeCalcdata(ax, trace, dim); - var lcol = ax.type === 'log' ? Lib.simpleMap(ccol, ax.c2l) : ccol; - cdata.push(ccol); - ldata.push(lcol); + xa = AxisIDs.getFromId(gd, trace._diag[i][0]); + ya = AxisIDs.getFromId(gd, trace._diag[i][1]); + + if(xa) { + makeCalcdata(xa, dim); + if(ya && ya.type === 'category') { + ya._categories = xa._categories.slice(); + } + } else if(ya) { + makeCalcdata(ya, dim); + if(xa && xa.type === 'category') { + xa._categories = ya._categories.slice(); + } } } } @@ -63,8 +83,8 @@ function calc(gd, trace) { dim = dimensions[i]; if(dim.visible) { - var xa = AxisIDs.getFromId(gd, trace._diag[i][0]) || {}; - var ya = AxisIDs.getFromId(gd, trace._diag[i][1]) || {}; + xa = AxisIDs.getFromId(gd, trace._diag[i][0]) || {}; + ya = AxisIDs.getFromId(gd, trace._diag[i][1]) || {}; // Reuse SVG scatter axis expansion routine. // For graphs with very large number of points and array marker.size, @@ -91,20 +111,6 @@ function calc(gd, trace) { return [{x: false, y: false, t: stash, trace: trace}]; } -function makeCalcdata(ax, trace, dim) { - // call makeCalcdata with fake input - var ccol = ax.makeCalcdata({ - v: dim.values, - vcalendar: trace.calendar - }, 'v'); - - for(var i = 0; i < ccol.length; i++) { - ccol[i] = ccol[i] === BADNUM ? NaN : ccol[i]; - } - - return ccol; -} - function sceneUpdate(gd, stash) { var scene = stash._scene; From 9da5a1bcf270250011a1515fada1e5002cc75f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Mon, 13 Aug 2018 15:03:11 -0400 Subject: [PATCH 03/13] add splom mutli axis type mock - note that axis type can be overwritten in layout --- .../image/baselines/splom_multi-axis-type.png | Bin 0 -> 36480 bytes test/image/mocks/splom_multi-axis-type.json | 45 ++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 test/image/baselines/splom_multi-axis-type.png create mode 100644 test/image/mocks/splom_multi-axis-type.json diff --git a/test/image/baselines/splom_multi-axis-type.png b/test/image/baselines/splom_multi-axis-type.png new file mode 100644 index 0000000000000000000000000000000000000000..13c9aa9b1767bf7fad9683f5f8e8cadcb8972fe2 GIT binary patch literal 36480 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 rx&IruHo;Ju|9^@A-T$wNr{llTR Date: Tue, 14 Aug 2018 14:25:31 -0400 Subject: [PATCH 04/13] swap (x|y)a -> (x|y)id for clarity --- src/traces/splom/defaults.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/traces/splom/defaults.js b/src/traces/splom/defaults.js index afcb002e8b3..599ee63fc9f 100644 --- a/src/traces/splom/defaults.js +++ b/src/traces/splom/defaults.js @@ -113,14 +113,14 @@ function handleAxisDefaults(traceIn, traceOut, layout, coerce) { for(i = 0; i < dimLength; i++) { var dim = dimensions[i]; - var xa = xaxes[i + xShift]; - var ya = yaxes[i + yShift]; + var xaId = xaxes[i + xShift]; + var yaId = yaxes[i + yShift]; - fillAxisStash(layout, xa, dim); - fillAxisStash(layout, ya, dim); + fillAxisStash(layout, xaId, dim); + fillAxisStash(layout, yaId, dim); // note that some the entries here may be undefined - diag[i] = [xa, ya]; + diag[i] = [xaId, yaId]; } // when lower half is omitted, override grid default From b3d27bdbd7c714270e57ada13beee5f3dd081b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 14 Aug 2018 17:06:19 -0400 Subject: [PATCH 05/13] skip dims with conflicting axis types --- src/traces/splom/index.js | 9 +++++---- test/jasmine/tests/splom_test.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/traces/splom/index.js b/src/traces/splom/index.js index a076305f97e..11cdba8dedc 100644 --- a/src/traces/splom/index.js +++ b/src/traces/splom/index.js @@ -59,16 +59,17 @@ function calc(gd, trace) { xa = AxisIDs.getFromId(gd, trace._diag[i][0]); ya = AxisIDs.getFromId(gd, trace._diag[i][1]); + // if corresponding x & y axes don't have matching types, skip dim + if(xa && ya && xa.type !== ya.type) continue; + if(xa) { makeCalcdata(xa, dim); if(ya && ya.type === 'category') { ya._categories = xa._categories.slice(); } - } else if(ya) { + } else { + // should not make it here, if both xa and ya undefined makeCalcdata(ya, dim); - if(xa && xa.type === 'category') { - xa._categories = ya._categories.slice(); - } } } } diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js index db52d7870cb..4be73e3f881 100644 --- a/test/jasmine/tests/splom_test.js +++ b/test/jasmine/tests/splom_test.js @@ -359,6 +359,36 @@ describe('Test splom trace defaults:', function() { }); }); +describe('Test splom trace calc step:', function() { + var gd; + + function _calc(opts, layout) { + gd = {}; + + gd.data = [Lib.extendFlat({type: 'splom'}, opts || {})]; + gd.layout = layout || {}; + supplyAllDefaults(gd); + Plots.doCalcdata(gd); + } + + it('should skip dimensions with conflicting axis types', function() { + _calc({ + dimensions: [{ + values: [1, 2, 3] + }, { + values: [2, 1, 2] + }] + }, { + xaxis: {type: 'category'}, + yaxis: {type: 'linear'} + }); + + var cd = gd.calcdata[0][0]; + + expect(cd.t._scene.matrixOptions.data).toBeCloseTo2DArray([[2, 1, 2]]); + }); +}); + describe('@gl Test splom interactions:', function() { var gd; From 9039a8e7e90a1f232ffa6fc896eb9b4feb33b16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 14 Aug 2018 17:07:37 -0400 Subject: [PATCH 06/13] keep track of visible dimensions using visibleDims list ... which simplifies logic downstream --- src/traces/splom/attributes.js | 17 ++++ src/traces/splom/base_plot.js | 36 ++++----- src/traces/splom/index.js | 132 +++++++++++++++---------------- test/jasmine/tests/splom_test.js | 1 + 4 files changed, 98 insertions(+), 88 deletions(-) diff --git a/src/traces/splom/attributes.js b/src/traces/splom/attributes.js index 0c5dd6a9185..dbc9169bbe4 100644 --- a/src/traces/splom/attributes.js +++ b/src/traces/splom/attributes.js @@ -58,6 +58,23 @@ module.exports = { description: 'Sets the dimension values to be plotted.' }, + axis: { + type: { + valType: 'enumerated', + values: ['linear', 'log', 'date', 'category'], + role: 'info', + editType: 'calc+clearAxisTypes', + description: [ + 'Sets the axis type for this dimension\'s generated', + 'x and y axes.', + 'Note that the axis `type` values set in layout take', + 'precedence over this attribute.' + ].join(' ') + }, + + editType: 'calc+clearAxisTypes' + }, + // TODO should add an attribute to pin down x only vars and y only vars // like https://seaborn.pydata.org/generated/seaborn.pairplot.html // x_vars and y_vars diff --git a/src/traces/splom/base_plot.js b/src/traces/splom/base_plot.js index 80bef941fb1..7e747ca0fd5 100644 --- a/src/traces/splom/base_plot.js +++ b/src/traces/splom/base_plot.js @@ -45,36 +45,34 @@ function drag(gd) { for(var i = 0; i < cd.length; i++) { var cd0 = cd[i][0]; var trace = cd0.trace; - var scene = cd0.t._scene; + var stash = cd0.t; + var scene = stash._scene; if(trace.type === 'splom' && scene && scene.matrix) { - dragOne(gd, trace, scene); + dragOne(gd, trace, stash, scene); } } } -function dragOne(gd, trace, scene) { - var dimensions = trace.dimensions; +function dragOne(gd, trace, stash, scene) { var visibleLength = scene.matrixOptions.data.length; + var visibleDims = stash.visibleDims; var ranges = new Array(visibleLength); - for(var i = 0, k = 0; i < dimensions.length; i++) { - if(dimensions[i].visible) { - var rng = ranges[k] = new Array(4); + for(var k = 0; k < visibleDims.length; k++) { + var i = visibleDims[k]; + var rng = ranges[k] = new Array(4); - var xa = AxisIDs.getFromId(gd, trace._diag[i][0]); - if(xa) { - rng[0] = xa.r2l(xa.range[0]); - rng[2] = xa.r2l(xa.range[1]); - } - - var ya = AxisIDs.getFromId(gd, trace._diag[i][1]); - if(ya) { - rng[1] = ya.r2l(ya.range[0]); - rng[3] = ya.r2l(ya.range[1]); - } + var xa = AxisIDs.getFromId(gd, trace._diag[i][0]); + if(xa) { + rng[0] = xa.r2l(xa.range[0]); + rng[2] = xa.r2l(xa.range[1]); + } - k++; + var ya = AxisIDs.getFromId(gd, trace._diag[i][1]); + if(ya) { + rng[1] = ya.r2l(ya.range[0]); + rng[3] = ya.r2l(ya.range[1]); } } diff --git a/src/traces/splom/index.js b/src/traces/splom/index.js index 11cdba8dedc..738ac23280e 100644 --- a/src/traces/splom/index.js +++ b/src/traces/splom/index.js @@ -36,6 +36,8 @@ function calc(gd, trace) { // only differ here for log axes, pass ldata to createMatrix as 'data' var cdata = opts.cdata = []; var ldata = opts.data = []; + // keep track of visible dimensions + var visibleDims = stash.visibleDims = []; var i, k, dim, xa, ya; function makeCalcdata(ax, dim) { @@ -71,6 +73,8 @@ function calc(gd, trace) { // should not make it here, if both xa and ya undefined makeCalcdata(ya, dim); } + + visibleDims.push(i); } } @@ -80,26 +84,24 @@ function calc(gd, trace) { var visibleLength = cdata.length; var hasTooManyPoints = (visibleLength * commonLength) > TOO_MANY_POINTS; - for(i = 0, k = 0; i < dimensions.length; i++) { + for(k = 0; k < visibleDims.length; k++) { + i = visibleDims[k]; dim = dimensions[i]; - if(dim.visible) { - xa = AxisIDs.getFromId(gd, trace._diag[i][0]) || {}; - ya = AxisIDs.getFromId(gd, trace._diag[i][1]) || {}; - - // Reuse SVG scatter axis expansion routine. - // For graphs with very large number of points and array marker.size, - // use average marker size instead to speed things up. - var ppad; - if(hasTooManyPoints) { - ppad = 2 * (opts.sizeAvg || Math.max(opts.size, 3)); - } else { - ppad = calcMarkerSize(trace, commonLength); - } - - calcAxisExpansion(gd, trace, xa, ya, cdata[k], cdata[k], ppad); - k++; + xa = AxisIDs.getFromId(gd, trace._diag[i][0]) || {}; + ya = AxisIDs.getFromId(gd, trace._diag[i][1]) || {}; + + // Reuse SVG scatter axis expansion routine. + // For graphs with very large number of points and array marker.size, + // use average marker size instead to speed things up. + var ppad; + if(hasTooManyPoints) { + ppad = 2 * (opts.sizeAvg || Math.max(opts.size, 3)); + } else { + ppad = calcMarkerSize(trace, commonLength); } + + calcAxisExpansion(gd, trace, xa, ya, cdata[k], cdata[k], ppad); } var scene = stash._scene = sceneUpdate(gd, stash); @@ -133,9 +135,7 @@ function sceneUpdate(gd, stash) { // draw traces in selection mode if(scene.matrix && scene.selectBatch) { scene.matrix.draw(scene.unselectBatch, scene.selectBatch); - } - - else if(scene.matrix) { + } else if(scene.matrix) { scene.matrix.draw(); } @@ -191,34 +191,32 @@ function plotOne(gd, cd0) { matrixOpts.upper = trace.showlowerhalf; matrixOpts.diagonal = trace.diagonal.visible; - var dimensions = trace.dimensions; + var visibleDims = stash.visibleDims; var visibleLength = cdata.length; var viewOpts = {}; viewOpts.ranges = new Array(visibleLength); viewOpts.domains = new Array(visibleLength); - for(i = 0, k = 0; i < dimensions.length; i++) { - if(trace.dimensions[i].visible) { - var rng = viewOpts.ranges[k] = new Array(4); - var dmn = viewOpts.domains[k] = new Array(4); + for(k = 0; k < visibleDims.length; k++) { + i = visibleDims[k]; - xa = AxisIDs.getFromId(gd, trace._diag[i][0]); - if(xa) { - rng[0] = xa._rl[0]; - rng[2] = xa._rl[1]; - dmn[0] = xa.domain[0]; - dmn[2] = xa.domain[1]; - } + var rng = viewOpts.ranges[k] = new Array(4); + var dmn = viewOpts.domains[k] = new Array(4); - ya = AxisIDs.getFromId(gd, trace._diag[i][1]); - if(ya) { - rng[1] = ya._rl[0]; - rng[3] = ya._rl[1]; - dmn[1] = ya.domain[0]; - dmn[3] = ya.domain[1]; - } + xa = AxisIDs.getFromId(gd, trace._diag[i][0]); + if(xa) { + rng[0] = xa._rl[0]; + rng[2] = xa._rl[1]; + dmn[0] = xa.domain[0]; + dmn[2] = xa.domain[1]; + } - k++; + ya = AxisIDs.getFromId(gd, trace._diag[i][1]); + if(ya) { + rng[1] = ya._rl[0]; + rng[3] = ya._rl[1]; + dmn[1] = ya.domain[0]; + dmn[3] = ya.domain[1]; } } @@ -260,25 +258,23 @@ function plotOne(gd, cd0) { var xpx = stash.xpx = new Array(visibleLength); var ypx = stash.ypx = new Array(visibleLength); - for(i = 0, k = 0; i < dimensions.length; i++) { - if(trace.dimensions[i].visible) { - xa = AxisIDs.getFromId(gd, trace._diag[i][0]); - if(xa) { - xpx[k] = new Array(commonLength); - for(j = 0; j < commonLength; j++) { - xpx[k][j] = xa.c2p(cdata[k][j]); - } - } + for(k = 0; k < visibleDims.length; k++) { + i = visibleDims[k]; - ya = AxisIDs.getFromId(gd, trace._diag[i][1]); - if(ya) { - ypx[k] = new Array(commonLength); - for(j = 0; j < commonLength; j++) { - ypx[k][j] = ya.c2p(cdata[k][j]); - } + xa = AxisIDs.getFromId(gd, trace._diag[i][0]); + if(xa) { + xpx[k] = new Array(commonLength); + for(j = 0; j < commonLength; j++) { + xpx[k][j] = xa.c2p(cdata[k][j]); } + } - k++; + ya = AxisIDs.getFromId(gd, trace._diag[i][1]); + if(ya) { + ypx[k] = new Array(commonLength); + for(j = 0; j < commonLength; j++) { + ypx[k][j] = ya.c2p(cdata[k][j]); + } } } @@ -293,8 +289,8 @@ function plotOne(gd, cd0) { } } else { - scene.matrix.update(matrixOpts); - scene.matrix.update(viewOpts); + scene.matrix.update(matrixOpts, null); + scene.matrix.update(viewOpts, null); stash.xpx = stash.ypx = null; } @@ -313,8 +309,8 @@ function hoverPoints(pointData, xval, yval) { var ypx = ya.c2p(yval); var maxDistance = pointData.distance; - var xi = getDimIndex(trace, xa); - var yi = getDimIndex(trace, ya); + var xi = getDimIndex(trace, stash, xa); + var yi = getDimIndex(trace, stash, ya); if(xi === false || yi === false) return [pointData]; var x = cdata[xi]; @@ -363,8 +359,8 @@ function selectPoints(searchInfo, polygon) { var hasOnlyLines = (!subTypes.hasMarkers(trace) && !subTypes.hasText(trace)); if(trace.visible !== true || hasOnlyLines) return selection; - var xi = getDimIndex(trace, xa); - var yi = getDimIndex(trace, ya); + var xi = getDimIndex(trace, stash, xa); + var yi = getDimIndex(trace, stash, ya); if(xi === false || yi === false) return selection; var xpx = stash.xpx[xi]; @@ -445,17 +441,15 @@ function style(gd, cds) { } } -function getDimIndex(trace, ax) { +function getDimIndex(trace, stash, ax) { var axId = ax._id; var axLetter = axId.charAt(0); var ind = {x: 0, y: 1}[axLetter]; - var dimensions = trace.dimensions; + var visibleDims = stash.visibleDims; - for(var i = 0, k = 0; i < dimensions.length; i++) { - if(dimensions[i].visible) { - if(trace._diag[i][ind] === axId) return k; - k++; - } + for(var k = 0; k < visibleDims.length; k++) { + var i = visibleDims[k]; + if(trace._diag[i][ind] === axId) return k; } return false; } diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js index 4be73e3f881..73243c8495b 100644 --- a/test/jasmine/tests/splom_test.js +++ b/test/jasmine/tests/splom_test.js @@ -386,6 +386,7 @@ describe('Test splom trace calc step:', function() { var cd = gd.calcdata[0][0]; expect(cd.t._scene.matrixOptions.data).toBeCloseTo2DArray([[2, 1, 2]]); + expect(cd.t.visibleDims).toEqual([1]); }); }); From ab7d9c6420e5a53fd745f74f78c03d08e1efb0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 14 Aug 2018 17:09:17 -0400 Subject: [PATCH 07/13] bring handleTypeDefaults api on-par ... with other sub-supply-defaults routines --- src/plots/cartesian/layout_defaults.js | 5 ++++- src/plots/cartesian/type_defaults.js | 13 +++---------- src/plots/gl3d/layout/axis_defaults.js | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/plots/cartesian/layout_defaults.js b/src/plots/cartesian/layout_defaults.js index 6c2f824781e..591174a0bcc 100644 --- a/src/plots/cartesian/layout_defaults.js +++ b/src/plots/cartesian/layout_defaults.js @@ -157,7 +157,9 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { axLayoutOut._annIndices = []; axLayoutOut._shapeIndices = []; - handleTypeDefaults(axLayoutIn, axLayoutOut, coerce, traces, axName); + // set up some private properties + axLayoutOut._name = axName; + var id = axLayoutOut._id = name2id(axName); var overlayableAxes = getOverlayableAxes(axLetter, axName); @@ -173,6 +175,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { cheateronly: axLetter === 'x' && xaCheater[axName] && !xaNonCheater[axName] }; + handleTypeDefaults(axLayoutIn, axLayoutOut, coerce, defaultOptions); handleAxisDefaults(axLayoutIn, axLayoutOut, coerce, defaultOptions, layoutOut); var spikecolor = coerce2('spikecolor'), diff --git a/src/plots/cartesian/type_defaults.js b/src/plots/cartesian/type_defaults.js index aff5de345c9..0e7cf1cfe91 100644 --- a/src/plots/cartesian/type_defaults.js +++ b/src/plots/cartesian/type_defaults.js @@ -11,27 +11,20 @@ var Registry = require('../../registry'); var autoType = require('./axis_autotype'); -var name2id = require('./axis_ids').name2id; /* * data: the plot data to use in choosing auto type * name: axis object name (ie 'xaxis') if one should be stored */ -module.exports = function handleTypeDefaults(containerIn, containerOut, coerce, data, name) { - // set up some private properties - if(name) { - containerOut._name = name; - containerOut._id = name2id(name); - } +module.exports = function handleTypeDefaults(containerIn, containerOut, coerce, options) { var axType = coerce('type'); if(axType === '-') { - setAutoType(containerOut, data); + setAutoType(containerOut, options.data); if(containerOut.type === '-') { containerOut.type = 'linear'; - } - else { + } else { // copy autoType back to input axis // note that if this object didn't exist // in the input layout, we have to put it in diff --git a/src/plots/gl3d/layout/axis_defaults.js b/src/plots/gl3d/layout/axis_defaults.js index a3ac9c14285..e28b1a74de4 100644 --- a/src/plots/gl3d/layout/axis_defaults.js +++ b/src/plots/gl3d/layout/axis_defaults.js @@ -39,7 +39,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, options) { containerOut._id = axName[0] + options.scene; containerOut._name = axName; - handleTypeDefaults(containerIn, containerOut, coerce, options.data); + handleTypeDefaults(containerIn, containerOut, coerce, options); handleAxisDefaults( containerIn, From 39b71bb0fa10f1d57bf1a3a023b48f8e47bb0f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 14 Aug 2018 17:17:42 -0400 Subject: [PATCH 08/13] add dimensions[i].axis.type .. to more easily set axis type on splom-generated axes --- src/plots/cartesian/axis_defaults.js | 4 +-- src/plots/cartesian/layout_defaults.js | 3 +- src/plots/cartesian/type_defaults.js | 3 +- src/traces/splom/defaults.js | 10 +++++- test/image/mocks/splom_multi-axis-type.json | 17 +++------- test/jasmine/tests/splom_test.js | 36 +++++++++++++++++++++ 6 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js index dad861716d4..06de3b99378 100644 --- a/src/plots/cartesian/axis_defaults.js +++ b/src/plots/cartesian/axis_defaults.js @@ -33,8 +33,8 @@ var setConvert = require('./set_convert'); */ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, options, layoutOut) { var letter = options.letter; - var id = containerOut._id; var font = options.font || {}; + var splomStash = options.splomStash || {}; var visible = coerce('visible', !options.cheateronly); @@ -66,7 +66,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, // template too. var dfltFontColor = (dfltColor !== layoutAttributes.color.dflt) ? dfltColor : font.color; // try to get default title from splom trace, fallback to graph-wide value - var dfltTitle = ((layoutOut._splomAxes || {})[letter] || {})[id] || layoutOut._dfltTitle[letter]; + var dfltTitle = splomStash.label || layoutOut._dfltTitle[letter]; coerce('title', dfltTitle); Lib.coerceFont(coerce, 'titlefont', { diff --git a/src/plots/cartesian/layout_defaults.js b/src/plots/cartesian/layout_defaults.js index 591174a0bcc..63abbc2364b 100644 --- a/src/plots/cartesian/layout_defaults.js +++ b/src/plots/cartesian/layout_defaults.js @@ -172,7 +172,8 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { bgColor: bgColor, calendar: layoutOut.calendar, automargin: true, - cheateronly: axLetter === 'x' && xaCheater[axName] && !xaNonCheater[axName] + cheateronly: axLetter === 'x' && xaCheater[axName] && !xaNonCheater[axName], + splomStash: ((layoutOut._splomAxes || {})[axLetter] || {})[id] }; handleTypeDefaults(axLayoutIn, axLayoutOut, coerce, defaultOptions); diff --git a/src/plots/cartesian/type_defaults.js b/src/plots/cartesian/type_defaults.js index 0e7cf1cfe91..1234f8a24a6 100644 --- a/src/plots/cartesian/type_defaults.js +++ b/src/plots/cartesian/type_defaults.js @@ -6,7 +6,6 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var Registry = require('../../registry'); @@ -17,8 +16,8 @@ var autoType = require('./axis_autotype'); * name: axis object name (ie 'xaxis') if one should be stored */ module.exports = function handleTypeDefaults(containerIn, containerOut, coerce, options) { + var axType = coerce('type', (options.splomStash || {}).type); - var axType = coerce('type'); if(axType === '-') { setAutoType(containerOut, options.data); diff --git a/src/traces/splom/defaults.js b/src/traces/splom/defaults.js index 599ee63fc9f..4d0d9c8dc28 100644 --- a/src/traces/splom/defaults.js +++ b/src/traces/splom/defaults.js @@ -61,6 +61,8 @@ function dimensionDefaults(dimIn, dimOut) { if(!(values && values.length)) dimOut.visible = false; else coerce('visible'); + + coerce('axis.type'); } function handleAxisDefaults(traceIn, traceOut, layout, coerce) { @@ -148,7 +150,13 @@ function fillAxisStash(layout, axId, dim) { var stash = layout._splomAxes[axLetter]; if(!(axId in stash)) { - stash[axId] = (dim || {}).label || ''; + var s = stash[axId] = {}; + if(dim) { + s.label = dim.label || ''; + if(dim.visible && dim.axis) { + s.type = dim.axis.type; + } + } } } diff --git a/test/image/mocks/splom_multi-axis-type.json b/test/image/mocks/splom_multi-axis-type.json index c348c2be273..35a817b0a40 100644 --- a/test/image/mocks/splom_multi-axis-type.json +++ b/test/image/mocks/splom_multi-axis-type.json @@ -16,11 +16,13 @@ }, { "label": "bool", - "values": [false, true, true, true, false, true, false, false, false, true] + "values": [false, true, true, true, false, true, false, false, false, true], + "axis": {"type": "category"} }, { "label": "0/1", - "values": [0, 1, 1, 1, 1, 1, 0, 0, 0, 0] + "values": [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], + "axis": {"type": "category"} }, { "label": "string", @@ -31,15 +33,6 @@ ], "layout": { "hovermode": "closest", - "margin": { - "b": 80, - "l": 80, - "r": 30, - "t": 30 - }, - "yaxis2": {"type": "category"}, - "yaxis3": {"type": "category"}, - "xaxis3": {"type": "category"}, - "xaxis4": {"type": "category"} + "margin": {"b": 80, "l": 80, "r": 30, "t": 30} } } diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js index 73243c8495b..f8a3ff281c0 100644 --- a/test/jasmine/tests/splom_test.js +++ b/test/jasmine/tests/splom_test.js @@ -357,6 +357,42 @@ describe('Test splom trace defaults:', function() { expect(fullLayout.xaxis2.type).toBe('date'); expect(fullLayout.yaxis2.type).toBe('date'); }); + + it('axis type in layout takes precedence over dimensions setting', function() { + _supply({ + dimensions: [ + {values: [1, 2, 1], axis: {type: 'category'}}, + {values: [2, 1, 3]} + ] + }, { + xaxis: {type: 'linear'}, + yaxis: {type: 'linear'}, + xaxis2: {type: 'category'}, + yaxis2: {type: 'category'} + }); + + var fullLayout = gd._fullLayout; + expect(fullLayout.xaxis.type).toBe('linear'); + expect(fullLayout.yaxis.type).toBe('linear'); + expect(fullLayout.xaxis2.type).toBe('category'); + expect(fullLayout.yaxis2.type).toBe('category'); + }); + + it('axis type setting should be skipped when dimension is not visible', function() { + _supply({ + dimensions: [ + {visible: false, values: [1, 2, 1], axis: {type: 'category'}}, + {values: [-1, 2, 3], axis: {type: 'category'}}, + ] + }, { + }); + + var fullLayout = gd._fullLayout; + expect(fullLayout.xaxis.type).toBe('linear'); + expect(fullLayout.yaxis.type).toBe('linear'); + expect(fullLayout.xaxis2.type).toBe('category'); + expect(fullLayout.yaxis2.type).toBe('category'); + }); }); describe('Test splom trace calc step:', function() { From 57ddadbef09b4d048eeabe8c833d99eec5abd867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 15 Aug 2018 10:42:10 -0400 Subject: [PATCH 09/13] pass gd to basePlotModule.updateFx .. in case (e.g. for splom) they need to lookup a few things in fullData and calcdata --- src/plot_api/subroutines.js | 2 +- src/plots/cartesian/graph_interact.js | 5 +++-- src/plots/geo/index.js | 3 ++- src/plots/gl2d/index.js | 3 ++- src/plots/gl3d/index.js | 3 ++- src/plots/mapbox/index.js | 3 ++- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index cdd067714bb..9efcca25773 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -520,7 +520,7 @@ exports.doModeBar = function(gd) { for(var i = 0; i < fullLayout._basePlotModules.length; i++) { var updateFx = fullLayout._basePlotModules[i].updateFx; - if(updateFx) updateFx(fullLayout); + if(updateFx) updateFx(gd); } return Plots.previousPromises(gd); diff --git a/src/plots/cartesian/graph_interact.js b/src/plots/cartesian/graph_interact.js index 2ed10621c1c..69dc718bf50 100644 --- a/src/plots/cartesian/graph_interact.js +++ b/src/plots/cartesian/graph_interact.js @@ -151,7 +151,7 @@ exports.initInteractions = function initInteractions(gd) { gd._fullLayout._lasthover.onmousedown(evt); }; - exports.updateFx(fullLayout); + exports.updateFx(gd); }; // Minimal set of update needed on 'modebar' edits. @@ -159,7 +159,8 @@ exports.initInteractions = function initInteractions(gd) { // // Note that changing the axis configuration and/or the fixedrange attribute // should trigger a full initInteractions. -exports.updateFx = function(fullLayout) { +exports.updateFx = function(gd) { + var fullLayout = gd._fullLayout; var cursor = fullLayout.dragmode === 'pan' ? 'move' : 'crosshair'; setCursor(fullLayout._draggers, cursor); }; diff --git a/src/plots/geo/index.js b/src/plots/geo/index.js index d6468d7508d..a393f0b5b82 100644 --- a/src/plots/geo/index.js +++ b/src/plots/geo/index.js @@ -78,7 +78,8 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) } }; -exports.updateFx = function(fullLayout) { +exports.updateFx = function(gd) { + var fullLayout = gd._fullLayout; var subplotIds = fullLayout._subplots[GEO]; for(var i = 0; i < subplotIds.length; i++) { diff --git a/src/plots/gl2d/index.js b/src/plots/gl2d/index.js index 26bb7fdc06e..f56572b8bac 100644 --- a/src/plots/gl2d/index.js +++ b/src/plots/gl2d/index.js @@ -138,7 +138,8 @@ exports.toSVG = function(gd) { } }; -exports.updateFx = function(fullLayout) { +exports.updateFx = function(gd) { + var fullLayout = gd._fullLayout; var subplotIds = fullLayout._subplots.gl2d; for(var i = 0; i < subplotIds.length; i++) { diff --git a/src/plots/gl3d/index.js b/src/plots/gl3d/index.js index 4c094e6519a..3c4dccbfa2e 100644 --- a/src/plots/gl3d/index.js +++ b/src/plots/gl3d/index.js @@ -129,7 +129,8 @@ exports.cleanId = function cleanId(id) { return SCENE + sceneNum; }; -exports.updateFx = function(fullLayout) { +exports.updateFx = function(gd) { + var fullLayout = gd._fullLayout; var subplotIds = fullLayout._subplots[GL3D]; for(var i = 0; i < subplotIds.length; i++) { diff --git a/src/plots/mapbox/index.js b/src/plots/mapbox/index.js index dc19d1c5dca..cda8cd931cd 100644 --- a/src/plots/mapbox/index.js +++ b/src/plots/mapbox/index.js @@ -152,7 +152,8 @@ function findAccessToken(gd, mapboxIds) { throw new Error(constants.noAccessTokenErrorMsg); } -exports.updateFx = function(fullLayout) { +exports.updateFx = function(gd) { + var fullLayout = gd._fullLayout; var subplotIds = fullLayout._subplots[MAPBOX]; for(var i = 0; i < subplotIds.length; i++) { From 15efc7223690615a7bab6ee22d542c7f537208d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 15 Aug 2018 12:19:10 -0400 Subject: [PATCH 10/13] clear additional 'matrixTrace' use by regl-splom for selection ... when restyling dragmode to non-selection modes. Previously, select -> dblclick -> pan lead to a duplication of rendered pts. --- src/traces/splom/base_plot.js | 26 +++++++- test/jasmine/tests/splom_test.js | 104 ++++++++++++++++++++++++++++++- 2 files changed, 128 insertions(+), 2 deletions(-) diff --git a/src/traces/splom/base_plot.js b/src/traces/splom/base_plot.js index 7e747ca0fd5..a91f83b7a67 100644 --- a/src/traces/splom/base_plot.js +++ b/src/traces/splom/base_plot.js @@ -227,6 +227,30 @@ function clean(newFullData, newFullLayout, oldFullData, oldFullLayout, oldCalcda Cartesian.clean(newFullData, newFullLayout, oldFullData, oldFullLayout); } +function updateFx(gd) { + Cartesian.updateFx(gd); + + var fullLayout = gd._fullLayout; + var dragmode = fullLayout.dragmode; + + // unset selection styles when coming out of a selection mode + if(dragmode === 'zoom' || dragmode === 'pan') { + var cd = gd.calcdata; + + for(var i = 0; i < cd.length; i++) { + var cd0 = cd[i][0]; + var trace = cd0.trace; + + if(trace.type === 'splom') { + var scene = cd0.t._scene; + if(scene.selectBatch === null) { + scene.matrix.update(scene.matrixOptions, null); + } + } + } + } +} + module.exports = { name: SPLOM, attr: Cartesian.attr, @@ -237,6 +261,6 @@ module.exports = { plot: plot, drag: drag, clean: clean, - updateFx: Cartesian.updateFx, + updateFx: updateFx, toSVG: Cartesian.toSVG }; diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js index f8a3ff281c0..6c21cfd6ec1 100644 --- a/test/jasmine/tests/splom_test.js +++ b/test/jasmine/tests/splom_test.js @@ -10,6 +10,7 @@ var destroyGraphDiv = require('../assets/destroy_graph_div'); var failTest = require('../assets/fail_test'); var mouseEvent = require('../assets/mouse_event'); var drag = require('../assets/drag'); +var doubleClick = require('../assets/double_click'); var customAssertions = require('../assets/custom_assertions'); var assertHoverLabelContent = customAssertions.assertHoverLabelContent; @@ -918,7 +919,7 @@ describe('@gl Test splom select:', function() { } it('should emit correct event data and draw selection outlines', function(done) { - var fig = require('@mocks/splom_0.json'); + var fig = Lib.extendDeep({}, require('@mocks/splom_0.json')); fig.layout = { dragmode: 'select', width: 400, @@ -1039,4 +1040,105 @@ describe('@gl Test splom select:', function() { .catch(failTest) .then(done); }); + + it('should behave correctly during select->dblclick->pan scenarios', function(done) { + var fig = Lib.extendDeep({}, require('@mocks/splom_0.json')); + fig.layout = { + width: 400, + height: 400, + margin: {l: 0, t: 0, r: 0, b: 0}, + grid: {xgap: 0, ygap: 0} + }; + + var scene; + + function _assert(msg, exp) { + expect(scene.matrix.update).toHaveBeenCalledTimes(exp.updateCnt, 'update cnt'); + expect(scene.matrix.draw).toHaveBeenCalledTimes(exp.drawCnt, 'draw cnt'); + + expect(scene.matrix.traces.length).toBe(exp.matrixTraces, '# of regl-splom traces'); + expect(scene.selectBatch).toEqual(exp.selectBatch, 'selectBatch'); + expect(scene.unselectBatch).toEqual(exp.unselectBatch, 'unselectBatch'); + + scene.matrix.update.calls.reset(); + scene.matrix.draw.calls.reset(); + } + + Plotly.plot(gd, fig).then(function() { + scene = gd.calcdata[0][0].t._scene; + spyOn(scene.matrix, 'update').and.callThrough(); + spyOn(scene.matrix, 'draw').and.callThrough(); + }) + .then(function() { + _assert('base', { + updateCnt: 0, + drawCnt: 0, + matrixTraces: 1, + selectBatch: null, + unselectBatch: null + }); + }) + .then(function() { return Plotly.relayout(gd, 'dragmode', 'select'); }) + .then(function() { + _assert('under dragmode:select', { + updateCnt: 3, // updates positions, viewport and style in 3 calls + drawCnt: 1, // results in a 'plot' edit + matrixTraces: 2, + selectBatch: [], + unselectBatch: [] + }); + }) + .then(function() { return _select([[5, 5], [100, 100]]); }) + .then(function() { + _assert('after selection', { + updateCnt: 0, + drawCnt: 1, + matrixTraces: 2, + selectBatch: [1], + unselectBatch: [0, 2] + }); + }) + .then(function() { return Plotly.relayout(gd, 'dragmode', 'pan'); }) + .then(function() { + _assert('under dragmode:pan with active selection', { + updateCnt: 0, + drawCnt: 0, // nothing here, this is a 'modebar' edit + matrixTraces: 2, + selectBatch: [1], + unselectBatch: [0, 2] + }); + }) + .then(function() { return Plotly.relayout(gd, 'dragmode', 'select'); }) + .then(function() { + _assert('back dragmode:select', { + updateCnt: 3, + drawCnt: 1, // a 'plot' edit (again) + matrixTraces: 2, + selectBatch: [1], + unselectBatch: [0, 2] + }); + }) + .then(function() { return doubleClick(100, 100); }) + .then(function() { + _assert('after dblclick clearing selection', { + updateCnt: 0, + drawCnt: 1, + matrixTraces: 2, + selectBatch: null, + unselectBatch: [] + }); + }) + .then(function() { return Plotly.relayout(gd, 'dragmode', 'pan'); }) + .then(function() { + _assert('under dragmode:pan with NO active selection', { + updateCnt: 1, // to clear off 1 matrixTrace + drawCnt: 0, + matrixTraces: 1, // N.B. back to '1' here + selectBatch: null, + unselectBatch: [] + }); + }) + .catch(failTest) + .then(done); + }); }); From 182390442ee0843e022e32a311baf138a18c4570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 15 Aug 2018 12:26:31 -0400 Subject: [PATCH 11/13] log info when skipping splom dim of conflicting axis types --- src/traces/splom/index.js | 5 ++++- test/jasmine/tests/splom_test.js | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/traces/splom/index.js b/src/traces/splom/index.js index 738ac23280e..eb96add9ecf 100644 --- a/src/traces/splom/index.js +++ b/src/traces/splom/index.js @@ -62,7 +62,10 @@ function calc(gd, trace) { ya = AxisIDs.getFromId(gd, trace._diag[i][1]); // if corresponding x & y axes don't have matching types, skip dim - if(xa && ya && xa.type !== ya.type) continue; + if(xa && ya && xa.type !== ya.type) { + Lib.log('Skipping splom dimension ' + i + ' with conflicting axis types'); + continue; + } if(xa) { makeCalcdata(xa, dim); diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js index 6c21cfd6ec1..0ec0a5de4e2 100644 --- a/test/jasmine/tests/splom_test.js +++ b/test/jasmine/tests/splom_test.js @@ -409,6 +409,8 @@ describe('Test splom trace calc step:', function() { } it('should skip dimensions with conflicting axis types', function() { + spyOn(Lib, 'log').and.callThrough(); + _calc({ dimensions: [{ values: [1, 2, 3] @@ -424,6 +426,8 @@ describe('Test splom trace calc step:', function() { expect(cd.t._scene.matrixOptions.data).toBeCloseTo2DArray([[2, 1, 2]]); expect(cd.t.visibleDims).toEqual([1]); + expect(Lib.log).toHaveBeenCalledTimes(1); + expect(Lib.log).toHaveBeenCalledWith('Skipping splom dimension 0 with conflicting axis types'); }); }); From 390f29202e4230035e094e9731f4f643e5ca9ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 15 Aug 2018 12:43:38 -0400 Subject: [PATCH 12/13] add mock of splom with conflicting axis types --- .../baselines/splom_mismatched-axis-types.png | Bin 0 -> 38975 bytes .../mocks/splom_mismatched-axis-types.json | 52 ++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 test/image/baselines/splom_mismatched-axis-types.png create mode 100644 test/image/mocks/splom_mismatched-axis-types.json diff --git a/test/image/baselines/splom_mismatched-axis-types.png b/test/image/baselines/splom_mismatched-axis-types.png new file mode 100644 index 0000000000000000000000000000000000000000..cb8d5793a81806fa06800a7e0a95b90a1406885d GIT binary patch literal 38975 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 see points in the \"bool\" dimension
as it has conflicting axis types", + "borderwidth": 1, + "bordercolor": "black", + "borderpad": 5 + }] + } +} From adb0004569783f5dffaae5fcda61601faa7d737e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 15 Aug 2018 13:51:51 -0400 Subject: [PATCH 13/13] use 'j' in value loop ... to avoid confusing with i in dimension loop in outer-scope. --- src/traces/splom/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/traces/splom/index.js b/src/traces/splom/index.js index eb96add9ecf..902646cb17a 100644 --- a/src/traces/splom/index.js +++ b/src/traces/splom/index.js @@ -47,8 +47,8 @@ function calc(gd, trace) { vcalendar: trace.calendar }, 'v'); - for(var i = 0; i < ccol.length; i++) { - ccol[i] = ccol[i] === BADNUM ? NaN : ccol[i]; + for(var j = 0; j < ccol.length; j++) { + ccol[j] = ccol[j] === BADNUM ? NaN : ccol[j]; } cdata.push(ccol); ldata.push(ax.type === 'log' ? Lib.simpleMap(ccol, ax.c2l) : ccol);