00001 |
/** |
00002 |
\file |
00003 |
\ingroup SASUNIT_EXAMPLES_PGM |
00004 |
|
00005 |
\brief Create boxplot for two groups |
00006 |
|
00007 |
Specification for chart: |
00008 |
- two overlayed boxplots, one per group, the two plots shall be |
00009 |
slightly offset for readability. |
00010 |
- boxplot for the smaller value of &group has gray color with dashed median line |
00011 |
- boxplot for the greater value of &group has black color with continuous median line |
00012 |
- lower border of boxes are at 25th percentile, higher border at 75th percentile |
00013 |
- whiskers shall be drawn from maximum and minimum value |
00014 |
- labels for variables &x und &y shall be written to the axes |
00015 |
- there shall be a legend for the group variable |
00016 |
- report format ist PDF |
00017 |
|
00018 |
\version \$Revision: 315 $ |
00019 |
\author \$Author: klandwich $ |
00020 |
\date \$Date: 2014-02-28 10:25:18 +0100 (Fr, 28 Feb 2014) $ |
00021 |
\sa For further information please refer to SASUnit User's Guide |
00022 |
\sa \$HeadURL: https://svn.code.sf.net/p/sasunit/code/trunk/example/saspgm/boxplot.sas $ |
00023 |
\copyright Copyright 2010, 2012 HMS Analytical Software GmbH. |
00024 |
This file is part of SASUnit, the Unit testing framework for SAS(R) programs. |
00025 |
For terms of usage under the GPL license see included file readme.txt |
00026 |
or https://sourceforge.net/p/sasunit/wiki/readme.v1.2/. |
00027 |
|
00028 |
\param data input data sets |
00029 |
\param x variable for x axis, must be numeric and equidistant und must have at least two values, |
00030 |
missing values are not allowed |
00031 |
\param y variable for y axis, must be numeric |
00032 |
\param group variable for grouping, must be dichotomous, |
00033 |
missing values are not allowed |
00034 |
\param report output report file (file name extension must be pdf) |
00035 |
*/ /** \cond */ |
00036 |
|
00037 |
%MACRO boxplot( |
00038 |
data = |
00039 |
,x = |
00040 |
,y = |
00041 |
,group = |
00042 |
,report = |
00043 |
); |
00044 |
|
00045 |
%local dsid grouptype xvalues xvalues2; |
00046 |
|
00047 |
/*-- check input data set ----------------------------------------------------*/ |
00048 |
%let dsid=%sysfunc(open(&data)); |
00049 |
%if &dsid=0 %then %do; |
00050 |
%put ERROR: boxplot: Data set &data does not exist; |
00051 |
%return; |
00052 |
%end; |
00053 |
/*-- check whether x variable has been specified -----------------------------*/ |
00054 |
%if "&x"="" %then %do; |
00055 |
%put ERROR: boxplot: X variable not specified; |
00056 |
%let dsid=%sysfunc(close(&dsid)); |
00057 |
%return; |
00058 |
%end; |
00059 |
/*-- check for existence of x variable ---------------------------------------*/ |
00060 |
%if %sysfunc(varnum(&dsid,&x))=0 %then %do; |
00061 |
%put ERROR: boxplot: Variable &x does not exist in data set &data ; |
00062 |
%let dsid=%sysfunc(close(&dsid)); |
00063 |
%return; |
00064 |
%end; |
00065 |
|
00066 |
/*-- check whether x variable is numeric -------------------------------------*/ |
00067 |
%if %sysfunc(vartype(&dsid,%sysfunc(varnum(&dsid,&x)))) NE N %then %do; |
00068 |
%put ERROR: boxplot: Variable &x in data set &data must be numeric; |
00069 |
%let dsid=%sysfunc(close(&dsid)); |
00070 |
%return; |
00071 |
%end; |
00072 |
/*-- determine values of x variable for axis ---------------------------------*/ |
00073 |
proc sql noprint; |
00074 |
select distinct &x into :xvalues separated by '" "' from &data; |
00075 |
select distinct &x into :xvalues2 separated by ' ' from &data; |
00076 |
quit; |
00077 |
/*-- check whether y variable has been specified -----------------------------*/ |
00078 |
%if "&y"="" %then %do; |
00079 |
%put ERROR: boxplot: Y variable not specified; |
00080 |
%let dsid=%sysfunc(close(&dsid)); |
00081 |
%return; |
00082 |
%end; |
00083 |
/*-- check for existence of y variable ---------------------------------------*/ |
00084 |
%if %sysfunc(varnum(&dsid,&y))=0 %then %do; |
00085 |
%put ERROR: boxplot: Variable &y does not exist in data set &data ; |
00086 |
%let dsid=%sysfunc(close(&dsid)); |
00087 |
%return; |
00088 |
%end; |
00089 |
/*-- check wheter y variable ist numeric -------------------------------------*/ |
00090 |
%if %sysfunc(vartype(&dsid,%sysfunc(varnum(&dsid,&y)))) NE N %then %do; |
00091 |
%put ERROR: boxplot: Variable &y in data set &data must be numeric; |
00092 |
%let dsid=%sysfunc(close(&dsid)); |
00093 |
%return; |
00094 |
%end; |
00095 |
/*-- check whether group variable has been specified -------------------------*/ |
00096 |
%if "&group"="" %then %do; |
00097 |
%put ERROR: boxplot: Group variable must be specified; |
00098 |
%let dsid=%sysfunc(close(&dsid)); |
00099 |
%return; |
00100 |
%end; |
00101 |
/*-- check for existence of group variable -----------------------------------*/ |
00102 |
%if %sysfunc(varnum(&dsid,&group))=0 %then %do; |
00103 |
%put ERROR: boxplot: Variable &group does not exist in data set &data ; |
00104 |
%let dsid=%sysfunc(close(&dsid)); |
00105 |
%return; |
00106 |
%end; |
00107 |
/*-- check for number of groups and determine variable type and group sequence -*/ |
00108 |
%let grouptype=%sysfunc(vartype(&dsid,%sysfunc(varnum(&dsid,&group)))); |
00109 |
%local count lower; |
00110 |
proc sql noprint; |
00111 |
select count(distinct &group) into :count from &data; |
00112 |
select min(&group) into :lower from &data; |
00113 |
quit; |
00114 |
%if &lower=. %then %do; |
00115 |
%put ERROR: boxplot: Missing values in group variable are not allowed; |
00116 |
%return; |
00117 |
%*** This is code not covered by any test case and left intentionally here to ***; |
00118 |
%*** demonstrate the functionality of the test coverage ***; |
00119 |
proc sql noprint; drop table &d_1; quit; |
00120 |
%end; |
00121 |
%if &count NE 2 %then %do; |
00122 |
%put ERROR: boxplot: Variable &group must have exactly two values; |
00123 |
%return; |
00124 |
%end; |
00125 |
|
00126 |
%let dsid=%sysfunc(close(&dsid)); |
00127 |
|
00128 |
/*-- calculate distance between the x values ---------------------------------*/ |
00129 |
%local d_1; |
00130 |
DATA; RUN; |
00131 |
%let d_1=&syslast; |
00132 |
|
00133 |
proc sql noprint; |
00134 |
create table &d_1 as select distinct &x from &data; |
00135 |
quit; |
00136 |
|
00137 |
data &d_1; |
00138 |
set &d_1; |
00139 |
&x = &x - lag(&x); |
00140 |
if _n_>1 then output; |
00141 |
run; |
00142 |
|
00143 |
%local xdiff1 xdiff2 xmin xmax misscount; |
00144 |
proc sql noprint; |
00145 |
select mean(&x), min(&x) into :xdiff1, :xdiff2 from &d_1; |
00146 |
select min(&x), max(&x) into :xmin, :xmax from &data; |
00147 |
%let misscount=0; |
00148 |
select count(*) into :misscount from &data where &x is missing; |
00149 |
quit; |
00150 |
%if &xdiff1=. %then %do; |
00151 |
%put ERROR: boxplot: x variable must have at least two values; |
00152 |
proc sql noprint; drop table &d_1; quit; |
00153 |
%return; |
00154 |
%end; |
00155 |
%if &misscount>0 %then %do; |
00156 |
%put ERROR: boxplot: Missing values in x variable are not allowed; |
00157 |
proc sql noprint; drop table &d_1; quit; |
00158 |
%return; |
00159 |
%end; |
00160 |
|
00161 |
%let xmin=%sysevalf(&xmin-&xdiff1); |
00162 |
%let xmax=%sysevalf(&xmax+&xdiff1); |
00163 |
|
00164 |
run; |
00165 |
%if &xdiff1 ne &xdiff2 %then %do; |
00166 |
%put ERROR: boxplot: Values of x variable are not equidistant; |
00167 |
proc sql noprint; drop table &d_1; quit; |
00168 |
%return; |
00169 |
%end; |
00170 |
|
00171 |
/*-- calculate offset between the plots of the two groups --------------------*/ |
00172 |
%local d_plot; |
00173 |
data; |
00174 |
SET &data (KEEP=&x &y &group); |
00175 |
IF &group = %if &grouptype=N %then &lower; %else "&lower"; THEN DO; |
00176 |
&x = &x - 0.11*&xdiff1; |
00177 |
END; |
00178 |
ELSE DO; |
00179 |
&x = &x + 0.11*&xdiff1; |
00180 |
END; |
00181 |
RUN; |
00182 |
%let d_plot=&syslast; |
00183 |
|
00184 |
/*-- create chart ------------------------------------------------------------*/ |
00185 |
GOPTIONS FTEXT="Helvetica" HTEXT=12pt hsize=16cm vsize=16cm; |
00186 |
SYMBOL1 WIDTH = 3 BWIDTH = 3 COLOR = gray LINE = 2 VALUE = none INTERPOL = BOXJT00 MODE = include; |
00187 |
SYMBOL2 WIDTH = 3 BWIDTH = 3 COLOR = black LINE = 1 VALUE = none INTERPOL = BOXJT00 MODE = include; |
00188 |
AXIS1 LABEL=(ANGLE=90) MINOR=none; |
00189 |
AXIS2 ORDER=(&xmin &xvalues2 &xmax) VALUE=(" " "&xvalues" " ") MINOR=none; |
00190 |
LEGEND1 FRAME; |
00191 |
|
00192 |
ODS PDF FILE="&report"; |
00193 |
ODS LISTING CLOSE; |
00194 |
PROC GPLOT DATA=&d_plot; |
00195 |
PLOT &y * &x = &group / VAXIS=Axis1 HAXIS=Axis2 LEGEND=Legend1 NOFRAME; |
00196 |
RUN; |
00197 |
QUIT; |
00198 |
ODS PDF CLOSE; |
00199 |
ODS LISTING; |
00200 |
|
00201 |
proc sql noprint; |
00202 |
drop table &d_plot; |
00203 |
drop table &d_1; |
00204 |
quit; |
00205 |
|
00206 |
%MEND boxplot; |
00207 |
/** \endcond */ |