Skip to content

Commit 05d6de2

Browse files
authored
Merge pull request #6356 from VictorBezak/first_poc_tickmode_sync
Add sync option to `tickmode` of cartesian axes to sync ticks with `overlaying` axis
2 parents 8acb04a + 25e1389 commit 05d6de2

File tree

14 files changed

+207
-18
lines changed

14 files changed

+207
-18
lines changed

Diff for: draftlogs/6356_add.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Add `sync` tickmode option [[#6356](https://github.com/plotly/plotly.js/pull/6356)]

Diff for: src/components/colorbar/attributes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ module.exports = overrideAll({
129129
description: 'Sets the color of padded area.'
130130
},
131131
// tick and title properties named and function exactly as in axes
132-
tickmode: axesAttrs.tickmode,
132+
tickmode: axesAttrs.minor.tickmode,
133133
nticks: axesAttrs.nticks,
134134
tick0: axesAttrs.tick0,
135135
dtick: axesAttrs.dtick,

Diff for: src/plots/cartesian/axes.js

+70-6
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,13 @@ axes.calcTicks = function calcTicks(ax, opts) {
951951
continue;
952952
}
953953

954+
// fill tickVals based on overlaying axis
955+
if(mockAx.tickmode === 'sync') {
956+
tickVals = [];
957+
ticksOut = syncTicks(ax);
958+
continue;
959+
}
960+
954961
// add a tiny bit so we get ticks which may have rounded out
955962
var exRng = expandRange(rng);
956963
var startTick = exRng[0];
@@ -1203,6 +1210,51 @@ axes.calcTicks = function calcTicks(ax, opts) {
12031210
return ticksOut;
12041211
};
12051212

1213+
function filterRangeBreaks(ax, ticksOut) {
1214+
if(ax.rangebreaks) {
1215+
// remove ticks falling inside rangebreaks
1216+
ticksOut = ticksOut.filter(function(d) {
1217+
return ax.maskBreaks(d.x) !== BADNUM;
1218+
});
1219+
}
1220+
1221+
return ticksOut;
1222+
}
1223+
1224+
function syncTicks(ax) {
1225+
// get the overlaying axis
1226+
var baseAxis = ax._mainAxis;
1227+
1228+
var ticksOut = [];
1229+
if(baseAxis._vals) {
1230+
for(var i = 0; i < baseAxis._vals.length; i++) {
1231+
// filter vals with noTick flag
1232+
if(baseAxis._vals[i].noTick) {
1233+
continue;
1234+
}
1235+
1236+
// get the position of the every tick
1237+
var pos = baseAxis.l2p(baseAxis._vals[i].x);
1238+
1239+
// get the tick for the current axis based on position
1240+
var vali = ax.p2l(pos);
1241+
var obj = axes.tickText(ax, vali);
1242+
1243+
// assign minor ticks
1244+
if(baseAxis._vals[i].minor) {
1245+
obj.minor = true;
1246+
obj.text = '';
1247+
}
1248+
1249+
ticksOut.push(obj);
1250+
}
1251+
}
1252+
1253+
ticksOut = filterRangeBreaks(ax, ticksOut);
1254+
1255+
return ticksOut;
1256+
}
1257+
12061258
function arrayTicks(ax) {
12071259
var rng = Lib.simpleMap(ax.range, ax.r2l);
12081260
var exRng = expandRange(rng);
@@ -1249,12 +1301,7 @@ function arrayTicks(ax) {
12491301
}
12501302
}
12511303

1252-
if(ax.rangebreaks) {
1253-
// remove ticks falling inside rangebreaks
1254-
ticksOut = ticksOut.filter(function(d) {
1255-
return ax.maskBreaks(d.x) !== BADNUM;
1256-
});
1257-
}
1304+
ticksOut = filterRangeBreaks(ax, ticksOut);
12581305

12591306
return ticksOut;
12601307
}
@@ -2256,6 +2303,18 @@ axes.draw = function(gd, arg, opts) {
22562303
return ax.overlaying;
22572304
});
22582305

2306+
// order axes that have dependency to other axes
2307+
axList.map(function(axId) {
2308+
var ax = axes.getFromId(gd, axId);
2309+
2310+
if(ax.tickmode === 'sync' && ax.overlaying) {
2311+
var overlayingIndex = axList.findIndex(function(axis) {return axis === ax.overlaying;});
2312+
2313+
if(overlayingIndex >= 0) {
2314+
axList.unshift(axList.splice(overlayingIndex, 1).shift());
2315+
}
2316+
}
2317+
});
22592318

22602319
var axShifts = {'false': {'left': 0, 'right': 0}};
22612320

@@ -3247,6 +3306,11 @@ axes.drawTicks = function(gd, ax, opts) {
32473306
axes.drawGrid = function(gd, ax, opts) {
32483307
opts = opts || {};
32493308

3309+
if(ax.tickmode === 'sync') {
3310+
// for tickmode sync we use the overlaying axis grid
3311+
return;
3312+
}
3313+
32503314
var cls = ax._id + 'grid';
32513315

32523316
var hasMinor = ax.minor && ax.minor.showgrid;

Diff for: src/plots/cartesian/dragbox.js

+8
Original file line numberDiff line numberDiff line change
@@ -727,15 +727,23 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
727727
}
728728
}
729729

730+
function pushActiveAxIdsSynced(axList, axisType) {
731+
for(i = 0; i < axList.length; i++) {
732+
if(!axList[i].fixedrange && axList[i][axisType]) {activeAxIds.push(axList[i][axisType]._id);}
733+
}
734+
}
735+
730736
if(editX) {
731737
pushActiveAxIds(xaxes);
732738
pushActiveAxIds(links.xaxes);
733739
pushActiveAxIds(matches.xaxes);
740+
pushActiveAxIdsSynced(plotinfo.overlays, 'xaxis');
734741
}
735742
if(editY) {
736743
pushActiveAxIds(yaxes);
737744
pushActiveAxIds(links.yaxes);
738745
pushActiveAxIds(matches.yaxes);
746+
pushActiveAxIdsSynced(plotinfo.overlays, 'yaxis');
739747
}
740748

741749
updates = {};

Diff for: src/plots/cartesian/layout_attributes.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var constants = require('./constants');
1212
var HOUR = constants.HOUR_PATTERN;
1313
var DAY_OF_WEEK = constants.WEEKDAY_PATTERN;
1414

15-
var tickmode = {
15+
var minorTickmode = {
1616
valType: 'enumerated',
1717
values: ['auto', 'linear', 'array'],
1818
editType: 'ticks',
@@ -29,6 +29,15 @@ var tickmode = {
2929
].join(' ')
3030
};
3131

32+
var tickmode = extendFlat({}, minorTickmode, {
33+
values: minorTickmode.values.slice().concat(['sync']),
34+
description: [
35+
minorTickmode.description,
36+
'If *sync*, the number of ticks will sync with the overlayed axis',
37+
'set by `overlaying` property.'
38+
].join(' ')
39+
});
40+
3241
function makeNticks(minor) {
3342
return {
3443
valType: 'integer',
@@ -947,7 +956,7 @@ module.exports = {
947956
},
948957

949958
minor: {
950-
tickmode: tickmode,
959+
tickmode: minorTickmode,
951960
nticks: makeNticks('minor'),
952961
tick0: tick0,
953962
dtick: dtick,

Diff for: src/plots/cartesian/position_defaults.js

+6
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ module.exports = function handlePositionDefaults(containerIn, containerOut, coer
8383
// which applied in the calculation below:
8484
if(domain[0] > domain[1] - 1 / 4096) containerOut.domain = dfltDomain;
8585
Lib.noneOrAll(containerIn.domain, containerOut.domain, dfltDomain);
86+
87+
// tickmode sync needs an overlaying axis, otherwise
88+
// we should default it to 'auto'
89+
if(containerOut.tickmode === 'sync') {
90+
containerOut.tickmode = 'auto';
91+
}
8692
}
8793

8894
coerce('layer');

Diff for: src/plots/cartesian/tick_value_defaults.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ module.exports = function handleTickValueDefaults(containerIn, containerOut, coe
2626
'auto';
2727
var tickmode = coerce(prefix + 'tickmode', tickmodeDefault);
2828

29-
if(tickmode === 'auto') {
29+
if(tickmode === 'auto' || tickmode === 'sync') {
3030
coerce(prefix + 'nticks');
3131
} else if(tickmode === 'linear') {
3232
// dtick is usually a positive number, but there are some

Diff for: src/plots/gl3d/layout/axis_attributes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ module.exports = overrideAll({
7474
anim: false
7575
}),
7676
// ticks
77-
tickmode: axesAttrs.tickmode,
77+
tickmode: axesAttrs.minor.tickmode,
7878
nticks: axesAttrs.nticks,
7979
tick0: axesAttrs.tick0,
8080
dtick: axesAttrs.dtick,

Diff for: src/plots/polar/layout_attributes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var axisLineGridAttr = overrideAll({
2323
}, 'plot', 'from-root');
2424

2525
var axisTickAttrs = overrideAll({
26-
tickmode: axesAttrs.tickmode,
26+
tickmode: axesAttrs.minor.tickmode,
2727
nticks: axesAttrs.nticks,
2828
tick0: axesAttrs.tick0,
2929
dtick: axesAttrs.dtick,

Diff for: src/plots/ternary/layout_attributes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ var ternaryAxesAttrs = {
1515
},
1616
color: axesAttrs.color,
1717
// ticks
18-
tickmode: axesAttrs.tickmode,
18+
tickmode: axesAttrs.minor.tickmode,
1919
nticks: extendFlat({}, axesAttrs.nticks, {dflt: 6, min: 1}),
2020
tick0: axesAttrs.tick0,
2121
dtick: axesAttrs.dtick,

Diff for: src/traces/indicator/attributes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ module.exports = {
307307
dflt: true
308308
}),
309309
// tick and title properties named and function exactly as in axes
310-
tickmode: axesAttrs.tickmode,
310+
tickmode: axesAttrs.minor.tickmode,
311311
nticks: axesAttrs.nticks,
312312
tick0: axesAttrs.tick0,
313313
dtick: axesAttrs.dtick,

Diff for: test/image/baselines/z-new_tickmode_sync.png

45.3 KB
Loading

Diff for: test/image/mocks/z-new_tickmode_sync.json

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
{
2+
"data": [
3+
{
4+
"name": "Apples",
5+
"type": "bar",
6+
"x": [
7+
"2000-01",
8+
"2000-02",
9+
"2000-03",
10+
"2000-04",
11+
"2000-05"
12+
],
13+
"y": [
14+
232,
15+
2506,
16+
470,
17+
1864,
18+
-190
19+
]
20+
},
21+
{
22+
"name": "Oranges",
23+
"type": "scatter",
24+
"x": [
25+
"A",
26+
"B",
27+
"C",
28+
"D",
29+
"E"
30+
],
31+
"y": [
32+
0,
33+
0.4,
34+
0.1,
35+
0.3,
36+
0.2
37+
],
38+
"yaxis": "y2",
39+
"xaxis": "x2"
40+
}
41+
],
42+
"layout": {
43+
"margin": {
44+
"t": 40,
45+
"r": 70,
46+
"b": 40,
47+
"l": 70
48+
},
49+
"width": 700,
50+
"showlegend": false,
51+
"xaxis": {
52+
"showgrid": true,
53+
"ticklen": 10,
54+
"tickwidth": 3,
55+
"ticklabelmode": "period"
56+
},
57+
"xaxis2": {
58+
"anchor": "y2",
59+
"side": "top",
60+
"overlaying": "x",
61+
"tickmode": "sync",
62+
"ticklen": 10,
63+
"tickwidth": 3
64+
},
65+
"yaxis": {
66+
"title": {
67+
"text": "Apples"
68+
},
69+
"side": "left",
70+
"range": [
71+
0,
72+
2500
73+
],
74+
"ticklen": 10,
75+
"tickwidth": 3,
76+
"minor": {
77+
"showgrid": true
78+
}
79+
},
80+
"yaxis2": {
81+
"title": {
82+
"text": "Oranges"
83+
},
84+
"side": "right",
85+
"range": [
86+
0,
87+
0.5
88+
],
89+
"ticklen": 10,
90+
"tickwidth": 3,
91+
"overlaying": "y",
92+
"tickmode": "sync",
93+
"minor": {
94+
"showgrid": true
95+
},
96+
"zeroline": false
97+
}
98+
}
99+
}

Diff for: test/plot-schema.json

+6-4
Original file line numberDiff line numberDiff line change
@@ -11005,14 +11005,15 @@
1100511005
"valType": "number"
1100611006
},
1100711007
"tickmode": {
11008-
"description": "Sets the tick mode for this axis. If *auto*, the number of ticks is set via `nticks`. If *linear*, the placement of the ticks is determined by a starting position `tick0` and a tick step `dtick` (*linear* is the default value if `tick0` and `dtick` are provided). If *array*, the placement of the ticks is set via `tickvals` and the tick text is `ticktext`. (*array* is the default value if `tickvals` is provided).",
11008+
"description": "Sets the tick mode for this axis. If *auto*, the number of ticks is set via `nticks`. If *linear*, the placement of the ticks is determined by a starting position `tick0` and a tick step `dtick` (*linear* is the default value if `tick0` and `dtick` are provided). If *array*, the placement of the ticks is set via `tickvals` and the tick text is `ticktext`. (*array* is the default value if `tickvals` is provided). If *sync*, the number of ticks will sync with the overlayed axis set by `overlaying` property.",
1100911009
"editType": "ticks",
1101011010
"impliedEdits": {},
1101111011
"valType": "enumerated",
1101211012
"values": [
1101311013
"auto",
1101411014
"linear",
11015-
"array"
11015+
"array",
11016+
"sync"
1101611017
]
1101711018
},
1101811019
"tickprefix": {
@@ -12013,14 +12014,15 @@
1201312014
"valType": "number"
1201412015
},
1201512016
"tickmode": {
12016-
"description": "Sets the tick mode for this axis. If *auto*, the number of ticks is set via `nticks`. If *linear*, the placement of the ticks is determined by a starting position `tick0` and a tick step `dtick` (*linear* is the default value if `tick0` and `dtick` are provided). If *array*, the placement of the ticks is set via `tickvals` and the tick text is `ticktext`. (*array* is the default value if `tickvals` is provided).",
12017+
"description": "Sets the tick mode for this axis. If *auto*, the number of ticks is set via `nticks`. If *linear*, the placement of the ticks is determined by a starting position `tick0` and a tick step `dtick` (*linear* is the default value if `tick0` and `dtick` are provided). If *array*, the placement of the ticks is set via `tickvals` and the tick text is `ticktext`. (*array* is the default value if `tickvals` is provided). If *sync*, the number of ticks will sync with the overlayed axis set by `overlaying` property.",
1201712018
"editType": "ticks",
1201812019
"impliedEdits": {},
1201912020
"valType": "enumerated",
1202012021
"values": [
1202112022
"auto",
1202212023
"linear",
12023-
"array"
12024+
"array",
12025+
"sync"
1202412026
]
1202512027
},
1202612028
"tickprefix": {

0 commit comments

Comments
 (0)