Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ecd3c76
Calculate hidden minor ticks if ticklabelindex is set.
my-tien Mar 27, 2026
4366ed7
Add draftlog for PR 7735
my-tien Mar 27, 2026
52a00cb
Fix missing trailing newline char in new mocks
my-tien Mar 27, 2026
081da50
Baseline images for testing ticklabelindex when minor ticks are hidden
my-tien Mar 30, 2026
a3cc377
Fix accidental drawing of additional minor tick before tick0.
my-tien Apr 27, 2026
92c800a
Update baseline images for date_axes_period_ticklabelindex and date_a…
my-tien Apr 27, 2026
e3f9006
Merge remote-tracking branch 'origin-plotly/master' into calculate-hi…
my-tien Apr 27, 2026
3d9714c
Update baseline images for date_axes_period_ticklabelindex and date_a…
my-tien Apr 27, 2026
e85de13
Change draftlog from change to fix
my-tien Apr 29, 2026
202ea7b
Merge new mocks for ticklabelindex on figures with hidden minor ticks…
my-tien Apr 29, 2026
5861fc5
Revert code style for checking if the label should be hidden to how i…
my-tien Apr 29, 2026
474daa5
Add minor tick dtick and tick0 for new ticklabelindex mock
my-tien Apr 29, 2026
60b5d66
Revert "Revert code style for checking if the label should be hidden …
my-tien Apr 29, 2026
f5700e9
Refactor logic for skipLabel flag in combination with ticklabelindex
my-tien May 4, 2026
af9a2f3
Explain in comments why minor ticks need an additional tick in the ca…
my-tien May 4, 2026
50a7135
Baseline image for ticklabelindex-hidden-minor-ticks
my-tien May 4, 2026
71ba43a
Delete test/image/baselines/zz-ticklabelindex-hidden-minor-ticks-dtic…
emilykl May 4, 2026
5bed43e
Delete test/image/baselines/zz-ticklabelindex-hidden-minor-ticks-one-…
emilykl May 4, 2026
2bde37f
Delete test/image/baselines/zz-ticklabelindex-hidden-minor-ticks-tick…
emilykl May 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions draftlogs/7735_fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Fix unexpected `ticklabelindex` behavior when minor ticks are not shown. [[#7735](https://github.com/plotly/plotly.js/pull/7735)]
44 changes: 30 additions & 14 deletions src/plots/cartesian/axes.js
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ function autoShiftMonthBins(binStart, data, dtick, dataMin, calendar) {

// ensure we have minor tick0 and dtick calculated
axes.prepMinorTicks = function(mockAx, ax, opts) {
if(!ax.minor.dtick) {
if(!ax.minor?.dtick) {
delete mockAx.dtick;
var hasMajor = ax.dtick && isNumeric(ax._tmin);
var mockMinorRange;
Expand Down Expand Up @@ -690,7 +690,7 @@ axes.prepMinorTicks = function(mockAx, ax, opts) {
// put back the original range, to use to find the full set of minor ticks
mockAx.range = ax.range;
}
if(ax.minor._tick0Init === undefined) {
if(ax.minor?._tick0Init === undefined) {
// ensure identical tick0
mockAx.tick0 = ax.tick0;
}
Expand Down Expand Up @@ -973,21 +973,23 @@ axes.calcTicks = function calcTicks(ax, opts) {
var allTicklabelVals = [];

var hasMinor = ax.minor && (ax.minor.ticks || ax.minor.showgrid);
// minor ticks should be calculated if they are visible or if ticklabelindex is set because then
// the labels are placed at minor ticks (even if invisible) instead of major ticks.
var calcMinor = hasMinor || ticklabelIndex;

// calc major first
for(var major = 1; major >= (hasMinor ? 0 : 1); major--) {
for(var major = 1; major >= (calcMinor ? 0 : 1); major--) {
var isMinor = !major;

if(major) {
ax._dtickInit = ax.dtick;
ax._tick0Init = ax.tick0;
} else {
} else if (hasMinor) {
ax.minor._dtickInit = ax.minor.dtick;
ax.minor._tick0Init = ax.minor.tick0;
}

var mockAx = major ? ax : Lib.extendFlat({}, ax, ax.minor);

var mockAx = major ? ax : Lib.extendFlat({}, ax, hasMinor ? ax.minor : {"minor": {}});
if(isMinor) {
axes.prepMinorTicks(mockAx, ax, opts);
} else {
Expand Down Expand Up @@ -1074,10 +1076,13 @@ axes.calcTicks = function calcTicks(ax, opts) {
}
}

if(major && isPeriod) {
// add one item to label period before tick0
if((major || ticklabelIndex) && isPeriod) {
// if major: add one item to label period before tick0
// if minor: add one item for ticklabelindex positioning. positionPeriodTicks requires
// at least 2 ticks to calculate the period length, so we add a dummy tick, ensuring
// that if a tick is labeled, there are always at least 2 ticks.
x = axes.tickIncrement(x, dtick, !axrev, calendar);
majorId--;
if (major) majorId--;
}

for(;
Expand Down Expand Up @@ -1125,13 +1130,17 @@ axes.calcTicks = function calcTicks(ax, opts) {
}
}

// check if ticklabelIndex makes sense, otherwise ignore it
if(!minorTickVals || minorTickVals.length < 2) {
// check if ticklabelIndex makes sense, otherwise ignore it.
// It makes sense if in addition to the always present dummy, there are at least 2 minor ticks
// with the required distance to each other.
if(!minorTickVals || minorTickVals.length < 3) {
Comment thread
emilykl marked this conversation as resolved.
ticklabelIndex = false;
} else {
var diff = (minorTickVals[1].value - minorTickVals[0].value) * (isReversed ? -1 : 1);
var diff = (minorTickVals[2].value - minorTickVals[1].value) * (isReversed ? -1 : 1);
if(!periodCompatibleWithTickformat(diff, ax.tickformat)) {
ticklabelIndex = false;
// remove previously added tick before tick0 for handling ticklabelindex positioning
minorTickVals = minorTickVals.slice(1);
}
}
// Determine for which ticks to draw labels
Expand Down Expand Up @@ -1169,6 +1178,9 @@ axes.calcTicks = function calcTicks(ax, opts) {
}
});
});
tickVals.forEach(function(tick) {
tick.skipLabel = allTicklabelVals.indexOf(tick) === -1;
});
}

if(hasMinor) {
Expand Down Expand Up @@ -1298,14 +1310,18 @@ axes.calcTicks = function calcTicks(ax, opts) {
} else {
lastVisibleHead = ax._prevDateHead;
t = setTickLabel(ax, tickVals[i]);
if(tickVals[i].skipLabel ||
ticklabelIndex && allTicklabelVals.indexOf(tickVals[i]) === -1) {
if (tickVals[i].skipLabel) {
hideLabel(t);
}

ticksOut.push(t);
}
}

if(isPeriod && ticklabelIndex && minorTicks.length) {
// drop very first minor tick that we added to handle ticklabelindex
minorTicks[0].noTick = true;
}
ticksOut = ticksOut.concat(minorTicks);

ax._inCalcTicks = false;
Expand Down
Binary file modified test/image/baselines/date_axes_period2_ticklabelindex.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/date_axes_period_ticklabelindex.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
94 changes: 94 additions & 0 deletions test/image/mocks/ticklabelindex-hidden-minor-ticks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"data": [
{
"showlegend": false,
"x": [
"2023-01-01",
"2024-01-01",
"2025-01-01",
"2026-01-01",
"2027-01-01"
],
"type": "scatter",
"xaxis": "x",
"yaxis": "y"
},
{
"showlegend": false,
"x": [
"2023-01-01",
"2024-01-01",
"2025-01-01",
"2026-01-01"
],
"type": "scatter",
"xaxis": "x2",
"yaxis": "y2"
},
{
"showlegend": false,
"x": [
"2023-01-01",
"2024-01-01",
"2025-01-01",
"2026-01-01",
"2027-01-01"
],
"type": "scatter",
"xaxis": "x3",
"yaxis": "y3"
}
],
"layout": {
"width": 700,
"height": 700,
"grid": {
"rows": 3,
"columns": 1,
"pattern": "independent"
},
"xaxis": {
"ticklen": 20,
"ticklabelindex": -1,
"tickformat": "%Y",
"ticklabelmode": "period",
"dtick": "M24",
"minor": {
"dtick": "M12",
"tick0": "2023-01-01"
},
"title": {
"text": "Should display 2 ticks and labels 2023 and 2025 to the left of them."
}
},
"xaxis2": {
"ticklen": 20,
"ticklabelindex": -2,
"tickformat": "%Y",
"ticklabelmode": "period",
"dtick": "M24",
"minor": {
"dtick": "M12",
"tick0": "2023-01-01"
},
"title": {
"text": "Should display a label at 2024"
}
},
"xaxis3": {
"ticklen": 20,
"ticklabelindex": -1,
"tickformat": "%Y",
"ticklabelmode": "period",
"ticklabelstep": 2,
"dtick": "M12",
"minor": {
"dtick": "M12",
"tick0": "2023-01-01"
},
"title": {
"text": "Should display yearly ticks with labels at 2023 and 2025"
}
}
}
}
Loading