How to define the (minimum) number of ticks with "ytick mode auto"

14 views (last 30 days)
Hi, to emphasize possible nonlinearities in scaling I need to have a minimum number of ticks, more than two for positive data, or mor than three for data if zero is included.
I am aware of all the "official" properties, such as YLim, YTick, YTickMode, YTickLabel, etc.,
But how to get more than three ticks when data are centered around zero automatically?
Or, when using the manual mode, how to get "nice numbers" as it is done within the "auto" tick mode function? E.g., such that Zero is included, the data are "round" and symmetric?
  13 Comments
Andre Zeug
Andre Zeug on 4 Sep 2025
Many thanks for clarifying!
Thanks to your explanation I found the full desciption of Operator Precedence in MATLAB.
Sam Chak
Sam Chak on 5 Sep 2025
Hi @Andre Zeug, Thanks for your updates. It is good to know that you have adopted @Stephen23's niceTicks(). If you find the solution helpful and satisfactory, please consider clicking 'Accept' ✔ on his answer, as well as voting for other helpful contributions by the others.

Sign in to comment.

Answers (1)

Stephen23
Stephen23 on 4 Sep 2025
Axes do not expose a “minimum tick count” property. In auto mode the tick positions are chosen internally from the axis limits, the figure size and the font size; you cannot tell the axes to “use at least N ticks”. The only time you have full control over tick placement is when you switch the ruler into manual mode and set the TickValues/YTick vector yourself:
If you want a custom number of ticks with “nice” values you therefore have to compute the ticks and pass them to the axis. There is no built‑in function that does this automatically, but you can implement the common “nice number” algorithm. The idea is to compute a raw spacing equal to (maxVal–minVal)/(numTicks-1), round this to a “nice” value (multiples of 1, 2, 2.5, 5, … × 10^n), and then generate tick positions that include zero if it lies in the range. Below is one possible implementation that tries to hit your requested number of ticks but uses “nice” spacing. When zero is in the range an odd number of ticks gives a symmetrical tick at zero; even numbers are likely to require an extra tick.
function ticks = niceTicks(minVal,maxVal,numTicks)
if minVal==maxVal
ticks = minVal;
return
elseif minVal>maxVal
[minVal,maxVal] = deal(maxVal,minVal);
end
includeZero = (minVal <= 0 && maxVal >= 0);
% Raw spacing and exponent
rawStep = (maxVal-minVal)./(numTicks-1);
exponent = floor(log10(rawStep));
baseStep = 10.^exponent;
% Candidate multipliers for “nice” spacing
mult = [1,2,2.5,5,10];
bestDiff = Inf;
for m = mult
step = m*baseStep;
tMin = floor(minVal/step)*step;
tMax = ceil (maxVal/step)*step;
ticks = tMin:step:tMax;
if includeZero && ~ismember(0,ticks), ticks = sort([ticks 0]); end
ticks = ticks(ticks>=minVal & ticks<=maxVal);
difft = abs(numel(ticks) - numTicks);
if difft < bestDiff || (difft==bestDiff && numel(ticks)>=numTicks)
bestTicks = ticks;
bestDiff = difft;
end
end
ticks = bestTicks;
end
You can call this function and then set the axis ticks manually:
x = linspace(0,10,100);
y = sin(x);
numTicks = 5;
ticks = niceTicks(min(y),max(y),numTicks)
ticks = 1×7
-0.7500 -0.5000 -0.2500 0 0.2500 0.5000 0.7500
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
plot(x,y);
ylim([min(y) max(y)]);
set(gca,'YTick',ticks) % fix tick positions
For your examples:
niceTicks(-5,5,5)
ans = 1×5
-5.0000 -2.5000 0 2.5000 5.0000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
niceTicks(-0.17,0.12,5) % (six ticks because of zero)
ans = 1×6
-0.1500 -0.1000 -0.0500 0 0.0500 0.1000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
niceTicks(0.003,0.12,5)
ans = 1×6
0.0200 0.0400 0.0600 0.0800 0.1000 0.1200
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
This approach gives you “round” tick values and includes zero when it lies in the range. When the requested count cannot be achieved exactly with “nice” spacing, the function favours having more ticks rather than fewer so that the non‑linear scaling is visible. If you need an exact number of tick labels regardless of “niceness” you can fall back on a simple linspace(minVal,maxVal,numTicks) call and use sprintf or YTickLabelFormat to format the numbers.
  2 Comments
Andre Zeug
Andre Zeug on 4 Sep 2025
Edited: Andre Zeug on 4 Sep 2025
amost PERFECT!
Your function uses ore ore less the same strategy as mine, but better!
However
niceTicks(-1.5, 1.5, 4)
ans =
-1 0 1
provides 3 instead of at least 4 niceTicks
I changed 2 lines in your function, but still it is a bit curious to me
function ticks = niceTicks(minVal, maxVal, numTicks)
if minVal==maxVal
ticks = minVal;
return
elseif minVal>maxVal
[minVal,maxVal] = deal(maxVal,minVal);
end
includeZero = (minVal <= 0 && maxVal >= 0);
% Raw spacing and exponent
rawStep = (maxVal-minVal)./(numTicks-1+includeZero);
exponent = floor(log10(rawStep));
baseStep = 10.^exponent;
% Candidate multipliers for “nice” spacing
mult = [1,2,2.5,5,10];
bestDiff = Inf;
for m = mult
step = m*baseStep;
tMin = floor(minVal/step)*step;
tMax = ceil (maxVal/step)*step;
ticks = tMin:step:tMax;
if includeZero && ~ismember(0,ticks), ticks = sort([ticks 0]); end
ticks = ticks(ticks>=minVal & ticks<=maxVal);
difft = abs(numel(ticks) - numTicks);
if numel(ticks) >= numTicks && (difft < bestDiff || (difft==bestDiff && numel(ticks)>=numTicks))
bestTicks = ticks;
bestDiff = difft;
end
end
ticks = bestTicks;
end
I chaned
rawStep = (maxVal-minVal)./(numTicks-1+includeZero);
and
if numel(ticks) >= numTicks && (difft < bestDiff || (difft==bestDiff && numel(ticks)>=numTicks))
but did not understand, what the "abs" in
difft = abs(numel(ticks) - numTicks);
is good for.
I have the feeling that your function could still be improved, because due to my changes some parts are unnecessary or redundant. But maybe I'm wrong.
Andre Zeug
Andre Zeug on 6 Sep 2025
I further refined your function. Now I think it does what MATLABs internal function does anyway + the minimum number of ticks can be controlled by the 3rd input parameter rather than by axe and font size.
function ticks = niceTicks(minVal, maxVal, numTicks)
% ticks = niceTicks(minVal, maxVal, numTicks)
%
% Generates a set of "nice", i.e., most round ticks for a given minimum
% number of values.
%
% Inputs:
% minVal: The minimum value of the range.
% maxVal: The maximum value of the range.
% numTicks: The minimum number of ticks.
%
% Outputs:
% ticks: A vector of "nice" tick values, which are evenly spaced
% within the specified range, with zero included if it falls within
% the range or zero would be included if the range would be
% extended.
% So it returns [-.2 0 .2 ...] rather than [-.1 .1 .3 ...],
% or [1.2 1.4 1.6 ...] rather than [1.1 1.3 1.5 ...].
if minVal == maxVal
ticks = minVal;
return;
elseif minVal > maxVal
[minVal, maxVal] = deal(maxVal, minVal);
end
% Include zero if it lies within the range
includeZero = (minVal <= 0 && maxVal >= 0);
% Calculate raw step and exponent
rawStep = (maxVal - minVal) / (numTicks - 1 + includeZero);
exponent = floor(log10(rawStep));
baseStep = 10^exponent;
% Candidate multipliers for "nice" spacing
mult = [1, 2, 2.5, 5, 10];
bestTicks = [];
bestDiff = Inf;
% Calculate ticks according to multipliers
for m = mult
step = m * baseStep;
tMin = floor(minVal / step) * step;
tMax = ceil(maxVal / step) * step;
ticks = tMin:step:tMax;
ticks = ticks(-eps < ticks-minVal & ticks-maxVal < eps);
% ticks = ticks(ticks >= minVal & ticks <= maxVal);
% does not work for, e.g., niceTicks(-0.1, 0.3, 3) !!!
difft = numel(ticks) - numTicks;
if numel(ticks) >= numTicks && difft < bestDiff
bestTicks = ticks;
bestDiff = difft;
else
break
end
end
ticks = bestTicks;
end

Sign in to comment.

Products


Release

R2024b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!