From ee5fcea9ff3d374efd675d242ada2eb8c0daa054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 3 Oct 2018 17:50:13 -0400 Subject: [PATCH 1/8] :hocho: console.log from parcats_test.js --- test/jasmine/tests/parcats_test.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/jasmine/tests/parcats_test.js b/test/jasmine/tests/parcats_test.js index 6fc5070ba53..c4c3fb92873 100644 --- a/test/jasmine/tests/parcats_test.js +++ b/test/jasmine/tests/parcats_test.js @@ -723,7 +723,6 @@ describe('Drag to reordered dimensions', function() { Plotly.newPlot(gd, mock) .then(function() { - console.log(gd.data); restyleCallback = jasmine.createSpy('restyleCallback'); gd.on('plotly_restyle', restyleCallback); @@ -1229,9 +1228,6 @@ describe('Click events', function() { /** @type {ParcatsViewModel} */ var parcatsViewModel = d3.select('g.trace.parcats').datum(); - console.log(gd.data[0]); - console.log(parcatsViewModel.hoverinfoItems); - gd.on('plotly_click', function(data) { clickData = data; }); From 6bc71574eeeb8342770a453039c28e8ec3f5f857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 3 Oct 2018 17:52:30 -0400 Subject: [PATCH 2/8] add parcats mock to Plotly.react noop tests and fix it ... by storing 'calc'ed categoryarray and ticktext as using '_', so that Plots.supplyDefaults doesn't pickup spurious changes. --- src/traces/parcats/calc.js | 14 +++++++------- test/jasmine/assets/mock_lists.js | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/traces/parcats/calc.js b/src/traces/parcats/calc.js index d52bbc4fca7..b2517abed61 100644 --- a/src/traces/parcats/calc.js +++ b/src/traces/parcats/calc.js @@ -174,8 +174,8 @@ module.exports = function calc(gd, trace) { var cats = dimensionModels[d].categories; if(cats[catInd] === undefined) { - var catValue = trace.dimensions[containerInd].categoryarray[catInd]; - var catLabel = trace.dimensions[containerInd].ticktext[catInd]; + var catValue = trace.dimensions[containerInd]._categoryarray[catInd]; + var catLabel = trace.dimensions[containerInd]._ticktext[catInd]; cats[catInd] = createCategoryModel(d, catInd, catValue, catLabel); } @@ -480,19 +480,19 @@ function validateDimensionDisplayInds(trace) { function validateCategoryProperties(dim, uniqueInfoDim) { // Update categoryarray - dim.categoryarray = uniqueInfoDim.uniqueValues; + dim._categoryarray = uniqueInfoDim.uniqueValues; // Handle ticktext if(dim.ticktext === null || dim.ticktext === undefined) { - dim.ticktext = []; + dim._ticktext = []; } else { // Shallow copy to avoid modifying input array - dim.ticktext = dim.ticktext.slice(); + dim._ticktext = dim.ticktext.slice(); } // Extend ticktext with elements from uniqueInfoDim.uniqueValues - for(var i = dim.ticktext.length; i < uniqueInfoDim.uniqueValues.length; i++) { - dim.ticktext.push(uniqueInfoDim.uniqueValues[i]); + for(var i = dim._ticktext.length; i < uniqueInfoDim.uniqueValues.length; i++) { + dim._ticktext.push(uniqueInfoDim.uniqueValues[i]); } } diff --git a/test/jasmine/assets/mock_lists.js b/test/jasmine/assets/mock_lists.js index c54d91a4e00..3e59cc7bbc3 100644 --- a/test/jasmine/assets/mock_lists.js +++ b/test/jasmine/assets/mock_lists.js @@ -27,6 +27,7 @@ var svgMockList = [ ['range_selector_style', require('@mocks/range_selector_style.json')], ['range_slider_multiple', require('@mocks/range_slider_multiple.json')], ['sankey_energy', require('@mocks/sankey_energy.json')], + ['parcats_basic', require('@mocks/parcats_basic.json')], ['scattercarpet', require('@mocks/scattercarpet.json')], ['shapes', require('@mocks/shapes.json')], ['splom_iris', require('@mocks/splom_iris.json')], From fc7c7464b86e492fbfbd8dd0c7f8d7ba0ffcda5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 3 Oct 2018 18:03:49 -0400 Subject: [PATCH 3/8] add tolerance to make new pie tests pass on etpinard's laptop --- test/jasmine/tests/pie_test.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/jasmine/tests/pie_test.js b/test/jasmine/tests/pie_test.js index 2880a514f5b..24c85e494e1 100644 --- a/test/jasmine/tests/pie_test.js +++ b/test/jasmine/tests/pie_test.js @@ -198,8 +198,8 @@ describe('Pie traces:', function() { expect(title.size()).toBe(1); var titlePos = getClientPosition('g.titletext'); var pieCenterPos = getClientPosition('g.trace'); - expect(Math.abs(titlePos[0] - pieCenterPos[0])).toBeLessThan(2); - expect(Math.abs(titlePos[1] - pieCenterPos[1])).toBeLessThan(2); + expect(Math.abs(titlePos[0] - pieCenterPos[0])).toBeLessThan(4); + expect(Math.abs(titlePos[1] - pieCenterPos[1])).toBeLessThan(4); }) .catch(failTest) .then(done); @@ -229,15 +229,15 @@ describe('Pie traces:', function() { var pieBox = d3.select('g.trace').node().getBoundingClientRect(); var radius = 0.1 * Math.min(pieBox.width / 2, pieBox.height / 2); var pieCenterPos = getClientPosition('g.trace'); - // unfortunately boundingClientRect is inaccurate and so we allow an error of 2 + // unfortunately boundingClientRect is inaccurate and so we allow an error of 3 expect(_verifyPointInCircle(titleBox.left, titleBox.top, pieCenterPos, radius)) - .toBeLessThan(2); + .toBeLessThan(3); expect(_verifyPointInCircle(titleBox.right, titleBox.top, pieCenterPos, radius)) - .toBeLessThan(2); + .toBeLessThan(3); expect(_verifyPointInCircle(titleBox.left, titleBox.bottom, pieCenterPos, radius)) - .toBeLessThan(2); + .toBeLessThan(3); expect(_verifyPointInCircle(titleBox.right, titleBox.bottom, pieCenterPos, radius)) - .toBeLessThan(2); + .toBeLessThan(3); }) .catch(failTest) .then(done); From f4227e433e45fc596bd6a8e7928729a576a893c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 3 Oct 2018 18:07:20 -0400 Subject: [PATCH 4/8] add tolerance Drawing.bbox on window.scroll test ... to make them pass on etpinard's laptop on using Ubuntu 18.04 and Chrome 69 --- test/jasmine/tests/drawing_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jasmine/tests/drawing_test.js b/test/jasmine/tests/drawing_test.js index 414f2239b26..257e074e3eb 100644 --- a/test/jasmine/tests/drawing_test.js +++ b/test/jasmine/tests/drawing_test.js @@ -363,7 +363,7 @@ describe('Drawing', function() { 'width', 'left', 'right' ].forEach(function(dim) { // give larger dimensions some extra tolerance - var tol = Math.max(expected[dim] / 10, 3); + var tol = Math.max(expected[dim] / 10, 3.5); expect(actual[dim]).toBeWithin(expected[dim], tol, dim); }); } From e43d0f85149570e9d8194bc1383ebd40465fdf9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 3 Oct 2018 18:15:59 -0400 Subject: [PATCH 5/8] add tolerance in layout slider push margins test ... to make it pass on etpinard's laptop running Ubuntu 18.04 and Chrome 69. --- test/jasmine/tests/sliders_test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/jasmine/tests/sliders_test.js b/test/jasmine/tests/sliders_test.js index ff3851ca24d..5438273dbd4 100644 --- a/test/jasmine/tests/sliders_test.js +++ b/test/jasmine/tests/sliders_test.js @@ -334,13 +334,13 @@ describe('sliders interactions', function() { d3.select(gd).selectAll('.slider-group').each(function(d, i) { var sliderBB = this.getBoundingClientRect(); var gdBB = gd.getBoundingClientRect(); + if(i === 0) { expect(sliderBB.left - gdBB.left) - .toBeWithin(12, 3, 'left: ' + msg); - } - else { + .toBeWithin(12, 5.1, 'left: ' + msg); + } else { expect(gdBB.bottom - sliderBB.bottom) - .toBeWithin(8, 3, 'bottom: ' + msg); + .toBeWithin(8, 5.1, 'bottom: ' + msg); } }); } From 3bb0a774623d32bd48c6db854f4e3d8b7ffcf0cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 5 Oct 2018 11:54:21 -0400 Subject: [PATCH 6/8] fix copy :pasta: docstring --- src/traces/parcats/calc.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/traces/parcats/calc.js b/src/traces/parcats/calc.js index b2517abed61..5482d2423da 100644 --- a/src/traces/parcats/calc.js +++ b/src/traces/parcats/calc.js @@ -471,9 +471,7 @@ function validateDimensionDisplayInds(trace) { /** - * Validate the requested display order for the dimensions. - * If the display order is a permutation of 0 through dimensions.length - 1 then leave it alone. Otherwise, repalce - * the display order with the dimension order + * Update category properties based on the unique values found for this dimension * @param {Object} dim * @param {UniqueInfo} uniqueInfoDim */ From 157a6e28aa3d79d17320bddef5029e1804306420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 5 Oct 2018 11:55:42 -0400 Subject: [PATCH 7/8] don't mutate dimensions[i].displayindex in calc ... so that Plotly.react works on parcats mocks that have "bad" displayindex values --- src/traces/parcats/calc.js | 23 ++++++++++++------ .../baselines/parcats_bad-displayindex.png | Bin 0 -> 47980 bytes .../image/mocks/parcats_bad-displayindex.json | 17 +++++++++++++ test/jasmine/assets/mock_lists.js | 2 +- 4 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 test/image/baselines/parcats_bad-displayindex.png create mode 100644 test/image/mocks/parcats_bad-displayindex.json diff --git a/src/traces/parcats/calc.js b/src/traces/parcats/calc.js index 5482d2423da..81bc615a33c 100644 --- a/src/traces/parcats/calc.js +++ b/src/traces/parcats/calc.js @@ -160,7 +160,7 @@ module.exports = function calc(gd, trace) { // Array of DimensionModel objects var dimensionModels = trace.dimensions.filter(visible).map(function(di, i) { - return createDimensionModel(i, di._index, di.displayindex, di.label, totalCount); + return createDimensionModel(i, di._index, di._displayindex, di.label, totalCount); }); @@ -456,16 +456,23 @@ function getUniqueInfo(values, uniqueValues) { /** * Validate the requested display order for the dimensions. - * If the display order is a permutation of 0 through dimensions.length - 1 then leave it alone. Otherwise, repalce - * the display order with the dimension order + * If the display order is a permutation of 0 through dimensions.length - 1, link to _displayindex + * Otherwise, replace the display order with the dimension order * @param {Object} trace */ function validateDimensionDisplayInds(trace) { - var displayInds = trace.dimensions.filter(visible).map(function(dim) {return dim.displayindex;}); - if(!isRangePermutation(displayInds)) { - trace.dimensions.filter(visible).forEach(function(dim, i) { - dim.displayindex = i; - }); + var visibleDims = Lib.filterVisible(trace.dimensions); + var displayInds = visibleDims.map(function(d) { return d.displayindex; }); + var i; + + if(isRangePermutation(displayInds)) { + for(i = 0; i < visibleDims.length; i++) { + visibleDims[i]._displayindex = visibleDims[i].displayindex; + } + } else { + for(i = 0; i < visibleDims.length; i++) { + visibleDims[i]._displayindex = i; + } } } diff --git a/test/image/baselines/parcats_bad-displayindex.png b/test/image/baselines/parcats_bad-displayindex.png new file mode 100644 index 0000000000000000000000000000000000000000..1b02d451a15a36c610d4a4206a3ce4271e530905 GIT binary patch literal 47980 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 ?Qcnl`D7~WygF%MW7m)wepX@yKNiuDsWEUJ z^rYu1Do_~Z71|Uo(qIY8(gsiG8}AWwthRJ3cf{vsntfc;$oqBJ;@A572Zkrt%`h&d zQ>Cgaj{^`>3Q9D;QjgOT^!mJ(!_vY!s^P8;0?9MGQ$NcS4sBh*4CF^03= z>S4B=)+6xjF>+cXqn3234S~R@L=EEC{<|r)kJ>@pS0d(DP;5V2{gkmw!ktOq@e%S? zsA*=-#$5K6Zuut0^At~ZZmk$g&6{D@6cIk`I)TH8<5c=2IhXzIl!Px2WkbS}GcVI~sz>;J=9uf9paLi-oC9NJXdv!j)eWLN892~MS4 z8jW*Pyid$9&l&K$OA}I(a(F8y|Uu9@GKrJvks3=jP-O zAuzO)n2vsbH|r+}zn!2z9A+;|V0Kpeo_dccR*g2_9zBMVPSi*~tew@U#5aJ7V<(SE zpMl!8(29k@uy3g;)`TaX>%EQ+UU#>$+>wn^Ig8$(KKUM!++WIaY4G6-lm;c}uN)oA z83{-pf{{z7Z{O-`Q6wg5a%4QPA-(D-)_1>J09qr;6}G&^YG`9K0I;4yGXxJYf~SS|2% zfxpiYI%53OLD!sD0Oo!dCp9^5Lbc{*;w^@FgL_yH{)hz%*$A_X!WL_2@6%mBRCz=G zR6lnlne38yDI?aXp4WmU2n+i#2+L?hb{`K09(MS#v(C-jV{Cr5(hI*CKQ&O{{Sx4j#_!7e^TF1ZzXM07NvY<}>h?P{ zfZn>^a`>f87CTQ5^-z4M=?955Mm80To#>SCA_W=0tZcyuQh{DXu-!F#v;R1u^KojI zff2LcxVw|zaWDKm+Oj`6ov~^_wz9Nl;Fyv?^SLt*VRl*c?Lde`LjZ&8i^@y?-)7jT zvhkUbZiME%m-8KgR5G$-4)kB5;B?}DDt`+HL>1`Ja_5qt8=q}=U1}cTytakJa?;$G zr#(>wRx9TWBnqe6(i)K?=$XkHN4%T~(_y7(lnyq0YF@{LZGb@0!$vl8}SC@fdN^QuEYhzu3b7JOo?mmrs1) zf61nDzl&iH$Qzt;-Eag?9toZ_;w)O|oon*wSXXj_KTPu25nPm)i;};>V0Kf_J!0Kz z6PX?H`L~65bnFLZ@s#$(TZX6IiH17wvRAo_Zk7k(T-QJI?OdOPFHy2(#;V8ygrfkp;vZK0<_M>ssfUt0 z_i~~K3s#Kx-MD6B32-K5`4abjTAW)@e}1~Ue>iUN;bbCLdFEaXV3bDj74}_D|5VhI zpC9jtKf+bVSHR)lMF6TBLG4OgM6UxbFD1IS#Uma7nm4aJMO0}}{{0b^J;Cdr9)hR! zwMOx)5QB~HmAU+(EX-EII6y@Wg&3sl;urZa27}iuz`H<;kv8u4s*ktZ>#q)KPcDx= z@B0EBxuZT&NoS8@DBxYZA?9y4zX$iqDFaG~S5vZYwkTZZYI(aqqwLc}=C#*7PCZz1oP)^0M@bEcAzGOBM6Y#}`aj+lCKYdxfqQ-@7_3{K72Z z=8IIHYy+rQ0eX*1In^DzUCi*lJZ-&S!GRM{s0tMdr>Ue#majqtBY3S9`OS)|JQ z1ABxR1cjPPJgFuYT4<={FWCfOghFS1T)W~s?p)i~jmLW}OY-x?x|d?f4?-3?I>;0g zP`a0Zm^a;<-a4?**CDdG@$K7qjt>bHKf9Mj$9I@Op_bX1@}-#e^bk7ZOA4u~DX=it z8OlwTyWx0OKGYAx*CYMEAbH+$g7c{rU >Cf+c1Xlt+Qc^opzh3ci+eYyYrb0Tv@ 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 N)Ng4kmnuC7`5%Z|2k!s? literal 0 HcmV?d00001 diff --git a/test/image/mocks/parcats_bad-displayindex.json b/test/image/mocks/parcats_bad-displayindex.json new file mode 100644 index 00000000000..f8ab51ab978 --- /dev/null +++ b/test/image/mocks/parcats_bad-displayindex.json @@ -0,0 +1,17 @@ +{ + "data": [ + {"type": "parcats", + "dimensions": [ + {"label": "One", "values": [1, 1, 2, 1, 2, 1, 1, 2, 1], + "displayindex": 1, "categoryarray": [1, 2], "ticktext": ["One", "Two"]}, + {"label": "Two", "values": ["A", "B", "A", "B", "C", "C", "A", "B", "C"], + "displayindex": 2, "categoryarray": ["B", "A", "C"]}, + {"label": "Three", "values": [11, 11, 11, 11, 11, 11, 11, 11, 11], "displayindex": 1}]} + ], + "layout": { + "height": 602, + "width": 592, + "margin": { + "l": 40, "r": 40, "t": 50, "b": 40 + }} +} diff --git a/test/jasmine/assets/mock_lists.js b/test/jasmine/assets/mock_lists.js index 3e59cc7bbc3..2b0a4e8f61f 100644 --- a/test/jasmine/assets/mock_lists.js +++ b/test/jasmine/assets/mock_lists.js @@ -27,7 +27,7 @@ var svgMockList = [ ['range_selector_style', require('@mocks/range_selector_style.json')], ['range_slider_multiple', require('@mocks/range_slider_multiple.json')], ['sankey_energy', require('@mocks/sankey_energy.json')], - ['parcats_basic', require('@mocks/parcats_basic.json')], + ['parcats_bad-displayindex', require('@mocks/parcats_bad-displayindex.json')], ['scattercarpet', require('@mocks/scattercarpet.json')], ['shapes', require('@mocks/shapes.json')], ['splom_iris', require('@mocks/splom_iris.json')], From 24af02a7ded0d15fe750e8876b049c23adb66b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 5 Oct 2018 14:18:14 -0400 Subject: [PATCH 8/8] filter visible dimensions just once --- src/traces/parcats/calc.js | 43 +++++++++----------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/src/traces/parcats/calc.js b/src/traces/parcats/calc.js index 81bc615a33c..70b8f8a277f 100644 --- a/src/traces/parcats/calc.js +++ b/src/traces/parcats/calc.js @@ -17,11 +17,6 @@ var filterUnique = require('../../lib/filter_unique.js'); var Drawing = require('../../components/drawing'); var Lib = require('../../lib'); - -function visible(dimension) { return !('visible' in dimension) || dimension.visible; } - -// Exports -// ======= /** * Create a wrapped ParcatsModel object from trace * @@ -31,24 +26,18 @@ function visible(dimension) { return !('visible' in dimension) || dimension.visi * @return {Array.} */ module.exports = function calc(gd, trace) { + var visibleDims = Lib.filterVisible(trace.dimensions); - // Process inputs - // -------------- - if(trace.dimensions.filter(visible).length === 0) { - // No visible dimensions specified. Nothing to compute - return []; - } + if(visibleDims.length === 0) return []; - // Compute unique information - // -------------------------- - // UniqueInfo per dimension - var uniqueInfoDims = trace.dimensions.filter(visible).map(function(dim) { + var uniqueInfoDims = visibleDims.map(function(dim) { var categoryValues; if(dim.categoryorder === 'trace') { // Use order of first occurrence in trace categoryValues = null; } else if(dim.categoryorder === 'array') { - // Use categories specified in `categoryarray` first, then add extra to the end in trace order + // Use categories specified in `categoryarray` first, + // then add extra to the end in trace order categoryValues = dim.categoryarray; } else { // Get all categories up front so we can order them @@ -61,8 +50,6 @@ module.exports = function calc(gd, trace) { return getUniqueInfo(dim.values, categoryValues); }); - // Process counts - // -------------- var counts, count, totalCount; @@ -72,13 +59,9 @@ module.exports = function calc(gd, trace) { counts = [trace.counts]; } - // Validate dimension display order - // -------------------------------- - validateDimensionDisplayInds(trace); + validateDimensionDisplayInds(visibleDims); - // Validate category display order - // ------------------------------- - trace.dimensions.filter(visible).forEach(function(dim, dimInd) { + visibleDims.forEach(function(dim, dimInd) { validateCategoryProperties(dim, uniqueInfoDims[dimInd]); }); @@ -111,7 +94,7 @@ module.exports = function calc(gd, trace) { // Number of values and counts // --------------------------- - var numValues = trace.dimensions.filter(visible)[0].values.length; + var numValues = visibleDims[0].values.length; // Build path info // --------------- @@ -155,11 +138,7 @@ module.exports = function calc(gd, trace) { updatePathModel(pathModels[pathKey], valueInd, count); } - // Build categories info - // --------------------- - - // Array of DimensionModel objects - var dimensionModels = trace.dimensions.filter(visible).map(function(di, i) { + var dimensionModels = visibleDims.map(function(di, i) { return createDimensionModel(i, di._index, di._displayindex, di.label, totalCount); }); @@ -216,7 +195,6 @@ module.exports = function calc(gd, trace) { */ function createParcatsModel(dimensions, paths, count) { var maxCats = dimensions - .filter(visible) .map(function(d) {return d.categories.length;}) .reduce(function(v1, v2) {return Math.max(v1, v2);}); return {dimensions: dimensions, paths: paths, trace: undefined, maxCats: maxCats, count: count}; @@ -460,8 +438,7 @@ function getUniqueInfo(values, uniqueValues) { * Otherwise, replace the display order with the dimension order * @param {Object} trace */ -function validateDimensionDisplayInds(trace) { - var visibleDims = Lib.filterVisible(trace.dimensions); +function validateDimensionDisplayInds(visibleDims) { var displayInds = visibleDims.map(function(d) { return d.displayindex; }); var i;