**************************************************************************************************** * PROGRAM OVERVIEW **************************************************************************************************** * * PROGRAM: figure_axes.sas * Created (mm/dd/yyyy): 09/08/2021 * *-------------------------------------------------------------------------------------------------- * PURPOSE: The macro computes X and Y axis tick marks * * Program inputs: * - N/A * * Program outputs: * - N/A * * PARAMETERS: * - data: figure data * - figure: figure # * - figuresub: figuresub from figurefile * - where: where clause to restrict figure data * - xtickmarks: macro variable name for x tick mark list * - xvar = variable with xaxis metric * - ytickmarks: macro variable name for y tick mark list * - yvar= variable with yaxis metric * * Programming Notes: * * *-------------------------------------------------------------------------------------------------- * CONTACT INFO: * Sentinel Coordinating Center * info@sentinelsystem.org * ***************************************************************************************************; %macro figure_axes(data=, figure=, figuresub=, where=, xtickmarks=, xvar=, ytickmarks=, yvar=); %put =====> MACRO CALLED: figure_axes; %let xmax = ; %let xtick = ; %let ymin = ; %let ymax = ; %let ytick = ; %let datamin= ; %let datamax = ; %let fxtickmarks = ; %let fytickmarks = ; /*select min and max value from input dataset for x axis*/ %if %str(&xtickmarks) ne %str() %then %do; proc sql noprint; select min(&xvar.), max(&xvar.) into :datamin, :datamax from &data(where=(&where.)); quit; %end; %if %str(&yvar.) ne %str() %then %do; proc sql noprint; select max(&yvar.) into :datamax from &data(where=(&where.)); quit; %end; /*Extract axis parameters from figurefile*/ data _null_; set figurefile(where=(figure="&figure." and figuresub="&figuresub")); /*set min/max defaults if missing*/ %if %str(&xtickmarks) ne %str() %then %do; if missing(xmin) then xmin = &datamin.; if missing(xmax) then xmax = &datamax.; %end; %if %str(&ytickmarks) ne %str() %then %do; if missing(ymin) then ymin = 0; %if %str(&yvar.) = %str() %then %do; if missing(ymax) then ymax = 1; %end; %else %do; if missing(ymax) then ymax = round(&datamax.+4,10); /*to prevent cut off data*/ %end; %end; /*set default tick if missing: - 6 total tick marks (min, max, and 4 interim) - for x axis - round to the nearest divisor of 1, 5, or 30 depending on length of axis - for y axis - round to nearest divisor of 10 */ %if %str(&xtickmarks) ne %str() %then %do; if missing(xtick) then do; xmaxminusmin = xmax-xmin; if xmaxminusmin <=10 then xtick = round(xmaxminusmin/5, 1); else if xmaxminusmin <=120 then xtick = round(xmaxminusmin/5, 5); else xtick = round(xmaxminusmin/5, 30); if xtick = 0 then xtick = 1; end; xloopcount=round(divide(xmax-xmin,xtick))+1; call symputx('xmin', xmin); call symputx('xmax', xmax); call symputx('xtick', xtick); call symputx('xloopcount', xloopcount); %end; %if %str(&ytickmarks) ne %str() %then %do; if missing(ytick) then do; ymaxminusmin = ymax-ymin; if ymaxminusmin>1 then ytick = round(ymaxminusmin/5, 10); /*tick every 10*/ /*two tick options for 0-1 axis*/ else if ymaxminusmin >.04 then ytick = round(ymaxminusmin/5, .01); else ytick = round(ymaxminusmin/5, .001); if (ytick = 0 or ytick= .) and ymaxminusmin<=1 then ytick = .01; /*ymax <=1*/ else if ytick = 0 or ytick= . then ytick = 5; /*ymax data driven, 0 possible if ymax <=25*/ end; yloopcount=round(divide(ymax-ymin,ytick))+1; call symputx('ymin', ymin); call symputx('ymax', ymax); call symputx('ytick', ytick); call symputx('yloopcount', yloopcount); %end; run; /*xaxis*/ %if %str(&xtickmarks) ne %str() %then %do; %let xloop = &xmin.; %let axisloopcount = 1; %do %while(%sysevalf(&axisloopcount. <=&xloopcount.)); %if %eval(&axisloopcount. ne &xloopcount.) %then %do; %let fxtickmarks = &fxtickmarks%str( )&xloop.; %end; %else %do; %let fxtickmarks = &fxtickmarks%str( )%sysfunc(min(&xmax.,&xloop.)); /*Add max value if gap between last tick mark and max value is >tick/2*/ %if %scan(&fxtickmarks., -1) ne &xmax. %then %do; %let diff = %sysevalf(&xmax.-%scan(&fxtickmarks., -1)); %let div2 = %sysfunc(divide(&xtick.,2)); %if %sysevalf(&diff.>&div2.) %then %do; %let fxtickmarks = &fxtickmarks%str( )&xmax.; %end; %end; %end; %let xloop=%sysevalf(&xloop + &xtick); %let axisloopcount = %eval(&axisloopcount+1); %end; %let &xtickmarks = &fxtickmarks; %end; /*yaxis*/ %if %str(&ytickmarks) ne %str() %then %do; %let yloop = &ymin.; %let axisloopcount = 1; %do %while(%sysevalf(&axisloopcount. <=&yloopcount.)); %if %eval(&axisloopcount. ne &yloopcount.) %then %do; %let fytickmarks = &fytickmarks%str( )&yloop.; %end; %else %do; %let fytickmarks = &fytickmarks%str( )%sysfunc(min(&ymax.,&yloop.)); /*Add max value if gap between last tick mark and max value is >tick/2*/ %if %scan(&fytickmarks., -1) ne &ymax. %then %do; %let diff = %sysevalf(&ymax.-%scan(&fytickmarks., -1)); %let div2 = %sysfunc(divide(&ytick.,2)); %if %sysevalf(&diff.>&div2.) %then %do; %let fytickmarks = &fytickmarks%str( )&ymax.; %end; %end; %end; %let yloop=%sysfunc(round(%sysevalf(&yloop + &ytick),.001)); %let axisloopcount = %eval(&axisloopcount+1); %end; %let &ytickmarks = &fytickmarks; %end; %put =====> END MACRO: figure_axes; %mend figure_axes;