Skip to content

Commit dad2472

Browse files
authored
Merge pull request #5329 from plotly/inside-ticklabels-scaleanchor-matches
Make inside ticklabels autorange work with scaleanchor or matches
2 parents 04966b7 + ef1979b commit dad2472

12 files changed

+167
-17
lines changed

src/plots/cartesian/autorange.js

+17-8
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ var Lib = require('../../lib');
1414
var FP_SAFE = require('../../constants/numerical').FP_SAFE;
1515
var Registry = require('../../registry');
1616

17-
var getFromId = require('./axis_ids').getFromId;
17+
var axIds = require('./axis_ids');
18+
var getFromId = axIds.getFromId;
19+
var isLinked = axIds.isLinked;
1820

1921
module.exports = {
2022
getAutoRange: getAutoRange,
@@ -56,8 +58,9 @@ function getAutoRange(gd, ax) {
5658
var i, j;
5759
var newRange = [];
5860

59-
var getPadMin = makePadFn(ax, 0);
60-
var getPadMax = makePadFn(ax, 1);
61+
var fullLayout = gd._fullLayout;
62+
var getPadMin = makePadFn(fullLayout, ax, 0);
63+
var getPadMax = makePadFn(fullLayout, ax, 1);
6164
var extremes = concatExtremes(gd, ax);
6265
var minArray = extremes.min;
6366
var maxArray = extremes.max;
@@ -202,13 +205,15 @@ function calcBreaksLength(ax, v0, v1) {
202205
* calculate the pixel padding for ax._min and ax._max entries with
203206
* optional extrapad as 5% of the total axis length
204207
*/
205-
function makePadFn(ax, max) {
208+
function makePadFn(fullLayout, ax, max) {
206209
// 5% padding for points that specify extrapad: true
207210
var extrappad = 0.05 * ax._length;
208211

212+
var anchorAxis = ax._anchorAxis || {};
213+
209214
if(
210215
(ax.ticklabelposition || '').indexOf('inside') !== -1 ||
211-
((ax._anchorAxis || {}).ticklabelposition || '').indexOf('inside') !== -1
216+
(anchorAxis.ticklabelposition || '').indexOf('inside') !== -1
212217
) {
213218
var axReverse = ax.autorange === 'reversed';
214219
if(!axReverse) {
@@ -218,8 +223,12 @@ function makePadFn(ax, max) {
218223
if(axReverse) max = !max;
219224
}
220225

221-
var A = padInsideLabelsOnAnchorAxis(ax, max);
222-
var B = padInsideLabelsOnThisAxis(ax, max);
226+
var A = 0;
227+
var B = 0;
228+
if(!isLinked(fullLayout, ax._id)) {
229+
A = padInsideLabelsOnAnchorAxis(ax, max);
230+
B = padInsideLabelsOnThisAxis(ax, max);
231+
}
223232

224233
var zero = Math.max(A, B);
225234
extrappad = Math.max(zero, extrappad);
@@ -273,7 +282,7 @@ function padInsideLabelsOnThisAxis(ax, max) {
273282

274283
function padInsideLabelsOnAnchorAxis(ax, max) {
275284
var pad = 0;
276-
var anchorAxis = (ax._anchorAxis || {});
285+
var anchorAxis = ax._anchorAxis || {};
277286
if((anchorAxis.ticklabelposition || '').indexOf('inside') !== -1) {
278287
// increase padding to make more room for inside tick labels of the counter axis
279288
if((

src/plots/cartesian/axes.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ axes.setConvert = require('./set_convert');
5656
var autoType = require('./axis_autotype');
5757

5858
var axisIds = require('./axis_ids');
59+
var idSort = axisIds.idSort;
60+
var isLinked = axisIds.isLinked;
61+
62+
// tight coupling to chart studio
5963
axes.id2name = axisIds.id2name;
6064
axes.name2id = axisIds.name2id;
6165
axes.cleanId = axisIds.cleanId;
@@ -2907,7 +2911,7 @@ axes.drawZeroLine = function(gd, ax, opts) {
29072911
// If several zerolines enter at the same time we will sort once per,
29082912
// but generally this should be a minimal overhead.
29092913
opts.layer.selectAll('path').sort(function(da, db) {
2910-
return axisIds.idSort(da.id, db.id);
2914+
return idSort(da.id, db.id);
29112915
});
29122916
});
29132917

@@ -3205,7 +3209,8 @@ axes.drawLabels = function(gd, ax, opts) {
32053209
var anchorAx = ax._anchorAxis;
32063210
if(
32073211
anchorAx && anchorAx.autorange &&
3208-
(ax.ticklabelposition || '').indexOf('inside') !== -1
3212+
(ax.ticklabelposition || '').indexOf('inside') !== -1 &&
3213+
!isLinked(fullLayout, ax._id)
32093214
) {
32103215
if(!fullLayout._insideTickLabelsAutorange) {
32113216
fullLayout._insideTickLabelsAutorange = {};

src/plots/cartesian/axis_ids.js

+16
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,19 @@ exports.ref2id = function(ar) {
136136
// return the axis ID. Otherwise it returns false.
137137
return (/^[xyz]/.test(ar)) ? ar.split(' ')[0] : false;
138138
};
139+
140+
function isFound(axId, list) {
141+
if(list && list.length) {
142+
for(var i = 0; i < list.length; i++) {
143+
if(list[i][axId]) return true;
144+
}
145+
}
146+
return false;
147+
}
148+
149+
exports.isLinked = function(fullLayout, axId) {
150+
return (
151+
isFound(axId, fullLayout._axisMatchGroups) ||
152+
isFound(axId, fullLayout._axisConstraintGroups)
153+
);
154+
};

src/plots/cartesian/constraints.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -565,8 +565,8 @@ exports.enforce = function enforce(gd) {
565565
// *are* expanding to the full domain
566566
var outerMin = rangeCenter - halfRange * factor * 1.0001;
567567
var outerMax = rangeCenter + halfRange * factor * 1.0001;
568-
var getPadMin = autorange.makePadFn(ax, 0);
569-
var getPadMax = autorange.makePadFn(ax, 1);
568+
var getPadMin = autorange.makePadFn(fullLayout, ax, 0);
569+
var getPadMax = autorange.makePadFn(fullLayout, ax, 1);
570570

571571
updateDomain(ax, factor);
572572
var m = Math.abs(ax._m);

src/plots/cartesian/layout_attributes.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,10 @@ module.exports = {
525525
'top or bottom has no effect on x axes or when `ticklabelmode` is set to *period*.',
526526
'Similarly',
527527
'left or right has no effect on y axes or when `ticklabelmode` is set to *period*.',
528-
'Has no effect on *multicategory* axes or when `tickson` is set to *boundaries*.'
528+
'Has no effect on *multicategory* axes or when `tickson` is set to *boundaries*.',
529+
'When used on axes linked by `matches` or `scaleanchor`,',
530+
'no extra padding for inside labels would be added by autorange,',
531+
'so that the scales could match.'
529532
].join(' ')
530533
},
531534
mirror: {
Loading
Loading
-9.86 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
{
2+
"data": [
3+
{"y":[1,2], "marker": {"color": "red"}},
4+
{"y":[1,2],"xaxis":"x2","yaxis":"y2", "marker": {"color": "red"}},
5+
{"y":[1,2],"xaxis":"x3","yaxis":"y3", "marker": {"color": "red"}},
6+
{"y":[1,2],"xaxis":"x4","yaxis":"y4", "marker": {"color": "red"}},
7+
{"y":[1,2],"xaxis":"x5","yaxis":"y5", "marker": {"color": "green"}},
8+
{"y":[1,2],"xaxis":"x6","yaxis":"y6", "marker": {"color": "green"}},
9+
{"y":[1,2],"xaxis":"x7","yaxis":"y7", "marker": {"color": "green"}},
10+
{"y":[1,2],"xaxis":"x8","yaxis":"y8", "marker": {"color": "green"}},
11+
{"y":[1,2],"xaxis":"x9","yaxis":"y9", "marker": {"color": "blue"}},
12+
{"y":[1,2],"xaxis":"x10","yaxis":"y10", "marker": {"color": "blue"}},
13+
{"y":[1,2],"xaxis":"x11","yaxis":"y11", "marker": {"color": "blue"}},
14+
{"y":[1,2],"xaxis":"x12","yaxis":"y12", "marker": {"color": "blue"}},
15+
{"y":[1,2],"xaxis":"x13","yaxis":"y13", "marker": {"color": "black"}},
16+
{"y":[1,2],"xaxis":"x14","yaxis":"y14", "marker": {"color": "black"}},
17+
{"y":[1,2],"xaxis":"x15","yaxis":"y15", "marker": {"color": "black"}},
18+
{"y":[1,2],"xaxis":"x16","yaxis":"y16", "marker": {"color": "black"}}
19+
],
20+
"layout": {
21+
"xaxis": {"ticklabelposition": "inside", "domain": [0, 0.2], "anchor": "y"},
22+
"yaxis": {"ticklabelposition": "inside", "domain": [0, 0.15], "anchor": "x", "matches": "x"},
23+
"xaxis2": {"ticklabelposition": "inside", "domain": [0.25, 0.45], "anchor": "y2", "scaleanchor": "y"},
24+
"yaxis2": {"ticklabelposition": "inside", "domain": [0, 0.15], "anchor": "x2", "matches": "x2"},
25+
"xaxis3": {"ticklabelposition": "inside", "domain": [0.5, 0.7], "anchor": "y3", "scaleanchor": "y2"},
26+
"yaxis3": {"ticklabelposition": "inside", "domain": [0, 0.15], "anchor": "x3", "matches": "x3"},
27+
"xaxis4": {"ticklabelposition": "inside", "domain": [0.75, 0.95], "anchor": "y4", "scaleanchor": "y3"},
28+
"yaxis4": {"ticklabelposition": "inside", "domain": [0, 0.15], "anchor": "x4", "matches": "x4"},
29+
30+
"xaxis5": {"ticklabelposition": "inside", "domain": [0, 0.2], "anchor": "y5", "constrain": "domain"},
31+
"yaxis5": {"ticklabelposition": "inside", "domain": [0.25, 0.4], "anchor": "x5", "matches": "x5", "constrain": "domain"},
32+
"xaxis6": {"ticklabelposition": "inside", "domain": [0.25, 0.45], "anchor": "y6", "scaleanchor": "y5", "constrain": "domain"},
33+
"yaxis6": {"ticklabelposition": "inside", "domain": [0.25, 0.4], "anchor": "x6", "matches": "x6", "constrain": "domain"},
34+
"xaxis7": {"ticklabelposition": "inside", "domain": [0.5, 0.7], "anchor": "y7", "scaleanchor": "y6", "constrain": "domain"},
35+
"yaxis7": {"ticklabelposition": "inside", "domain": [0.25, 0.4], "anchor": "x7", "matches": "x7", "constrain": "domain"},
36+
"xaxis8": {"ticklabelposition": "inside", "domain": [0.75, 0.95], "anchor": "y8", "scaleanchor": "y7", "constrain": "domain"},
37+
"yaxis8": {"ticklabelposition": "inside", "domain": [0.25, 0.4], "anchor": "x8", "matches": "x8", "constrain": "domain"},
38+
39+
"xaxis9": {"ticklabelposition": "inside", "domain": [0, 0.15], "anchor": "y9"},
40+
"yaxis9": {"ticklabelposition": "inside", "domain": [0.5, 0.7], "anchor": "x9", "matches": "x9"},
41+
"xaxis10": {"ticklabelposition": "inside", "domain": [0.25, 0.4], "anchor": "y10", "scaleanchor": "y9"},
42+
"yaxis10": {"ticklabelposition": "inside", "domain": [0.5, 0.7], "anchor": "x10", "matches": "x10"},
43+
"xaxis11": {"ticklabelposition": "inside", "domain": [0.5, 0.65], "anchor": "y11", "scaleanchor": "y10"},
44+
"yaxis11": {"ticklabelposition": "inside", "domain": [0.5, 0.7], "anchor": "x11", "matches": "x11"},
45+
"xaxis12": {"ticklabelposition": "inside", "domain": [0.75, 0.9], "anchor": "y12", "scaleanchor": "y11"},
46+
"yaxis12": {"ticklabelposition": "inside", "domain": [0.5, 0.7], "anchor": "x12", "matches": "x12"},
47+
48+
"xaxis13": {"ticklabelposition": "inside", "domain": [0, 0.15], "anchor": "y13", "constrain": "domain"},
49+
"yaxis13": {"ticklabelposition": "inside", "domain": [0.75, 0.95], "anchor": "x13", "matches": "x13", "constrain": "domain"},
50+
"xaxis14": {"ticklabelposition": "inside", "domain": [0.25, 0.4], "anchor": "y14", "scaleanchor": "y13", "constrain": "domain"},
51+
"yaxis14": {"ticklabelposition": "inside", "domain": [0.75, 0.95], "anchor": "x14", "matches": "x14", "constrain": "domain"},
52+
"xaxis15": {"ticklabelposition": "inside", "domain": [0.5, 0.65], "anchor": "y15", "scaleanchor": "y14", "constrain": "domain"},
53+
"yaxis15": {"ticklabelposition": "inside", "domain": [0.75, 0.95], "anchor": "x15", "matches": "x15", "constrain": "domain"},
54+
"xaxis16": {"ticklabelposition": "inside", "domain": [0.75, 0.9], "anchor": "y16", "scaleanchor": "y15", "constrain": "domain"},
55+
"yaxis16": {"ticklabelposition": "inside", "domain": [0.75, 0.95], "anchor": "x16", "matches": "x16", "constrain": "domain"},
56+
57+
"shapes": [
58+
{"x0": 0, "x1": 0.2, "y0": 0, "y1": 0.15, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
59+
{"x0": 0.25, "x1": 0.45, "y0": 0, "y1": 0.15, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
60+
{"x0": 0.5, "x1": 0.7, "y0": 0, "y1": 0.15, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
61+
{"x0": 0.75, "x1": 0.95, "y0": 0, "y1": 0.15, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
62+
{"x0": 0, "x1": 0.2, "y0": 0.25, "y1": 0.4, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
63+
{"x0": 0.25, "x1": 0.45, "y0": 0.25, "y1": 0.4, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
64+
{"x0": 0.5, "x1": 0.7, "y0": 0.25, "y1": 0.4, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
65+
{"x0": 0.75, "x1": 0.95, "y0": 0.25, "y1": 0.4, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
66+
{"x0": 0, "x1": 0.15, "y0": 0.5, "y1": 0.7, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
67+
{"x0": 0.25, "x1": 0.4, "y0": 0.5, "y1": 0.7, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
68+
{"x0": 0.5, "x1": 0.65, "y0": 0.5, "y1": 0.7, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
69+
{"x0": 0.75, "x1": 0.9, "y0": 0.5, "y1": 0.7, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
70+
{"x0": 0, "x1": 0.15, "y0": 0.75, "y1": 0.95, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
71+
{"x0": 0.25, "x1": 0.4, "y0": 0.75, "y1": 0.95, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
72+
{"x0": 0.5, "x1": 0.65, "y0": 0.75, "y1": 0.95, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}},
73+
{"x0": 0.75, "x1": 0.9, "y0": 0.75, "y1": 0.95, "type": "rect", "xref": "paper", "yref": "paper", "line": {"color": "#ccc", "dash": "dot"}}
74+
],
75+
"annotations": [{"x": 0, "y": 1, "xanchor": "left", "yanchor": "top", "xref": "paper", "yref": "paper", "showarrow": false, "align": "left", "text": "y matches same x, x scales to the previous y. Subplot aspect ratios compound"}],
76+
77+
"width": 500,
78+
"height": 500,
79+
"margin": {"l": 50, "r": 0, "t": 0, "b": 50},
80+
"showlegend": false
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"data": [
3+
{"z": [[1, 2], [3, 4], [5, 6]], "type": "heatmap", "showscale": false},
4+
{"z": [[1, 2, 3], [6, 5, 4]], "type": "heatmap", "xaxis": "x2", "yaxis": "y2", "showscale": false},
5+
{"z": [[1, 6], [2, 5], [3, 4]], "type": "heatmap", "xaxis": "x3", "yaxis": "y3", "showscale": false},
6+
{"z": [[1, 2, 3], [4, 5, 6]], "type": "heatmap", "xaxis": "x4", "yaxis": "y4", "showscale": false}
7+
],
8+
"layout": {
9+
"xaxis": {"ticklabelposition": "inside", "domain": [0, 0.4], "constrain": "domain"},
10+
"yaxis": {"ticklabelposition": "inside", "domain": [0, 0.3], "constrain": "domain", "scaleanchor": "x", "title": {"text": "constrain domain"}},
11+
"xaxis2": {"ticklabelposition": "inside", "domain": [0.6, 1], "matches": "x", "anchor": "y2", "title": {"text": "<- each right subplot matches<br>the axes left and below<br>and all are constrained<br>to square bricks."}},
12+
"yaxis2": {"ticklabelposition": "inside", "domain": [0.2, 0.5], "matches": "y", "anchor": "x2"},
13+
"xaxis3": {"ticklabelposition": "inside", "domain": [0, 0.4], "constrain": "range", "anchor": "y3"},
14+
"yaxis3": {"ticklabelposition": "inside", "domain": [0.5, 0.8], "constrain": "range", "scaleanchor": "x3", "anchor": "x3", "title": {"text": "constrain range"}},
15+
"xaxis4": {"ticklabelposition": "inside", "domain": [0.6, 1], "matches": "x3", "anchor": "y4"},
16+
"yaxis4": {"ticklabelposition": "inside", "domain": [0.7, 1], "matches": "y3", "anchor": "x4"},
17+
"shapes": [
18+
{"x0": 0, "x1": 0.4, "y0": 0, "y1": 0.3, "xref": "paper", "yref": "paper", "type": "rect", "line": {"color": "#888", "dash": "dot"}},
19+
{"x0": 0.6, "x1": 1, "y0": 0.2, "y1": 0.5, "xref": "paper", "yref": "paper", "type": "rect", "line": {"color": "#888", "dash": "dot"}},
20+
{"x0": 0, "x1": 0.4, "y0": 0.5, "y1": 0.8, "xref": "paper", "yref": "paper", "type": "rect", "line": {"color": "#888", "dash": "dot"}},
21+
{"x0": 0.6, "x1": 1, "y0": 0.7, "y1": 1, "xref": "paper", "yref": "paper", "type": "rect", "line": {"color": "#888", "dash": "dot"}}
22+
],
23+
"width": 700,
24+
"height": 600
25+
}
26+
}

test/image/mocks/ticklabelposition-3.json

+9-4
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@
2828
}, {
2929
"xaxis": "x3",
3030
"yaxis": "y3",
31-
"type": "scatter",
32-
"mode": "lines",
33-
"x": [-100, 0, 100],
34-
"y": [-100, 0, 100]
31+
"type": "image",
32+
"z": [
33+
[[255, 0, 0], [255, 255, 0], [0, 255, 0], [0, 255, 255], [0, 0, 255], [255, 0, 255]],
34+
[[255, 255, 0], [0, 255, 0], [0, 255, 255], [0, 0, 255], [255, 0, 255], [255, 0, 0]],
35+
[[0, 255, 0], [0, 255, 255], [0, 0, 255], [255, 0, 255], [255, 0, 0], [255, 255, 0]],
36+
[[0, 255, 255], [0, 0, 255], [255, 0, 255], [255, 0, 0], [255, 255, 0], [0, 255, 0]],
37+
[[0, 0, 255], [255, 0, 255], [255, 0, 0], [255, 255, 0], [0, 255, 0], [0, 255, 255]],
38+
[[255, 0, 255], [255, 0, 0], [255, 255, 0], [0, 255, 0], [0, 255, 255], [0, 0, 255]]
39+
]
3540
}, {
3641
"xaxis": "x4",
3742
"yaxis": "y4",

test/jasmine/tests/mock_test.js

+4
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ var list = [
8484
'axes_category_null',
8585
'axes_chain_scaleanchor_matches',
8686
'axes_chain_scaleanchor_matches2',
87+
'axes_chain_scaleanchor_matches_inside-ticklabels',
88+
'axes_chain_scaleanchor_matches2_inside-ticklabels',
8789
'axes_custom-ticks_log-date',
8890
'axes_enumerated_ticks',
8991
'axes_free_default',
@@ -1173,6 +1175,8 @@ figs['axes_category_categoryarray_truncated_tails'] = require('@mocks/axes_categ
11731175
figs['axes_category_null'] = require('@mocks/axes_category_null');
11741176
figs['axes_chain_scaleanchor_matches'] = require('@mocks/axes_chain_scaleanchor_matches');
11751177
figs['axes_chain_scaleanchor_matches2'] = require('@mocks/axes_chain_scaleanchor_matches2');
1178+
figs['axes_chain_scaleanchor_matches_inside-ticklabels'] = require('@mocks/axes_chain_scaleanchor_matches_inside-ticklabels');
1179+
figs['axes_chain_scaleanchor_matches2_inside-ticklabels'] = require('@mocks/axes_chain_scaleanchor_matches2_inside-ticklabels');
11761180
figs['axes_custom-ticks_log-date'] = require('@mocks/axes_custom-ticks_log-date');
11771181
figs['axes_enumerated_ticks'] = require('@mocks/axes_enumerated_ticks');
11781182
figs['axes_free_default'] = require('@mocks/axes_free_default');

0 commit comments

Comments
 (0)