From f0134268ee39d129b66f78f778f97f194dffd322 Mon Sep 17 00:00:00 2001 From: hannahker Date: Thu, 15 Sep 2022 13:43:02 -0400 Subject: [PATCH 01/10] Add mock and exploratory code --- src/plot_api/subroutines.js | 12 ++++ src/plots/cartesian/axes.js | 21 +++++-- test/image/mocks/multiple_axes_multiple.json | 12 ++-- test/image/mocks/z-multiple-yaxes-layout.json | 56 +++++++++++++++++++ 4 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 test/image/mocks/z-multiple-yaxes-layout.json diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index 03e775879a7..992e86d63fa 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -713,3 +713,15 @@ exports.drawMarginPushers = function(gd) { Registry.getComponentMethod('updatemenus', 'draw')(gd); Registry.getComponentMethod('colorbar', 'draw')(gd); }; + +// function getAxDepth(ax) { +// var depth = null; +// if (ax.type == 'multicategory') { +// depth = majorTickSigns[4] * (getLabelLevelBbox('tick2')[ax.side] - mainLinePosition); + +// } else if(ax.title.hasOwnProperty('standoff')) { +// depth = majorTickSigns[4] * (getLabelLevelBbox()[ax.side] - mainLinePosition); +// } + +// } + diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 4a5bed02b15..47107a9229a 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2248,16 +2248,23 @@ axes.draw = function(gd, arg, opts) { var axList = (!arg || arg === 'redraw') ? axes.listIds(gd) : arg; + var allDepths = [0] // Or dict w keys/values? + return Lib.syncOrAsync(axList.map(function(axId) { return function() { if(!axId) return; var ax = axes.getFromId(gd, axId); - var axDone = axes.drawOne(gd, ax, opts); + var axDone = axes.drawOne(gd, ax, opts, allDepths); + var depth = ax._depth + console.log(depth) + //var depthPrev = allDepths.pop + allDepths.push(depth) + ax._r = ax.range.slice(); ax._rl = Lib.simpleMap(ax._r, ax.r2l); - + //debugger; return axDone; }; })); @@ -2290,11 +2297,12 @@ axes.draw = function(gd, arg, opts) { * - ax._depth (when required only): * - and calls ax.setScale */ -axes.drawOne = function(gd, ax, opts) { +axes.drawOne = function(gd, ax, opts, allDepths) { + //debugger; opts = opts || {}; var i, sp, plotinfo; - + console.log(allDepths) ax.setScale(); var fullLayout = gd._fullLayout; @@ -2541,6 +2549,7 @@ axes.drawOne = function(gd, ax, opts) { var s = ax.side.charAt(0); var sMirror = OPPOSITE_SIDE[ax.side].charAt(0); var pos = axes.getPxPosition(gd, ax); + console.log(pos) var outsideTickLen = outsideTicks ? ax.ticklen : 0; var llbbox; @@ -2646,7 +2655,7 @@ axes.drawOne = function(gd, ax, opts) { ) { seq.push(function() { return drawTitle(gd, ax); }); } - + console.log(seq) return Lib.syncOrAsync(seq); }; @@ -3764,7 +3773,7 @@ function drawDividers(gd, ax, opts) { * - {number} position * @return {number} */ -axes.getPxPosition = function(gd, ax) { +axes.getPxPosition = function(gd, ax, offset) { var gs = gd._fullLayout._size; var axLetter = ax._id.charAt(0); var side = ax.side; diff --git a/test/image/mocks/multiple_axes_multiple.json b/test/image/mocks/multiple_axes_multiple.json index 4afadf4ce6a..3ab5872527a 100644 --- a/test/image/mocks/multiple_axes_multiple.json +++ b/test/image/mocks/multiple_axes_multiple.json @@ -80,7 +80,8 @@ "color": "#1f77b4" }, "text": "yaxis title" - } + }, + "automargin": true }, "yaxis2": { "title": { @@ -95,7 +96,8 @@ "anchor": "free", "side": "left", "position": 0.15, - "overlaying": "y" + "overlaying": "y", + "automargin": true }, "yaxis3": { "title": { @@ -109,7 +111,8 @@ }, "anchor": "x", "side": "right", - "overlaying": "y" + "overlaying": "y", + "automargin": true }, "yaxis4": { "title": { @@ -124,7 +127,8 @@ "anchor": "free", "side": "right", "position": 0.85, - "overlaying": "y" + "overlaying": "y", + "automargin": true } } } diff --git a/test/image/mocks/z-multiple-yaxes-layout.json b/test/image/mocks/z-multiple-yaxes-layout.json new file mode 100644 index 00000000000..29a096ed9b0 --- /dev/null +++ b/test/image/mocks/z-multiple-yaxes-layout.json @@ -0,0 +1,56 @@ +{ + "data": [ + { + "x": [ + 1, + 2, + 3 + ], + "y": [ + 4, + 5, + 6 + ], + "name": "yaxis1 data", + "type": "scatter" + }, + { + "x": [ + 2, + 3, + 4 + ], + "y": [ + 40, + 50, + 60 + ], + "name": "yaxis2 data", + "yaxis": "y2", + "type": "scatter" + } + ], + "layout": { + "title": { + "text": "multiple y-axes example" + }, + "width": 800, + "xaxis": { + "domain": [ + 0.5, + 1 + ] + }, + "yaxis": { + "title": {"text": "yaxis title"}, + "automargin": true, + "anchor": "free" + }, + "yaxis2": { + "title": {"text": "yaxis2 title"}, + "anchor": "free", + "overlaying": "y", + "automargin": true + } + } +} From 7e45c3b69ef6874d37a915b7e31706f8151cfc41 Mon Sep 17 00:00:00 2001 From: hannahker Date: Sun, 18 Sep 2022 17:10:33 -0700 Subject: [PATCH 02/10] MVP with hard coded title offset --- src/plot_api/subroutines.js | 3 +- src/plots/cartesian/axes.js | 27 ++++++------ test/image/mocks/z-multiple-yaxes-layout.json | 42 +++++++++++++++++++ 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index 992e86d63fa..c222fb0306e 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -69,6 +69,7 @@ function lsInner(gd) { function getLinePosition(ax, counterAx, side) { var lwHalf = ax._lw / 2; + var xshift = ax.position > 0 ? 0 : ax._xshift; if(ax._id.charAt(0) === 'x') { if(!counterAx) return gs.t + gs.h * (1 - (ax.position || 0)) + (lwHalf % 1); @@ -76,7 +77,7 @@ function lsInner(gd) { return counterAx._offset + counterAx._length + pad + lwHalf; } - if(!counterAx) return gs.l + gs.w * (ax.position || 0) + (lwHalf % 1); + if(!counterAx) return gs.l + gs.w * (ax.position || 0) + (lwHalf % 1) + xshift; else if(side === 'right') return counterAx._offset + counterAx._length + pad + lwHalf; return counterAx._offset - pad - lwHalf; } diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 47107a9229a..1a8b783951d 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2257,14 +2257,11 @@ axes.draw = function(gd, arg, opts) { var ax = axes.getFromId(gd, axId); var axDone = axes.drawOne(gd, ax, opts, allDepths); - var depth = ax._depth - console.log(depth) - //var depthPrev = allDepths.pop + var depth = ax._depth > 0 ? (ax._depth + 50) : ax._depth; // Add offset to account for title size allDepths.push(depth) ax._r = ax.range.slice(); ax._rl = Lib.simpleMap(ax._r, ax.r2l); - //debugger; return axDone; }; })); @@ -2302,9 +2299,11 @@ axes.drawOne = function(gd, ax, opts, allDepths) { opts = opts || {}; var i, sp, plotinfo; - console.log(allDepths) + //('All depths:') + //console.log(allDepths) + ax.setScale(); - + var fullLayout = gd._fullLayout; var axId = ax._id; var axLetter = axId.charAt(0); @@ -2338,6 +2337,8 @@ axes.drawOne = function(gd, ax, opts, allDepths) { // (touching either the tick label or ticks) // depth can be expansive to compute, so we only do so when required ax._depth = null; + // Shift the sum of existing axes depth + ax._xshift = allDepths.reduce((a, b) => a + b) // calcLabelLevelBbox can be expensive, // so make sure to not call it twice during the same Axes.drawOne call @@ -2549,7 +2550,6 @@ axes.drawOne = function(gd, ax, opts, allDepths) { var s = ax.side.charAt(0); var sMirror = OPPOSITE_SIDE[ax.side].charAt(0); var pos = axes.getPxPosition(gd, ax); - console.log(pos) var outsideTickLen = outsideTicks ? ax.ticklen : 0; var llbbox; @@ -2655,7 +2655,6 @@ axes.drawOne = function(gd, ax, opts, allDepths) { ) { seq.push(function() { return drawTitle(gd, ax); }); } - console.log(seq) return Lib.syncOrAsync(seq); }; @@ -3773,12 +3772,14 @@ function drawDividers(gd, ax, opts) { * - {number} position * @return {number} */ -axes.getPxPosition = function(gd, ax, offset) { +axes.getPxPosition = function(gd, ax) { + var gs = gd._fullLayout._size; var axLetter = ax._id.charAt(0); var side = ax.side; var anchorAxis; + var xshift = ax.position > 0 ? 0 : ax._xshift; if(ax.anchor !== 'free') { anchorAxis = ax._anchorAxis; } else if(axLetter === 'x') { @@ -3788,16 +3789,15 @@ axes.getPxPosition = function(gd, ax, offset) { }; } else if(axLetter === 'y') { anchorAxis = { - _offset: gs.l + (ax.position || 0) * gs.w, + _offset: (gs.l + (ax.position || 0) * gs.w) + xshift, _length: 0 }; } - if(side === 'top' || side === 'left') { return anchorAxis._offset; } else if(side === 'bottom' || side === 'right') { return anchorAxis._offset + anchorAxis._length; - } + } }; /** @@ -3841,6 +3841,7 @@ function approxTitleDepth(ax) { * - {boolean} showticklabels */ function drawTitle(gd, ax) { + debugger; var fullLayout = gd._fullLayout; var axId = ax._id; var axLetter = axId.charAt(0); @@ -3889,7 +3890,7 @@ function drawTitle(gd, ax) { x = (ax.side === 'right') ? pos + titleStandoff : pos - titleStandoff; transform = {rotate: '-90', offset: 0}; } - + debugger; var avoid; if(ax.type !== 'multicategory') { diff --git a/test/image/mocks/z-multiple-yaxes-layout.json b/test/image/mocks/z-multiple-yaxes-layout.json index 29a096ed9b0..f0115ebee85 100644 --- a/test/image/mocks/z-multiple-yaxes-layout.json +++ b/test/image/mocks/z-multiple-yaxes-layout.json @@ -28,6 +28,36 @@ "name": "yaxis2 data", "yaxis": "y2", "type": "scatter" + }, + { + "x": [ + 3, + 4, + 5 + ], + "y": [ + 400, + 500, + 600 + ], + "name": "yaxis3 data", + "yaxis": "y3", + "type": "scatter" + }, + { + "x": [ + 4, + 5, + 6 + ], + "y": [ + 4000, + 5000, + 6000 + ], + "name": "yaxis4 data", + "yaxis": "y4", + "type": "scatter" } ], "layout": { @@ -51,6 +81,18 @@ "anchor": "free", "overlaying": "y", "automargin": true + }, + "yaxis3": { + "title": {"text": "yaxis3 title"}, + "anchor": "free", + "overlaying": "y", + "automargin": true + }, + "yaxis4": { + "title": {"text": "yaxis4 title"}, + "anchor": "free", + "overlaying": "y", + "automargin": true } } } From 68b8f8fdc8735a00e1582c3bd71b613a3917879d Mon Sep 17 00:00:00 2001 From: hannahker Date: Mon, 19 Sep 2022 13:53:06 -0700 Subject: [PATCH 03/10] Add more complex mock and clean up code --- src/plots/cartesian/axes.js | 27 +++-- .../image/mocks/z-multiple-yaxes-complex.json | 112 ++++++++++++++++++ ...yout.json => z-multiple-yaxes-simple.json} | 18 ++- 3 files changed, 142 insertions(+), 15 deletions(-) create mode 100644 test/image/mocks/z-multiple-yaxes-complex.json rename test/image/mocks/{z-multiple-yaxes-layout.json => z-multiple-yaxes-simple.json} (85%) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 1a8b783951d..71b4ff2a68b 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2248,7 +2248,7 @@ axes.draw = function(gd, arg, opts) { var axList = (!arg || arg === 'redraw') ? axes.listIds(gd) : arg; - var allDepths = [0] // Or dict w keys/values? + var allDepths = [] return Lib.syncOrAsync(axList.map(function(axId) { return function() { @@ -2257,8 +2257,11 @@ axes.draw = function(gd, arg, opts) { var ax = axes.getFromId(gd, axId); var axDone = axes.drawOne(gd, ax, opts, allDepths); - var depth = ax._depth > 0 ? (ax._depth + 50) : ax._depth; // Add offset to account for title size - allDepths.push(depth) + // If we've just drawn a y axis, then keep track of its width so that we can push + // out additional y axes if needed + if (ax._id.charAt(0) == 'y') { + allDepths.push(ax._depth + ax._titleDepth); + } ax._r = ax.range.slice(); ax._rl = Lib.simpleMap(ax._r, ax.r2l); @@ -2295,12 +2298,9 @@ axes.draw = function(gd, arg, opts) { * - and calls ax.setScale */ axes.drawOne = function(gd, ax, opts, allDepths) { - //debugger; opts = opts || {}; var i, sp, plotinfo; - //('All depths:') - //console.log(allDepths) ax.setScale(); @@ -2337,8 +2337,15 @@ axes.drawOne = function(gd, ax, opts, allDepths) { // (touching either the tick label or ticks) // depth can be expansive to compute, so we only do so when required ax._depth = null; - // Shift the sum of existing axes depth - ax._xshift = allDepths.reduce((a, b) => a + b) + // If drawing another y-axis, then look at the sum of the depths of existing axes + // to determine how much to shift this one out by + // TODO: Also need to account for the expected depth of the current axis + // (if drawing from the left inwards) + if (axLetter == 'y' & allDepths.length > 0) { + ax._xshift = allDepths.reduce((a, b) => a + b); + } else { + ax._xshift = null; + } // calcLabelLevelBbox can be expensive, // so make sure to not call it twice during the same Axes.drawOne call @@ -3841,7 +3848,6 @@ function approxTitleDepth(ax) { * - {boolean} showticklabels */ function drawTitle(gd, ax) { - debugger; var fullLayout = gd._fullLayout; var axId = ax._id; var axLetter = axId.charAt(0); @@ -3878,7 +3884,7 @@ function drawTitle(gd, ax) { } } } - + ax._titleDepth = titleStandoff var pos = axes.getPxPosition(gd, ax); var transform, x, y; @@ -3890,7 +3896,6 @@ function drawTitle(gd, ax) { x = (ax.side === 'right') ? pos + titleStandoff : pos - titleStandoff; transform = {rotate: '-90', offset: 0}; } - debugger; var avoid; if(ax.type !== 'multicategory') { diff --git a/test/image/mocks/z-multiple-yaxes-complex.json b/test/image/mocks/z-multiple-yaxes-complex.json new file mode 100644 index 00000000000..f3317a478b6 --- /dev/null +++ b/test/image/mocks/z-multiple-yaxes-complex.json @@ -0,0 +1,112 @@ +{ + "data": [ + { + "x": [ + 1, + 2, + 3 + ], + "y": [ + 4, + 5, + 6 + ], + "name": "yaxis1 data", + "type": "scatter" + }, + { + "x": [ + 2, + 3, + 4 + ], + "y": [ + 40, + 50, + 60 + ], + "name": "yaxis2 data", + "yaxis": "y2", + "type": "scatter" + }, + { + "x": [ + 3, + 4, + 5 + ], + "y": [ + 400, + 500, + 600 + ], + "name": "yaxis3 data", + "yaxis": "y3", + "type": "scatter" + }, + { + "x": [ + 4, + 5, + 6 + ], + "y": [ + 4000, + 5000, + 6000 + ], + "name": "yaxis4 data", + "yaxis": "y4", + "type": "scatter" + } + ], + "layout": { + "title": { + "text": "multiple y-axes example - complex formatting" + }, + "width": 800, + "xaxis": { + "domain": [ + 0.5, + 1 + ] + }, + + "yaxis": { + "title": { + "text": "yaxis title" + + }, + "automargin": true, + "anchor": "free" + }, + "yaxis2": { + "title": {"text": "yaxis2 title"}, + "anchor": "free", + "overlaying": "y", + "automargin": true, + "ticklen":25 + + }, + "yaxis3": { + "title": { + "text": "yaxis3 title", + "font": {"size": 28} + }, + "tickfont": {"size": 28}, + "anchor": "free", + "overlaying": "y", + "automargin": true + }, + "yaxis4": { + "anchor": "free", + "title": { + "text": "yaxis4 title", + "font": {"size": 8} + }, + "tickfont": {"size": 8}, + "overlaying": "y", + "automargin": true + } + } +} diff --git a/test/image/mocks/z-multiple-yaxes-layout.json b/test/image/mocks/z-multiple-yaxes-simple.json similarity index 85% rename from test/image/mocks/z-multiple-yaxes-layout.json rename to test/image/mocks/z-multiple-yaxes-simple.json index f0115ebee85..d42d7388971 100644 --- a/test/image/mocks/z-multiple-yaxes-layout.json +++ b/test/image/mocks/z-multiple-yaxes-simple.json @@ -62,7 +62,7 @@ ], "layout": { "title": { - "text": "multiple y-axes example" + "text": "multiple y-axes example - uniform formatting" }, "width": 800, "xaxis": { @@ -71,8 +71,12 @@ 1 ] }, + "yaxis": { - "title": {"text": "yaxis title"}, + "title": { + "text": "yaxis title" + + }, "automargin": true, "anchor": "free" }, @@ -83,14 +87,20 @@ "automargin": true }, "yaxis3": { - "title": {"text": "yaxis3 title"}, + "title": { + "text": "yaxis3 title" + + }, "anchor": "free", "overlaying": "y", "automargin": true }, "yaxis4": { - "title": {"text": "yaxis4 title"}, "anchor": "free", + "title": { + "text": "yaxis4 title" + + }, "overlaying": "y", "automargin": true } From 419409768b0c585d3ab5b12d7c93b7139bfe8e74 Mon Sep 17 00:00:00 2001 From: hannahker Date: Mon, 19 Sep 2022 17:00:02 -0700 Subject: [PATCH 04/10] Axis titles are working --- src/plot_api/subroutines.js | 2 +- src/plots/cartesian/axes.js | 36 ++++++++--- test/image/mocks/multiple_axes_multiple.json | 6 +- test/image/mocks/z-multiple-yaxes-simple.json | 63 ++++++++++++------- 4 files changed, 71 insertions(+), 36 deletions(-) diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index c222fb0306e..7180492f88f 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -76,7 +76,7 @@ function lsInner(gd) { else if(side === 'top') return counterAx._offset - pad - lwHalf; return counterAx._offset + counterAx._length + pad + lwHalf; } - + console.log('xshift : ' + xshift) if(!counterAx) return gs.l + gs.w * (ax.position || 0) + (lwHalf % 1) + xshift; else if(side === 'right') return counterAx._offset + counterAx._length + pad + lwHalf; return counterAx._offset - pad - lwHalf; diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 71b4ff2a68b..a2b458e84d5 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2248,19 +2248,24 @@ axes.draw = function(gd, arg, opts) { var axList = (!arg || arg === 'redraw') ? axes.listIds(gd) : arg; - var allDepths = [] + var multAxisDepths = {'left': 0, 'right': 0} return Lib.syncOrAsync(axList.map(function(axId) { return function() { if(!axId) return; var ax = axes.getFromId(gd, axId); - var axDone = axes.drawOne(gd, ax, opts, allDepths); + var axDone = axes.drawOne(gd, ax, opts, multAxisDepths); // If we've just drawn a y axis, then keep track of its width so that we can push // out additional y axes if needed - if (ax._id.charAt(0) == 'y') { - allDepths.push(ax._depth + ax._titleDepth); + if (ax._id.charAt(0) === 'y') { + if (ax.side === 'left') { + multAxisDepths['left'] += 75 + } + else if (ax.side === 'right') { + multAxisDepths['right'] += 75 + } } ax._r = ax.range.slice(); @@ -2341,11 +2346,13 @@ axes.drawOne = function(gd, ax, opts, allDepths) { // to determine how much to shift this one out by // TODO: Also need to account for the expected depth of the current axis // (if drawing from the left inwards) - if (axLetter == 'y' & allDepths.length > 0) { - ax._xshift = allDepths.reduce((a, b) => a + b); + if (axLetter == 'y') { + ax._xshift = allDepths[ax.side]; } else { ax._xshift = null; } + console.log(ax._id); + console.log(ax._xshift); // calcLabelLevelBbox can be expensive, // so make sure to not call it twice during the same Axes.drawOne call @@ -3786,9 +3793,20 @@ axes.getPxPosition = function(gd, ax) { var side = ax.side; var anchorAxis; - var xshift = ax.position > 0 ? 0 : ax._xshift; + // Shift in the opposite direction depending on which side the axis is on + // But don't shift if 'position' is specified + var xshift = ax.position > 0 ? 0 : ax._xshift; + xshift = side === 'left' ? xshift : -xshift; + if(ax.anchor !== 'free') { - anchorAxis = ax._anchorAxis; + if (axLetter === 'y') { + anchorAxis = { + _offset: ax._anchorAxis._offset - xshift, + _length: ax._anchorAxis._length + } + } else { + anchorAxis = ax._anchorAxis; + } } else if(axLetter === 'x') { anchorAxis = { _offset: gs.t + (1 - (ax.position || 0)) * gs.h, @@ -3800,6 +3818,8 @@ axes.getPxPosition = function(gd, ax) { _length: 0 }; } + + //console.log(anchorAxis._offset); if(side === 'top' || side === 'left') { return anchorAxis._offset; } else if(side === 'bottom' || side === 'right') { diff --git a/test/image/mocks/multiple_axes_multiple.json b/test/image/mocks/multiple_axes_multiple.json index 3ab5872527a..3047188cfaa 100644 --- a/test/image/mocks/multiple_axes_multiple.json +++ b/test/image/mocks/multiple_axes_multiple.json @@ -21,9 +21,9 @@ 4 ], "y": [ - 40, - 50, - 60 + 40000, + 50000, + 60000 ], "name": "yaxis2 data", "yaxis": "y2", diff --git a/test/image/mocks/z-multiple-yaxes-simple.json b/test/image/mocks/z-multiple-yaxes-simple.json index d42d7388971..a2e7ec54a2f 100644 --- a/test/image/mocks/z-multiple-yaxes-simple.json +++ b/test/image/mocks/z-multiple-yaxes-simple.json @@ -21,9 +21,9 @@ 4 ], "y": [ - 40, - 50, - 60 + 33, + 67, + 92 ], "name": "yaxis2 data", "yaxis": "y2", @@ -36,9 +36,9 @@ 5 ], "y": [ - 400, - 500, - 600 + 22, + 23, + 24 ], "name": "yaxis3 data", "yaxis": "y3", @@ -51,13 +51,28 @@ 6 ], "y": [ - 4000, - 5000, - 6000 + 40.5, + 41, + 46 ], "name": "yaxis4 data", "yaxis": "y4", "type": "scatter" + }, + { + "x": [ + 4, + 5, + 6 + ], + "y": [ + 2, + 10, + 100 + ], + "name": "yaxis5 data", + "yaxis": "y5", + "type": "scatter" } ], "layout": { @@ -67,42 +82,42 @@ "width": 800, "xaxis": { "domain": [ - 0.5, - 1 + 0.25, + 0.75 ] - }, - + }, "yaxis": { "title": { "text": "yaxis title" - }, - "automargin": true, - "anchor": "free" + } }, "yaxis2": { "title": {"text": "yaxis2 title"}, - "anchor": "free", - "overlaying": "y", - "automargin": true + "overlaying": "y" }, "yaxis3": { "title": { "text": "yaxis3 title" }, - "anchor": "free", - "overlaying": "y", - "automargin": true + "overlaying": "y" }, "yaxis4": { - "anchor": "free", "title": { "text": "yaxis4 title" }, "overlaying": "y", - "automargin": true + "side": "right" + }, + "yaxis5": { + "title": { + "text": "yaxis5 title" + + }, + "overlaying": "y", + "side": "right" } } } From 23efbe8135501fb7430206a86a0a6c86566a7e75 Mon Sep 17 00:00:00 2001 From: hannahker Date: Mon, 19 Sep 2022 17:13:57 -0700 Subject: [PATCH 05/10] Tick labels position with automargin --- src/plot_api/subroutines.js | 5 ++--- src/plots/cartesian/axes.js | 1 - test/image/mocks/z-multiple-yaxes-complex.json | 13 +++---------- test/image/mocks/z-multiple-yaxes-simple.json | 3 ++- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index 7180492f88f..df3f542ea46 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -76,10 +76,9 @@ function lsInner(gd) { else if(side === 'top') return counterAx._offset - pad - lwHalf; return counterAx._offset + counterAx._length + pad + lwHalf; } - console.log('xshift : ' + xshift) if(!counterAx) return gs.l + gs.w * (ax.position || 0) + (lwHalf % 1) + xshift; - else if(side === 'right') return counterAx._offset + counterAx._length + pad + lwHalf; - return counterAx._offset - pad - lwHalf; + else if(side === 'right') return counterAx._offset + counterAx._length + pad + lwHalf + xshift; + return counterAx._offset - pad - lwHalf - xshift; } // some preparation of axis position info diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index a2b458e84d5..5b3f280481e 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2663,7 +2663,6 @@ axes.drawOne = function(gd, ax, opts, allDepths) { Plots.autoMargin(gd, axMirrorAutoMarginID(ax), mirrorPush); Plots.autoMargin(gd, rangeSliderAutoMarginID(ax), rangeSliderPush); }); - if(!opts.skipTitle && !(hasRangeSlider && ax.side === 'bottom') ) { diff --git a/test/image/mocks/z-multiple-yaxes-complex.json b/test/image/mocks/z-multiple-yaxes-complex.json index f3317a478b6..641ec747756 100644 --- a/test/image/mocks/z-multiple-yaxes-complex.json +++ b/test/image/mocks/z-multiple-yaxes-complex.json @@ -77,14 +77,11 @@ "text": "yaxis title" }, - "automargin": true, - "anchor": "free" + "automargin": true }, "yaxis2": { "title": {"text": "yaxis2 title"}, - "anchor": "free", "overlaying": "y", - "automargin": true, "ticklen":25 }, @@ -94,19 +91,15 @@ "font": {"size": 28} }, "tickfont": {"size": 28}, - "anchor": "free", - "overlaying": "y", - "automargin": true + "overlaying": "y" }, "yaxis4": { - "anchor": "free", "title": { "text": "yaxis4 title", "font": {"size": 8} }, "tickfont": {"size": 8}, - "overlaying": "y", - "automargin": true + "overlaying": "y" } } } diff --git a/test/image/mocks/z-multiple-yaxes-simple.json b/test/image/mocks/z-multiple-yaxes-simple.json index a2e7ec54a2f..04aa943837d 100644 --- a/test/image/mocks/z-multiple-yaxes-simple.json +++ b/test/image/mocks/z-multiple-yaxes-simple.json @@ -90,7 +90,8 @@ "title": { "text": "yaxis title" - } + }, + "automargin": true }, "yaxis2": { "title": {"text": "yaxis2 title"}, From 736db9da8851bdaee97eb44b30af9137e15a0a86 Mon Sep 17 00:00:00 2001 From: hannahker Date: Mon, 19 Sep 2022 17:21:51 -0700 Subject: [PATCH 06/10] Fix formatting --- src/plot_api/subroutines.js | 3 +-- src/plots/cartesian/axes.js | 43 ++++++++++++++++--------------------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index df3f542ea46..efd58436bfe 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -69,7 +69,7 @@ function lsInner(gd) { function getLinePosition(ax, counterAx, side) { var lwHalf = ax._lw / 2; - var xshift = ax.position > 0 ? 0 : ax._xshift; + var xshift = ax.position > 0 ? 0 : ax._xshift; if(ax._id.charAt(0) === 'x') { if(!counterAx) return gs.t + gs.h * (1 - (ax.position || 0)) + (lwHalf % 1); @@ -724,4 +724,3 @@ exports.drawMarginPushers = function(gd) { // } // } - diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 5b3f280481e..f2b69636869 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2248,7 +2248,7 @@ axes.draw = function(gd, arg, opts) { var axList = (!arg || arg === 'redraw') ? axes.listIds(gd) : arg; - var multAxisDepths = {'left': 0, 'right': 0} + var multAxisDepths = {'left': 0, 'right': 0}; return Lib.syncOrAsync(axList.map(function(axId) { return function() { @@ -2257,17 +2257,16 @@ axes.draw = function(gd, arg, opts) { var ax = axes.getFromId(gd, axId); var axDone = axes.drawOne(gd, ax, opts, multAxisDepths); - // If we've just drawn a y axis, then keep track of its width so that we can push + // If we've just drawn a y axis, then keep track of its width so that we can push // out additional y axes if needed - if (ax._id.charAt(0) === 'y') { - if (ax.side === 'left') { - multAxisDepths['left'] += 75 - } - else if (ax.side === 'right') { - multAxisDepths['right'] += 75 + if(ax._id.charAt(0) === 'y') { + if(ax.side === 'left') { + multAxisDepths.left += 75; + } else if(ax.side === 'right') { + multAxisDepths.right += 75; } } - + ax._r = ax.range.slice(); ax._rl = Lib.simpleMap(ax._r, ax.r2l); return axDone; @@ -2306,9 +2305,9 @@ axes.drawOne = function(gd, ax, opts, allDepths) { opts = opts || {}; var i, sp, plotinfo; - + ax.setScale(); - + var fullLayout = gd._fullLayout; var axId = ax._id; var axLetter = axId.charAt(0); @@ -2346,13 +2345,11 @@ axes.drawOne = function(gd, ax, opts, allDepths) { // to determine how much to shift this one out by // TODO: Also need to account for the expected depth of the current axis // (if drawing from the left inwards) - if (axLetter == 'y') { + if(axLetter === 'y') { ax._xshift = allDepths[ax.side]; } else { ax._xshift = null; } - console.log(ax._id); - console.log(ax._xshift); // calcLabelLevelBbox can be expensive, // so make sure to not call it twice during the same Axes.drawOne call @@ -3786,7 +3783,6 @@ function drawDividers(gd, ax, opts) { * @return {number} */ axes.getPxPosition = function(gd, ax) { - var gs = gd._fullLayout._size; var axLetter = ax._id.charAt(0); var side = ax.side; @@ -3798,14 +3794,14 @@ axes.getPxPosition = function(gd, ax) { xshift = side === 'left' ? xshift : -xshift; if(ax.anchor !== 'free') { - if (axLetter === 'y') { + if(axLetter === 'y') { anchorAxis = { - _offset: ax._anchorAxis._offset - xshift, + _offset: ax._anchorAxis._offset - xshift, _length: ax._anchorAxis._length - } + }; } else { anchorAxis = ax._anchorAxis; - } + } } else if(axLetter === 'x') { anchorAxis = { _offset: gs.t + (1 - (ax.position || 0)) * gs.h, @@ -3813,17 +3809,16 @@ axes.getPxPosition = function(gd, ax) { }; } else if(axLetter === 'y') { anchorAxis = { - _offset: (gs.l + (ax.position || 0) * gs.w) + xshift, + _offset: (gs.l + (ax.position || 0) * gs.w) + xshift, _length: 0 }; } - - //console.log(anchorAxis._offset); + if(side === 'top' || side === 'left') { return anchorAxis._offset; } else if(side === 'bottom' || side === 'right') { return anchorAxis._offset + anchorAxis._length; - } + } }; /** @@ -3903,7 +3898,7 @@ function drawTitle(gd, ax) { } } } - ax._titleDepth = titleStandoff + ax._titleDepth = titleStandoff; var pos = axes.getPxPosition(gd, ax); var transform, x, y; From e5f5e4c77a6b5e55f6ffe6542ae7722a83bff3bf Mon Sep 17 00:00:00 2001 From: hannahker Date: Wed, 21 Sep 2022 16:13:12 -0700 Subject: [PATCH 07/10] Calculate mainlineposition when drawing axis --- src/plot_api/subroutines.js | 1 + src/plots/cartesian/axes.js | 31 +++++++++++++++++-- test/image/mocks/z-multiple-yaxes-simple.json | 14 ++++++--- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index efd58436bfe..7f23a87c7e1 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -70,6 +70,7 @@ function lsInner(gd) { function getLinePosition(ax, counterAx, side) { var lwHalf = ax._lw / 2; var xshift = ax.position > 0 ? 0 : ax._xshift; + xshift = (xshift == undefined) ? 0 : xshift; if(ax._id.charAt(0) === 'x') { if(!counterAx) return gs.t + gs.h * (1 - (ax.position || 0)) + (lwHalf % 1); diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index f2b69636869..3523b1d94bb 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2318,7 +2318,6 @@ axes.drawOne = function(gd, ax, opts, allDepths) { if(!mainPlotinfo) return; var mainAxLayer = mainPlotinfo[axLetter + 'axislayer']; - var mainLinePosition = ax._mainLinePosition; var mainMirrorPosition = ax._mainMirrorPosition; var vals = ax._vals = axes.calcTicks(ax); @@ -2345,12 +2344,20 @@ axes.drawOne = function(gd, ax, opts, allDepths) { // to determine how much to shift this one out by // TODO: Also need to account for the expected depth of the current axis // (if drawing from the left inwards) - if(axLetter === 'y') { + if(axLetter === 'y' & !ax.position > 0) { ax._xshift = allDepths[ax.side]; } else { - ax._xshift = null; + ax._xshift = 0; } + var mainLinePosition; + if (ax._xshift > 0){ + // Calculate main line position from function + mainLinePosition = getLinePosition(ax, ax._anchorAxis, ax.side) + } else { + mainLinePosition = ax._mainLinePosition; + } + // calcLabelLevelBbox can be expensive, // so make sure to not call it twice during the same Axes.drawOne call // by stashing label-level bounding boxes per tick-label class @@ -4240,3 +4247,21 @@ function hideCounterAxisInsideTickLabels(ax, opts) { } } } + +// Copied over from subroutines.js since I want to calculate the line position when +// drawing each y-axis if there is an xshift to be applied +// TODO: Possible to reference this from subroutines.js directly or put the function in some general utils file? +function getLinePosition(ax, counterAx, side) { + var lwHalf = ax._lw / 2; + var xshift = ax.position > 0 ? 0 : ax._xshift; + xshift = (xshift == undefined) ? 0 : xshift; + + if(ax._id.charAt(0) === 'x') { + if(!counterAx) return gs.t + gs.h * (1 - (ax.position || 0)) + (lwHalf % 1); + else if(side === 'top') return counterAx._offset - lwHalf; + return counterAx._offset + counterAx._length + lwHalf; + } + if(!counterAx) return gs.l + gs.w * (ax.position || 0) + (lwHalf % 1) + xshift; + else if(side === 'right') return counterAx._offset + counterAx._length + lwHalf + xshift; + return counterAx._offset - lwHalf - xshift; +} \ No newline at end of file diff --git a/test/image/mocks/z-multiple-yaxes-simple.json b/test/image/mocks/z-multiple-yaxes-simple.json index 04aa943837d..64e67f26b1c 100644 --- a/test/image/mocks/z-multiple-yaxes-simple.json +++ b/test/image/mocks/z-multiple-yaxes-simple.json @@ -91,18 +91,20 @@ "text": "yaxis title" }, - "automargin": true + "showline": true }, "yaxis2": { "title": {"text": "yaxis2 title"}, - "overlaying": "y" + "overlaying": "y", + "showline": true }, "yaxis3": { "title": { "text": "yaxis3 title" }, - "overlaying": "y" + "overlaying": "y", + "showline": true }, "yaxis4": { "title": { @@ -110,7 +112,8 @@ }, "overlaying": "y", - "side": "right" + "side": "right", + "showline": true }, "yaxis5": { "title": { @@ -118,7 +121,8 @@ }, "overlaying": "y", - "side": "right" + "side": "right", + "showline": true } } } From 06d1daf1cf4522ca1011398cf1fa9c4922c7fa74 Mon Sep 17 00:00:00 2001 From: hannahker Date: Wed, 21 Sep 2022 16:20:22 -0700 Subject: [PATCH 08/10] Simplify syntax --- src/plots/cartesian/axes.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 3523b1d94bb..086bb8ff827 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2260,11 +2260,7 @@ axes.draw = function(gd, arg, opts) { // If we've just drawn a y axis, then keep track of its width so that we can push // out additional y axes if needed if(ax._id.charAt(0) === 'y') { - if(ax.side === 'left') { - multAxisDepths.left += 75; - } else if(ax.side === 'right') { - multAxisDepths.right += 75; - } + multAxisDepths[ax.side] += 75 } ax._r = ax.range.slice(); From 78c51ca674fa292830a6deee0caf1407d7a619fa Mon Sep 17 00:00:00 2001 From: hannahker Date: Thu, 22 Sep 2022 12:04:19 -0700 Subject: [PATCH 09/10] Improve logic --- src/plots/cartesian/axes.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 086bb8ff827..232799e089b 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2260,7 +2260,7 @@ axes.draw = function(gd, arg, opts) { // If we've just drawn a y axis, then keep track of its width so that we can push // out additional y axes if needed if(ax._id.charAt(0) === 'y') { - multAxisDepths[ax.side] += 75 + multAxisDepths[ax.side] += 75; } ax._r = ax.range.slice(); @@ -2346,14 +2346,15 @@ axes.drawOne = function(gd, ax, opts, allDepths) { ax._xshift = 0; } - var mainLinePosition; - if (ax._xshift > 0){ + var mainLinePosition; + + if(ax._xshift > 0 & ax.anchor !== 'free') { // Calculate main line position from function - mainLinePosition = getLinePosition(ax, ax._anchorAxis, ax.side) + mainLinePosition = getLinePosition(ax, ax._anchorAxis, ax.side); } else { mainLinePosition = ax._mainLinePosition; } - + // calcLabelLevelBbox can be expensive, // so make sure to not call it twice during the same Axes.drawOne call // by stashing label-level bounding boxes per tick-label class @@ -2363,7 +2364,6 @@ axes.drawOne = function(gd, ax, opts, allDepths) { if(!llbboxes[cls]) llbboxes[cls] = calcLabelLevelBbox(ax, cls); return llbboxes[cls]; } - if(!ax.visible) return; var transTickFn = axes.makeTransTickFn(ax); @@ -4244,7 +4244,7 @@ function hideCounterAxisInsideTickLabels(ax, opts) { } } -// Copied over from subroutines.js since I want to calculate the line position when +// Copied over from subroutines.js since I want to calculate the line position when // drawing each y-axis if there is an xshift to be applied // TODO: Possible to reference this from subroutines.js directly or put the function in some general utils file? function getLinePosition(ax, counterAx, side) { @@ -4260,4 +4260,4 @@ function getLinePosition(ax, counterAx, side) { if(!counterAx) return gs.l + gs.w * (ax.position || 0) + (lwHalf % 1) + xshift; else if(side === 'right') return counterAx._offset + counterAx._length + lwHalf + xshift; return counterAx._offset - lwHalf - xshift; -} \ No newline at end of file +} From 4194f8f7f4ed38db3bcda7704454d5b4f270d178 Mon Sep 17 00:00:00 2001 From: hannahker Date: Thu, 22 Sep 2022 15:50:38 -0700 Subject: [PATCH 10/10] To check image tests --- src/plots/cartesian/axes.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 232799e089b..21e3b1de9a4 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2340,7 +2340,11 @@ axes.drawOne = function(gd, ax, opts, allDepths) { // to determine how much to shift this one out by // TODO: Also need to account for the expected depth of the current axis // (if drawing from the left inwards) - if(axLetter === 'y' & !ax.position > 0) { + console.log("New axis!!") + console.log(ax._id) + console.log(ax.overlaying) + if(axLetter === 'y' & !(ax.position > 0) & ax.overlaying) { + console.log('here') ax._xshift = allDepths[ax.side]; } else { ax._xshift = 0; @@ -2355,6 +2359,10 @@ axes.drawOne = function(gd, ax, opts, allDepths) { mainLinePosition = ax._mainLinePosition; } + + console.log(ax._xshift) + console.log(mainLinePosition) + // calcLabelLevelBbox can be expensive, // so make sure to not call it twice during the same Axes.drawOne call // by stashing label-level bounding boxes per tick-label class