/*
/ Program : vaxis.sas
/ Version : 1.0
/ Author : Roland Rashleigh-Berry
/ Date : 04-May-2011
/ Purpose : To generate the values to construct a vaxis scale
/ SubMacros : none
/ Notes : It does not matter if you get the min and max values the wrong way
/ round. This will be detected and fixed. The global macro variables
/ populated are _from_, _to_, _by_, _format_ and _nminor_.
/ Usage : %vaxis(&min,&max,spare=1)
/
/===============================================================================
/ PARAMETERS:
/-------name------- -------------------------description------------------------
/ min (pos) Text minimum value (unquoted)
/ max (pos) Text maximum value (unquoted)
/ minticks=5 Minimum number of major tick marks to show on the axis
/ spare=0 Number of major tick mark divisions to leave spare at the
/ top for annotation.
/===============================================================================
/ AMENDMENT HISTORY:
/ init --date-- mod-id ----------------------description------------------------
/ rrb 29Mar07 Put out "macro called" message plus header tidy
/ rrb 04May11 Code tidy
/===============================================================================
/ This is public domain software. No guarantee as to suitability or accuracy is
/ given or implied. User uses this code entirely at their own risk.
/=============================================================================*/
%put MACRO CALLED: vaxis v1.0;
%macro vaxis(min,max,minticks=5,spare=0);
%local swap;
%global _from_ _to_ _by_ _format_ _nminor_;
%if %sysevalf(&max < &min) %then %do;
%let swap=&min;
%let min=&max;
%let max=&swap;
%end;
%if not %length(&spare) %then %let spare=0;
%let minticks=%eval(&minticks-&spare-1);
data _null_;
length fmt $ 5;
retain ld rd 0;
x=int(log10((&max-&min)/&minticks))+1;
_by=10**x;
_nminor=4;
if (ceil(&max/_by)*_by-floor(&min/_by)*_by)/_by < &minticks then do;
_by=5*10**(x-1);
_nminor=3;
end;
if (ceil(&max/_by)*_by-floor(&min/_by)*_by)/_by < &minticks then do;
_by=2*10**(x-1);
_nminor=3;
end;
if (ceil(&max/_by)*_by-floor(&min/_by)*_by)/_by < &minticks then do;
_by=10**(x-1);
_nminor=4;
end;
if (ceil(&max/_by)*_by-floor(&min/_by)*_by)/_by < &minticks then do;
_by=5*10**(x-2);
_nminor=3;
end;
if (ceil(&max/_by)*_by-floor(&min/_by)*_by)/_by < &minticks then do;
_by=2*10**(x-2);
_nminor=3;
end;
_from=floor(&min/_by)*_by;
_to=ceil(&max/_by)*_by;
if &spare GT 0 then _to=_to+(&spare*_by);
do i=_from to _to by _by;
if length(left(scan(put(i,best16.),1,'.'))) > ld
then ld=length(left(scan(put(i,best16.),1,'.')));
if scan(put(i,best16.),2,'.') NE ' ' then do;
if length(left(scan(put(i,best16.),2,'.'))) > rd
then rd=length(left(scan(put(i,best16.),2,'.')));
end;
end;
if rd>0 then fmt=compress(put(ld+rd+1,2.))||'.'||compress(put(rd,2.));
else fmt=compress(put(ld,2.))||'.';
call symput('_to_',trim(left(putn(_to,fmt))));
call symput('_from_',trim(left(putn(_from,fmt))));
call symput('_by_',compress(put(_by,best12.)));
call symput('_format_',trim(left(fmt)));
call symput('_nminor_',put(_nminor,1.));
run;
%mend vaxis;