From 66328b431708dc7be543c1bd427d1ebfbe2fae19 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 7 May 2025 13:04:57 +0200 Subject: [PATCH 1/2] Add support for `ticklabelposition` "inside"/"outside" for category axes with `tickson` set to "boundaries". "top", "bottom", "left", "right" are ignored if `tickson` is set to "boundaries". --- src/plots/cartesian/axes.js | 13 +- src/plots/cartesian/axis_defaults.js | 8 +- src/plots/cartesian/layout_attributes.js | 11 +- ...-tickson_boundaries_ticklabelposition.json | 150 ++++++++++++++++++ 4 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 test/image/mocks/zz-tickson_boundaries_ticklabelposition.json diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 84ebe5b3bb1..6f4c48538e1 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -3071,6 +3071,7 @@ function getPosX(d) { // v is a shift perpendicular to the axis function getTickLabelUV(ax) { var ticklabelposition = ax.ticklabelposition || ''; + var tickson = ax.tickson || ''; var has = function(str) { return ticklabelposition.indexOf(str) !== -1; }; @@ -3081,7 +3082,7 @@ function getTickLabelUV(ax) { var isBottom = has('bottom'); var isInside = has('inside'); - var isAligned = isBottom || isLeft || isTop || isRight; + var isAligned = (tickson != 'boundaries') && (isBottom || isLeft || isTop || isRight); // early return if(!isAligned && !isInside) return [0, 0]; @@ -3165,6 +3166,8 @@ axes.makeTickPath = function(ax, shift, sgn, opts) { */ axes.makeLabelFns = function(ax, shift, angle) { var ticklabelposition = ax.ticklabelposition || ''; + var tickson = ax.tickson || ''; + var has = function(str) { return ticklabelposition.indexOf(str) !== -1; }; @@ -3173,12 +3176,12 @@ axes.makeLabelFns = function(ax, shift, angle) { var isLeft = has('left'); var isRight = has('right'); var isBottom = has('bottom'); - var isAligned = isBottom || isLeft || isTop || isRight; + var isAligned = (tickson != 'boundaries') && (isBottom || isLeft || isTop || isRight); var insideTickLabels = has('inside'); var labelsOverTicks = (ticklabelposition === 'inside' && ax.ticks === 'inside') || - (!insideTickLabels && ax.ticks === 'outside' && ax.tickson !== 'boundaries'); + (!insideTickLabels && ax.ticks === 'outside' && tickson !== 'boundaries'); var labelStandoff = 0; var labelShift = 0; @@ -3890,6 +3893,8 @@ axes.drawLabels = function(gd, ax, opts) { } } else { var ticklabelposition = ax.ticklabelposition || ''; + var tickson = ax.tickson ||''; + var has = function(str) { return ticklabelposition.indexOf(str) !== -1; }; @@ -3897,7 +3902,7 @@ axes.drawLabels = function(gd, ax, opts) { var isLeft = has('left'); var isRight = has('right'); var isBottom = has('bottom'); - var isAligned = isBottom || isLeft || isTop || isRight; + var isAligned = (tickson != 'boundaries') && (isBottom || isLeft || isTop || isRight); var pad = !isAligned ? 0 : (ax.tickwidth || 0) + 2 * TEXTPAD; diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js index 8c5c75d8832..4531785cd2f 100644 --- a/src/plots/cartesian/axis_defaults.js +++ b/src/plots/cartesian/axis_defaults.js @@ -167,11 +167,11 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, (axType === 'category' || isMultiCategory) && (containerOut.ticks || containerOut.showgrid) ) { - var ticksonDflt; - if(isMultiCategory) ticksonDflt = 'boundaries'; - var tickson = coerce('tickson', ticksonDflt); - if(tickson === 'boundaries') { + if (isMultiCategory) { + coerce('tickson', 'boundaries'); delete containerOut.ticklabelposition; + } else { // category axis + coerce('tickson'); } } diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index 32afc99457a..9eb73a2477e 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -663,12 +663,13 @@ module.exports = { dflt: 'outside', editType: 'calc', description: [ - 'Determines where tick labels are drawn with respect to the axis', + 'Determines where tick labels are drawn with respect to the axis.', 'Please note that', - 'top or bottom has no effect on x axes or when `ticklabelmode` is set to *period*.', - 'Similarly', - 'left or right has no effect on y axes or when `ticklabelmode` is set to *period*.', - 'Has no effect on *multicategory* axes or when `tickson` is set to *boundaries*.', + 'top or bottom has no effect on x axes or when `ticklabelmode` is set to *period*', + 'or when `tickson` is set to *boundaries*. Similarly,', + 'left or right has no effect on y axes or when `ticklabelmode` is set to *period*', + 'or when `tickson` is set to *boundaries*.', + 'Has no effect on *multicategory* axes.', 'When used on axes linked by `matches` or `scaleanchor`,', 'no extra padding for inside labels would be added by autorange,', 'so that the scales could match.' diff --git a/test/image/mocks/zz-tickson_boundaries_ticklabelposition.json b/test/image/mocks/zz-tickson_boundaries_ticklabelposition.json new file mode 100644 index 00000000000..01962a67706 --- /dev/null +++ b/test/image/mocks/zz-tickson_boundaries_ticklabelposition.json @@ -0,0 +1,150 @@ +{ + "data": [ + { + "type": "box", + "x": [ + "day 1", + "day 1", + "day 1", + "day 1", + "day 1", + "day 1", + "day 2", + "day 2", + "day 2", + "day 2", + "day 2", + "day 2" + ], + "y": [0.2, 0.2, 0.6, 1, 0.5, 0.4, 0.2, 0.7, 0.9, 0.1, 0.5, 0.3] + }, + { + "type": "box", + "x": [ + "day 1", + "day 1", + "day 1", + "day 1", + "day 1", + "day 1", + "day 2", + "day 2", + "day 2", + "day 2", + "day 2", + "day 2" + ], + "y": [0.1, 0.3, 0.1, 0.9, 0.6, 0.6, 0.9, 1, 0.3, 0.6, 0.8, 0.5] + }, + { + "type": "box", + "x": [ + "day 1", + "day 1", + "day 1", + "day 1", + "day 1", + "day 1", + "day 2", + "day 2", + "day 2", + "day 2", + "day 2", + "day 2" + ], + "y": [0.6, 0.7, 0.3, 0.6, 0, 0.5, 0.7, 0.9, 0.5, 0.8, 0.7, 0.2] + }, + + { + "type": "bar", + "x": [1, 2, 1], + "y": ["apples", "bananas", "clementines"], + "orientation": "h", + "xaxis": "x2", + "yaxis": "y2" + }, + { + "type": "bar", + "x": [1.3, 2.2, 0.8], + "y": ["apples", "bananas", "clementines"], + "orientation": "h", + "xaxis": "x2", + "yaxis": "y2" + }, + { + "type": "bar", + "x": [3, 3.2, 1.8], + "y": ["apples", "bananas", "clementines"], + "orientation": "h", + "xaxis": "x2", + "yaxis": "y2" + }, + + { + "type": "bar", + "name": "with dtick !== 1", + "x": ["a", "b", "c", "d", "e", "f", "g", "h"], + "y": [1, 2, 1, 2, 1, 3, 4, 1], + "xaxis": "x3", + "yaxis": "y3" + }, + + { + "mode": "markers", + "marker": { "symbol": "square" }, + "name": "with overlapping tick labels", + "x": ["A very long title", "short", "Another very long title"], + "y": [0, 10, 2], + "xaxis": "x4", + "yaxis": "y4" + } + ], + "layout": { + "title": { + "text": "Although some ticklabelpositions have a side specified,
all category labels are expected to be centered." + }, + "boxmode": "group", + "grid": { + "rows": 4, + "columns": 1, + "pattern": "independent", + "ygap": 0.2 + }, + "xaxis": { + "ticklabelposition": "inside right", + "ticks": "outside", + "tickson": "boundaries", + "gridcolor": "white", + "gridwidth": 4 + }, + "yaxis2": { + "ticks": "inside", + "ticklabelposition": "inside top", + "tickson": "boundaries", + "gridcolor": "white", + "gridwidth": 4 + }, + "xaxis3": { + "ticks": "inside", + "ticklabelposition": "inside left", + "tickson": "boundaries", + "gridcolor": "white", + "gridwidth": 4, + "dtick": 2 + }, + "xaxis4": { + "domain": [0.22, 0.78], + "ticks": "outside", + "ticklabelposition": "inside", + "ticklen": 20, + "tickson": "boundaries", + "gridcolor": "white", + "gridwidth": 4 + }, + "plot_bgcolor": "lightgrey", + "showlegend": false, + "width": 500, + "height": 800, + "margin": { "b": 140 } + } +} From c84ae91e63f9f5e6ce0fc20bffd25a0227090e11 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 7 May 2025 13:55:39 +0200 Subject: [PATCH 2/2] Add draftlog for 7420 --- draftlogs/7420_add.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 draftlogs/7420_add.md diff --git a/draftlogs/7420_add.md b/draftlogs/7420_add.md new file mode 100644 index 00000000000..5dd6fc712c6 --- /dev/null +++ b/draftlogs/7420_add.md @@ -0,0 +1 @@ + - Add support for ticklabelposition "inside"/"outside" for category axes with `tickson` set to "boundaries" [[#7420](https://github.com/plotly/plotly.js/pull/7420)]