Home > voicebox > xyzticksi.m

xyzticksi

PURPOSE ^

XYZTIXKSI labels an axis of a plot using SI multipliers S=(AX,AH)

SYNOPSIS ^

function s=xyzticksi(ax,ah)

DESCRIPTION ^

XYZTIXKSI labels an axis of a plot using SI multipliers S=(AX,AH)

 This routine is not intended to be called directly. See XTICKSI and YTICKSI.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function s=xyzticksi(ax,ah)
0002 %XYZTIXKSI labels an axis of a plot using SI multipliers S=(AX,AH)
0003 %
0004 % This routine is not intended to be called directly. See XTICKSI and YTICKSI.
0005 
0006 %       Copyright (C) Mike Brookes 2009
0007 %      Version: $Id: xyzticksi.m 9302 2017-01-18 16:19:20Z dmb $
0008 %
0009 %   VOICEBOX is a MATLAB toolbox for speech processing.
0010 %   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
0011 %
0012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0013 %   This program is free software; you can redistribute it and/or modify
0014 %   it under the terms of the GNU General Public License as published by
0015 %   the Free Software Foundation; either version 2 of the License, or
0016 %   (at your option) any later version.
0017 %
0018 %   This program is distributed in the hope that it will be useful,
0019 %   but WITHOUT ANY WARRANTY; without even the implied warranty of
0020 %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021 %   GNU General Public License for more details.
0022 %
0023 %   You can obtain a copy of the GNU General Public License from
0024 %   http://www.gnu.org/copyleft/gpl.html or by writing to
0025 %   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
0026 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0027 
0028 % Note that "mu" = char(181) assumes Western European encoding
0029 % Bugs:
0030 %   (1) ipan=3 or 4 is not really debugged yet:
0031 %   (2) axis lengths incorrect for 3D graphs
0032 %   (3) should take account of axis shortening due to long labels at the ends
0033 %   (4) should calculate axis orentation from CameraPosition, CameraTarget and CameraUpVector
0034 if nargin<2
0035     ah=gca;
0036     if nargin<1
0037         ax=1;
0038     end
0039 end
0040 axfield={'XLim' 'YLim' 'ZLim'; 'XTick' 'YTick' 'ZTick'; 'XMinorTick' 'YMinorTick' 'ZMinorTick'; 'XTickLabel' 'YTickLabel' 'ZTickLabel'; 'XScale' 'YScale' 'ZScale'};
0041 tryglobal=nargout>0;
0042 digith=1;    % height of a digit in font units
0043 digitw=0.5;    % width of a digit in font units
0044 
0045 prefix={'y','z','a','f','p','n','','m','','k','M','G','T','P','E','Z','Y'};
0046 marg=[2 0.5 0.25 0.25];     % gap between labels in font units
0047 ntreq=[3 2 2 1];        % minimum number of labelled ticks required as a function of IPAN
0048 % grid template: each pair is [#steps final-value]. Start=10, end=100
0049 lgridtem={1; [1 20 1 50 1]; [1 20 4]; 9; [2 20 8]; [5 20 2 30 7]; [10 20 5 30 4 50 5]};
0050 ngrid=length(lgridtem);
0051 lgrid=cell(ngrid,1);
0052 agrid=zeros(ngrid,1);       % min and max ratio in decades
0053 % build the actual grid layouts
0054 for i=1:ngrid
0055     igridtem=[lgridtem{i} 100];
0056     igrid=zeros(1,sum(igridtem(1:2:end)));
0057     ntem=length(igridtem)/2;
0058     k=0;
0059     tick0=10;
0060     for j=1:ntem
0061         nstep=igridtem(2*j-1);
0062         igrid(k+1:k+nstep)=tick0+(0:nstep-1)*(igridtem(2*j)-tick0)/igridtem(2*j-1);
0063         k=k+nstep;
0064         tick0=igridtem(2*j);
0065     end
0066     agrid(i)=sum(log10([igrid(2:end) 100]./igrid).^2); % average log interval
0067     lgrid{i}=igrid';                 % grid positions
0068 end
0069 minsubsp=1;        % minimum subtick spacing (in font units)
0070 delcheck=[log10(2) log10(5) 2];     % check linear spacing
0071 delval=[1 2 5];
0072 dosubtick=0;         % default is not to allow subticks
0073 
0074 ngrid=length(lgrid);
0075 loggrid=cell(ngrid,1);
0076 for i=1:ngrid
0077     loggrid{i}=log10(lgrid{i})-1;
0078 end
0079 
0080 getgca=get(ah);
0081 set(ah,'Units','points','FontUnits','points');
0082 getgcac=get(ah);
0083 set(ah,'Units',getgca.Units,'FontUnits',getgca.FontUnits); % return to original values
0084 if ax==1
0085     widthc=getgcac.Position(3)/getgcac.FontSize;     % x axis length in font units
0086     axdir=[1 0];        % unit vector in axis direction
0087 else
0088     widthc=2*getgcac.Position(4)/getgcac.FontSize;     % y axis length in font units
0089         axdir=[0 1];        % unit vector in axis direction
0090 end
0091 axdir=max(abs(axdir),1e-10);        % avoid infinity problems
0092 a=getgca.(axfield{1,ax})(1);
0093 b=getgca.(axfield{1,ax})(2);
0094 
0095 ntick=0;
0096 tickint=[];                 % integer label
0097 tickdp=[];                  % tick decimal point position
0098 ticksi=[];                  % tick SI multiplier (always a multiple of 3)
0099 subtick=[];                 % sub tick positions
0100 if strcmp(getgca.(axfield{5,ax}),'log')   % log axis
0101     width10=widthc/log10(b/a); % fount units per decade
0102     ai3=3*ceil(log10(a)/3);             % lowest SI multiplier
0103     bi3=3*floor(log10(b)/3);            % highest SI multiplier
0104     if ai3>=-24 && bi3<=24              % do nothing if outside the SI multiplier range
0105         % first sort out if we can use a global SI multiplier
0106         if tryglobal && a>=10^(bi3-1)
0107             gi=bi3;
0108             s=prefix{9+gi/3};
0109             globalsi=1;                % global multiplier
0110         else
0111             gi=0;
0112             globalsi=0;                % disable global multiplier
0113             s='';
0114 
0115         end
0116         g=10^gi;
0117         ag=a/g;
0118         bg=b/g;
0119         al=log10(ag);
0120         bl=log10(bg);
0121         ai=ceil(al);
0122         bi=floor(bl);
0123         ai3=3*ceil(ai/3);
0124         bi3=3*floor(bi/3);
0125         for ipan=1:4                    % panic level: 1=spacious, 2=cramped, 3=any two labels, 4=any label
0126             % first try labelling only exact SI multiples
0127             margin=marg(ipan);
0128             incsi=3*ceil(min((2*digitw+margin)/axdir(1),(digith+margin)/axdir(2))/(3*width10));   % SI increment
0129             switch ipan
0130                 case {1,2}
0131                     ticksi=incsi*ceil(ai/incsi):incsi:incsi*floor(bi/incsi);
0132                 case {3,4}
0133                     ticksi=ai3:incsi:bi3;
0134             end
0135             ntick=length(ticksi);
0136             tickint=ones(1,ntick);
0137             tickdp=zeros(1,ntick);
0138             if width10>0.25
0139                 ticki=ai:bi;
0140                 subtick=10.^(ticki(ticki~=3*fix(ticki/3)));      % put subticks at all powers of 10;
0141             end
0142             if incsi==3         % no point in trying anything else if incsi>3
0143                 ci=floor(al);   % start of first decade that includes the start of the axis
0144                 cibi=ci:bi;     % ennumerate the decades that cover the entire axis
0145                 ndec=bi-ci+1;   % number of decades
0146                 if globalsi
0147                     siq0=zeros(1,ndec); % no SI multipliers within the labels if using a global multiplier
0148                 else
0149                     siq0=3*floor((cibi)/3); % determine the SI multiplier for each of the decades
0150                 end
0151                 siw0=siq0~=0;                % width of SI multiplier
0152                 dpq0=max(siq0-cibi+1,1);    % number of decimal places
0153                 for jgrid=1:ngrid
0154                     igrid=jgrid-(ipan<=2)*(2*jgrid-ngrid-1);
0155                     lgridi=lgrid{igrid};
0156                     ngridi=length(lgridi);
0157                     intq=reshape(repmat(lgridi,1,ndec).*repmat(10.^(cibi+dpq0-siq0-1),ngridi,1),1,[]);
0158                     dpq=reshape(repmat(dpq0,ngridi,1),1,[]);
0159                     msk=dpq>0 & rem(intq,10)==0;
0160                     intq(msk)=intq(msk)/10;
0161                     dpq(msk)=dpq(msk)-1;
0162                     widq=1+floor(log10(intq));
0163                     widq=digitw*(widq+(dpq>0).*max(1,dpq+2-widq)+reshape(repmat(siw0,ngridi,1),1,[]));
0164                     logvq=reshape(repmat(loggrid{igrid},1,ndec)+repmat(ci:ndec+ci-1,ngridi,1),1,[]);
0165                     % mask out any ticks outside the axis range
0166                     msk=logvq>=al & logvq<=bl;
0167                     widq=widq(msk);
0168                     logvq=logvq(msk);
0169                     % debug1=[intq(msk); -1 min((widq(1:end-1)+widq(2:end)+2*margin)/axdir(1),2*(digith+margin)/axdir(2))<=2*width10*(logvq(2:end)-logvq(1:end-1))];
0170                     if numel(widq)>=ntreq(ipan) && all(min((widq(1:end-1)+widq(2:end)+2*margin)/axdir(1),2*(digith+margin)/axdir(2))<=2*width10*(logvq(2:end)-logvq(1:end-1)))
0171                         % success: we have an acceptable pattern
0172                         ntick=numel(widq);       % number of ticks
0173                         tickint=intq(msk);      % integer label value (i.e. neglecting decimal point)
0174                         tickdp=dpq(msk);        % number of decimal places
0175                         siq=reshape(repmat(siq0,ngridi,1),1,[]);    % SI mltiplier power
0176                         ticksi=siq(msk);        % SI multiplier power masked
0177                         subtick=[];             % recalculate any subticks
0178                         dosubtick=igrid>1;
0179                         break;                  % do not try any more grid patterns
0180                     end
0181                 end % alternative grid patterns
0182                 % finally just try a linear increment
0183                 if ntick<5
0184                     ldeltamin=log10(bg- bg*10^(-min((digitw+margin)/axdir(1),(digith+margin)/axdir(2))/width10));  % smallest conceivable increment
0185                     ildelta=floor(ldeltamin);
0186                     ix=find(ldeltamin-ildelta<=delcheck,1);
0187                     jx=ildelta*3+ix;
0188                     while 1
0189                         deltax=floor(jx/3);
0190                         deltav=delval(jx-3*deltax+1);
0191                         delta=deltav*10^deltax;
0192                         multq=ceil(ag/delta):floor(bg/delta);   % multiples of delta to display
0193                         ntickq=numel(multq);
0194                         if ntickq<=ntick || ntickq<ntreq(ipan)   % give up now
0195                             break;
0196                         end
0197                         intq=deltav*multq;
0198                         lintq=floor(log10(intq));
0199                         siq=3*floor((lintq+deltax)/3);      % SI multiplier
0200                         dpq=siq-deltax;
0201                         msk=dpq<0;
0202                         intq(msk)=intq(msk).*10.^(-dpq(msk));
0203                         dpq(msk)=0;
0204                         msk=rem(intq,10)==0 & dpq>0;
0205                         while any(msk)      % remove unwanted trailing zeros
0206                             dpq(msk)=dpq(msk)-1;
0207                             intq(msk)=intq(msk)/10;
0208                             msk=rem(intq,10)==0 & dpq>0;
0209                         end
0210                         widq=1+floor(log10(intq));
0211                         widq=digitw*(widq+(dpq>0).*max(1,dpq+2-widq)+(siq~=0));
0212                         logvq=log10(multq)+log10(deltav)+deltax;
0213                         % debug2=[intq; widq; -1 (widq(1:end-1)+widq(2:end)+2*margin)<=2*width10*(logvq(2:end)-logvq(1:end-1))];
0214                         if all(min((widq(1:end-1)+widq(2:end)+2*margin)/axdir(1),2*(digith+margin)/axdir(2))<=2*width10*(logvq(2:end)-logvq(1:end-1)))
0215                             ntick=ntickq;
0216                             tickint=intq;
0217                             tickdp=dpq;
0218                             ticksi=siq;
0219                             dosubtick=1;
0220                             break
0221                         end
0222                         jx=jx+1;                            % try next coarser spacing
0223                     end
0224                 end
0225             end % try grid patterns since at most one exact SI multiple
0226             if ntick>=ntreq(ipan)
0227                 break% quit if we have enough labels
0228             end
0229         end% try next panic level
0230     end    % check if within SI range
0231     if ntick
0232         tickexp=gi+ticksi-tickdp;
0233         tickpos=tickint .* 10.^tickexp;
0234         ratthresh=10^(minsubsp/width10);   % min subtick ratio
0235         if dosubtick       % check for subticks
0236             subtick=[];
0237             if ntick>1      % at least two labelled ticks
0238                 stepexp=min(tickexp(1:end-1),tickexp(2:end))-1;
0239                 stepint=round((tickpos(2:end)-tickpos(1:end-1)).*10.^(-stepexp));  % always a multiple of 10
0240                 stepleft=tickint(1:end-1).*10.^(tickexp(1:end-1)-stepexp); % leftmost label in units of 10^stepexp
0241                 subbase=10.^ceil(log10(stepint)-1); % base sub-tick interval in units of 10^stepexp
0242                 substep=[-1 -3 5]*((1+[1; 2; 5]*(subbase./stepleft))>ratthresh); % actual step is 1,2 or 5 times subbase
0243                 substep(stepint~=10*substep)=max(2-substep(stepint~=10*substep),0); % but only >1 if stepint==10
0244                 substep=substep.*subbase; % subtick step in units of 10^stepexp
0245                 for i=1:ntick-1
0246                     ss=substep(i);
0247                     sl=stepleft(i);
0248                     if ss
0249                         subtick=[subtick (sl+(ss:ss:stepint(i)-ss))*10^stepexp(i)];
0250                         if i==1 && sl/(sl-ss)>ratthresh
0251                             subtick=[subtick (sl-(ss:ss:floor((tickpos(1)-a)/(ss*10^stepexp(i)))*ss))*10^stepexp(i)];
0252                         elseif i==ntick-1 && (1+ss/(sl+stepint(1)))>ratthresh
0253                             subtick=[subtick (sl+stepint(i)+(ss:ss:floor((b-tickpos(end))/(ss*10^stepexp(i)))*ss))*10^stepexp(i)];
0254                         end
0255                     end
0256                 end
0257             end
0258         end % if subtick
0259         [tps,ix]=sort([tickpos subtick]);
0260         nticks=length(tps);
0261         ticklab=cell(nticks,1);
0262         for j=1:nticks
0263             i=ix(j);
0264             if i>ntick
0265                 ticklab{j}='';
0266             else
0267                 ticklab{j}=sprintf(sprintf('%%.%df%%s',tickdp(i)),tickint(i)*10^(-tickdp(i)),prefix{ticksi(i)/3+9});
0268             end
0269         end
0270         if width10<2.5
0271             set(ah,axfield{3,ax},'off');
0272         end
0273         set(ah,axfield{2,ax},tps);
0274         set(ah,axfield{4,ax},ticklab);
0275     end
0276 
0277 else                    % linear axis
0278     for ipan=1:4                    % panic level: 1=spacious, 2=cramped, 3=any two labels, 4=any label
0279         margin=marg(ipan);
0280         % select a global multiplier
0281         if tryglobal
0282             gi=3*floor(log10(max(abs(a),abs(b)))/3);
0283             s=prefix{9+gi/3};
0284 
0285         else
0286             gi=0;
0287             s='';
0288         end
0289         g=10^gi;
0290         ag=a/g;
0291         bg=b/g;
0292         width1=widthc/(bg-ag);                  % width of 1 plot unit in font units
0293         ldeltamin=log10(min((digitw+margin)/axdir(1),(digith+margin)/axdir(2))/width1);        % log of smallest conceivable increment
0294         ildelta=floor(ldeltamin);
0295         ix=find(ldeltamin-ildelta<=delcheck,1);
0296         jx=ildelta*3+ix;
0297         while 1 % loop trying increasingly coarse labelling
0298             deltax=floor(jx/3);         % exponent of label increment
0299             deltav=delval(jx-3*deltax+1); % mantissa of label increment
0300             delta=deltav*10^deltax;         % actual label inrement
0301             multq=ceil(ag/delta):floor(bg/delta);   % multiples of delta to display
0302             ntickq=numel(multq);
0303             if ntickq<ntreq(ipan)   % give up now if too few labels
0304                 break;
0305             end
0306             intq=deltav*multq;
0307             lintq=floor(log10(abs(intq)+(intq==0)));
0308             siq=3*floor((lintq+deltax)/3)*~tryglobal;      % SI multiplier, but only if no global multiplier
0309             dpq=siq-deltax;
0310             msk=dpq<0;
0311             intq(msk)=intq(msk).*10.^(-dpq(msk));
0312             dpq(msk)=0;
0313             msk=rem(intq,10)==0 & dpq>0;
0314             while any(msk)      % remove unwanted trailing zeros
0315                 dpq(msk)=dpq(msk)-1;
0316                 intq(msk)=intq(msk)/10;
0317                 msk=rem(intq,10)==0 & dpq>0;
0318             end
0319             widq=1+floor(log10(abs(intq)+(intq==0)));
0320             widq=digitw*(widq+(dpq>0).*max(1,dpq+2-widq)+(siq~=0).*(intq~=0)+(intq<0)); % calculate width of each label
0321             % debug2=[intq; widq; digith+margin<=axdir(2)*width1*delta (widq(1:end-1)+widq(2:end)+2*margin)<=2*width1*delta];
0322             if all((widq(1:end-1)+widq(2:end)+2*margin)<=2*axdir(1)*width1*delta) || (digith+margin<=axdir(2)*width1*delta);
0323                 ntick=ntickq;
0324                 tickint=intq;
0325                 tickdp=dpq;
0326                 ticksi=siq;
0327                 if deltav>1 && width1*delta>0.5*deltav          % put explicit subticks if delta = 2 or 5
0328                     mults=ceil(ag*deltav/delta):floor(bg*deltav/delta);
0329                     subtick=(mults(deltav*fix(mults/deltav)~=mults))*delta/deltav;
0330                 else
0331                     subtick=[];
0332                 end
0333                 break                       % do not try any more coarser spacings
0334             end
0335             jx=jx+1;                            % try next coarser spacing
0336         end
0337         if ntick>=ntreq(ipan)
0338             break% quit if we have enough labels
0339         end
0340     end
0341     if ntick
0342         tickexp=gi+ticksi-tickdp;
0343         tickpos=tickint .* 10.^tickexp;
0344         [tps,ix]=sort([tickpos subtick*10^gi]);
0345         nticks=length(tps);
0346         ticklab=cell(nticks,1);
0347         for j=1:nticks
0348             i=ix(j);
0349             if i>ntick
0350                 ticklab{j}='';
0351             else
0352                 ticklab{j}=sprintf(sprintf('%%.%df%%s',tickdp(i)),tickint(i)*10^(-tickdp(i)),prefix{(ticksi(i)/3)*(tickint(i)~=0)+9});
0353             end
0354         end
0355         set(ah,axfield{2,ax},tps);
0356         set(ah,axfield{4,ax},ticklab);
0357         set(ah,axfield{3,ax},'on');
0358     end
0359 end

Generated on Tue 10-Oct-2017 08:30:10 by m2html © 2003