function h = prettyTickLabel(h, nTicks, nW, pr, nChar)
% PRETTYTICKLABEL format and limits the number of numeric ticks labels of a
% given axis handle using the function PRETTYFORMATING. The goal is to have
% pretty number and plots that can be easily aligned in a scientific paper
% without special resizing on a given plot.
% h = PRETTYTICKLABEL(h) format numeric ticks labels of the axis handle h
% with default values nW = 3 and pr = 3
%
% h = PRETTYTICKLABEL(h, nTicks, nW, pr, nChar) formats numeric ticks
% labels of the axis handle h. values of ticks are extracted and formatted
% to set tickLabel. nTicks gives the maximum number of labels. Vector
% value gives different values for each axis while scalar value uses the
% samemaximun on every axis. Negative values keep the current number of
% labels. nW an pr give respectivelly the maximum number of digit for the
% whole part of each number and the precision (number of digit in the
% fractional part) is the maximum number of digit allowed in the tick
% label; scalar and vector values are accepted. nChar is the is used to
% pad the number with spaces on the left so that at least nChar characters
% are used, including the signs, fractionaland exponential symbol, scalar
% and vector value are accepted.
% the only mandatory argument if the handle h. The default values for other
% arguments are: nTicks = -1, nW =3, pr = 3, nChar = 0;
%
% example prettyTickLabel(gca, 6, [1, 2, 2], [1, 2, 2]); will limit the
% number of tick labels to 6 in each direction, format the numbers to have
% a maximum of 1 digit for the whole part and 2 for the fractional part in
% the x direction, 2 digits for both the whole and the fractional part in the y
% [z direction]
%%
if ( (nargin==0)||(nargin>5) )
error('bad argument count');
end
if(nargin>=2)
if( max(size(nTicks))==1 )
maxNTicks = [nTicks, nTicks, nTicks];
else
maxNTicks = nTicks;
end
else
maxNTicks = [-1, -1, -1];
end
if(nargin>=3)
if( max(size(nW))==1 )
nWhole = [nW, nW, nW];
else
nWhole = nW;
end
else
nWhole = [3, 3, 3];
end
if(nargin>=4)
if( max(size(pr))==1 )
precisions = [pr, pr, pr];
else
precisions = pr;
end
else
precisions = [3, 3, 3];
end
if(nargin==5)
if( max(size(nChar))==1 )
nMaxChars = [nChar, nChar, nChar];
else
nMaxChars = nChar;
end
else
nMaxChars = [0, 0, 0];
end
xTicks= get(h,'XTick');
yTicks= get(h,'YTick');
xSize = max(size(xTicks));
ySize = max(size(yTicks));
xStrings = cell(xSize,1);
yStrings = cell(ySize,1);
%x axis
for i=1:xSize
xStrings{i}=prettyFormat( xTicks(i), nWhole(1), precisions(1), nMaxChars(1) );
end
if((maxNTicks(1)>=0)&&(xSize>maxNTicks(1)))
nDel=ceil(xSize/maxNTicks(1));% must keep only one over nDel elements;
for i=1:nDel:xSize
for j= i+1:i+nDel-1
xStrings{j} = '';
end
lastIdx=i;
end
%
for j=lastIdx+1: xSize-1
xStrings{j} = '';
end
end
set(h,'XTickLabel', xStrings);
%y axis
for i=1:ySize
yStrings{i}=prettyFormat( yTicks(i), nWhole(2), precisions(2), nMaxChars(2) );
end
if((maxNTicks(2)>=0)&&(ySize>maxNTicks(2)))
nDel=ceil(ySize/maxNTicks(2));% must keep only one over nDel elements;
for i=1:nDel:ySize
for j= i+1:i+nDel-1
yStrings{j} = '';
end
lastIdx=i;
end
%
for j=lastIdx+1: ySize-1
yStrings{j} = '';
end
end
set(h,'YTickLabel', yStrings);
%z axis
[~, el] = view(h);
if(el~=90)%shortcup to check the 3D view, may be wrong in some cases
zTicks= get(h,'YTick');
zSize = max(size(zTicks));
zStrings = cell(zSize,1);
for i=1:zSize
zStrings{i}=prettyFormat( zTicks(i), nWhole(3), precisions(3), nMaxChars(3));
end
if((maxNTicks(3)>=0)&&(zSize>maxNTicks(3)))
nDel=ceil(zSize/maxNTicks(3));% must keep only one over nDel elements;
for i=1:nDel:zSize
for j= i+1:i+nDel-1
zStrings{j} = '';
end
lastIdx=i;
end
%
for j=lastIdx+1: zSize-1
zStrings{j} = '';
end
end
set(h,'ZTickLabel', zStrings);
end
end
function strVal = prettyFormat(val, nW, pr, nMaxChar)
%% PRETTYFORMATING converts numeric values to string with a pretty
%% format. It is useful for labels in plots.
% It switches between different options (integer, scientific and
% floating point representation to define an appropriate format for a
% given value. for values larger than 10^nW or less than 10^-pr
% scientific notation is used. For values between 1 and 10^nW
% (excluded) the floating point format is used if the fractional part
% is significant otherwise integer representation is used, in[0,1]
% there many conditions depending on the position of the first
% significant values of the number and the first significant number
% after pr positions Give a try to see how it behaves.
%
% PRETTYFORMATING(val, nW, pr, nMaxChar) returns a string
% representation with a maximum of nW digit in the whole part, pr digit
% in the fractional part and a maximum of nMaxChar characters. The
% number is padded by spaces on the left.
% PRETTYFORMATING(val, nW, pr) does not care about padding
% PRETTYFORMATING(val, nW) uses the default value pr=3.
% PRETTYFORMATING(val) uses the default values nW=3 and pr=3.
switch (nargin)
case 0
error('insufisant number of arguments');
case 1
nW = 3;
pr = 3;
case 2
pr = 3;
otherwise
%nothing to do
end
if(nargin<4)
nMaxChar = 0;
end
sFormat = 1111;%scientific format
iFormat = 2222;%integer format
fFormat = 3333;%floating point format
v = abs(val);%absolute value
fracV = v-floor(v);
if(v>=10^nW)
format = sFormat;
%display(['using sFormat 1 for ' num2str(val)])
else
if( v>=1.0 )
if ( isSignificant(fracV, pr) )
format = fFormat;
%display(['using fFormat 1 for ' num2str(val)]);
else
format = iFormat;
%display(['using iFormat 1 for ' num2str(val)]);
end
else% in this case the number is zero
if (v>0.0)%
if(isSignificant(v, pr))
sDPos = round( abs( log10(v) ) );%position of the first significant digit
scaledV = v*10^sDPos;
rPart = scaledV - round(scaledV);% non significant part of v, scaled
if( ~isSignificant(rPart, pr) )
format = fFormat;
else
if(v<10^floor(-pr/2))
format = sFormat;
else
format = fFormat;
end
end
else
format = sFormat;
end
else
format = iFormat;
end
end
end
nDSign = floor( 0.5*( 1-sign(val) ) );%number of digit for the sig: 1 if negetive, 0 if not
switch( format )
case(sFormat)
nChar = pr + nDSign + 5;
%nChar includes: sign, fractional sign '.', exponantial symbol
%'e', the sign of the exponent and 2 digits exponent.
strVal=sprintf( [ '%.' num2str(pr) 'e'], val );
case(iFormat)
nChar = min(1, nW) + nDSign;
strVal=sprintf('%d', fix(val));%rounds towards zero
otherwise
nChar = nW + pr + nDSign + 1;%including the fractional mark '.'
%display([ '%' num2str(nW+pr) '.' num2str(pr) 'f']);
strVal=sprintf([ '%' num2str(nW+pr) '.' num2str(pr) 'f'], val );
end
if(nChar<nMaxChar)
padString = repmat( pad, 1, nMaxChar-nChar );
strVal = [padString strVal];
end
end
function rVal = isSignificant(v, pr)
rVal = ( round(v*10^pr + eps)~=0 );
end