v_xyzticksi

PURPOSE ^

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

SYNOPSIS ^

function s=v_xyzticksi(ax,ah)

DESCRIPTION ^

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

Generated by m2html © 2003