goptions reset=all target=ps300 ftext=swissb
         rotate=landscape gsfname=fred gsfmode=replace;

   /* Define the macro with parameters for input data set and    */
   /* survey month and year                                      */
%macro stdplot(indsn,monyear);

proc format;

   /* Define format for coding the response values               */
value respfmt 1 = '1=Poor'
              2 = '2=Fair'
              3 = '3=Good'
              4 = '4=Very Good'
              5 = '5=Excellent';

   /* Define format for Marital Status category                  */
value $ marfmt  'S' = 'Single'
                'M' = 'Married'
                'D' = 'Divorced'
                'W' = 'Widowed';

   /* Define format for Annual Income category                   */
value incfmt 0 = '< $25,000'
             1 = '$25,000-$49,999'
             2 = '$50,000-$74,999'
             3 = '$75,000-$99,999'
             4 = '$100,000 +';

   /* Define format for Sex category                             */
value $ sexfmt 'F' = 'Female'
               'M' = 'Male';

   /* Define ranges for Age Group category                       */
value agefmt 0 - 24 = 'Under 25'
            25 - 34 = '25 to 34'
            35 - 44 = '35 to 44'
            45 - 64 = '45 to 64'
            65 - high = '65 or older';
run;

   /* Read in raw data and define grouping variables             */
data survey;
   infile "~sasjzr/obs/issue15/&indsn..dat";
   length category $20;
   input sex $ 1 marital $ 3 age 5-6 income 8 overall 10;
   category=put(sex,$sexfmt.); group=1; output;
   category=put(marital,$marfmt.); group=2; output;
   category=put(age,agefmt.); group=3; output;
   category=put(income,incfmt.); group=4; output;
run;

   /* Sort the data by the CATEGORY variable before summarizing  */
   /* with PROC FREQ.                                            */
proc sort data=survey;
   by category;
run;

   /* Use the FREQ procedure to obtain the frequency count and   */
   /* percentage of respondents in each category of each group   */
   /* so that a customized table of values can be annotated onto */
   /* the plot.                                                  */
proc freq data=survey noprint;
   tables category*group / out=freqs;
run;

   /* Define an ANNOTATE data set to draw and fill a table       */
   /* containing the frequency count and percentage of           */
   /* respondents in each category of each group.                */
data anno1;
   set freqs;
   length function style color $8 xc text $15;

   /* Draw the outline of the table and fill with grey scale     */
   /* shading, place headings on the table columns and place     */
   /* group labels next to each category. These elements need    */
   /* only be drawn once, so they are defined at the beginning   */
   /* of the data step.                                          */
if _n_=1 then do;

   /* X values reflect a percentage of the axis area, y values   */
   /* reflect a percentage of the whole graphics output area     */
xsys='1'; ysys='3'; 

   /* Draw shaded background of table                            */
x=0; y=80; function='move'; output;
x=100; y=100; function='bar'; line=0; style='solid';
              color='grayee'; output;

   /* Draw table outline                                         */
x=0; y=80; function='move'; output;
x=100; y=100; function='bar'; style='empty';
              color='black'; output;

   /* Draw center line to divide frequency and percentage values */
function='move'; x=100; y=90; output;
function='draw'; line=1; x=0; output;

   /* Place labels to the left of each group of categories. Note */
   /* that the text is positioned just to the left of the first  */
   /* category value in each group by setting XSYS to '2' for    */
   /* data values, hardcoding the XC variable values for that    */
   /* category and assigning the horizontal location with a      */
   /* Y variable value of 12.5 percent.                          */
xsys='2';
function='label';
position='4'; size=1;
y=12.5; angle=90; style='swissb';
xc='Female';
text='Sex:'; output;
xc='Single';
text='Marital Status:'; output;
xc='Under 25';
text='Age Group:'; output;
xc='< $25,000';
text='Annual Income:'; output;

   /* Place labels at top of table                               */
xsys='1';
function='label'; position='5';
x=2; y=85; angle=90; style='swissb'; size=.75;
text='FREQ:'; output;
y=95; text='PCT:'; output;
function='move'; x=4; y=80; output;
function='draw'; y=100; output;
end;

   /* Place values in table                                      */
xsys='2'; ysys='3';
function='label';
style='swissb'; size=1;
xc=category;
y=85; position='5'; angle=90;
text=left(put(count,4.));
output;
position='4';
y=98; text=left(put(count/200,percent11.2));
output;
run;

   /* Run the MEANS procedure to obtain an overall mean response */
   /* value across the survey sample of customers. This value    */
   /* will be used to display and label a reference line at the  */
   /* mean.                                                      */
proc means data=survey mean noprint;
   var overall;
   output out=allmean mean=mean;
run;

   /* Combine the original data with the output data set from    */
   /* PROC MEANS, and define a macro variable that contains the  */
   /* overall mean value.                                        */
data all;
   set survey;
if _n_=1 then do;
   set allmean;
   call symput('mean',mean);
end;
run;

   /* Create a second ANNOTATE data set to label the reference   */
   /* line that reflects the overall mean value.                 */
data anno2;
   length text $20;
xsys='1'; ysys='2';
x=100; y=&mean; position='8';
function='label'; angle=90;
text='Overall Mean: '||left(put(&mean,5.2));
output;
run;

   /* Define SYMBOL statements that to request a standard        */
   /* deviation interpolation be applied to data from each of    */
   /* the four groups. The STDMJT interpolation method produces  */
   /* a plot with The fifth symbol definition is used for        */
   /* producing a null plot with the PLOT2 statement.            */
symbol1 i=stdmjt c=BLACK v=none;
symbol2 i=stdmjt c=BLACK v=none;
symbol3 i=stdmjt c=BLACK v=none;
symbol4 i=stdmjt c=BLACK v=none;
symbol5 i=none v=none;

   /* Specify titles and footnote                                */
title1 h=1.5 a=90 "Jude's Javas, Store #1";
title2 h=1.5 a=90 "Overall Selection of Coffees";
title3 h=1.5 a=90 "Customer Survey &monyear";

   /* Define AXIS statements to specify the attributes to be     */
   /* associated with the vertical and horizontal axes. The      */
   /* ORDER= list for the horizontal axis explicitly lists the   */
   /* category variable values in the appropriate order, with    */
   /* blank spaces inserted between the groups of values, while  */
   /* the ORDER= list for the vertical axis relies on a user-    */
   /* written format to provide the desired tick mark values.    */
axis1 order=(
   /* SEX                                                        */
'Female' 'Male' ' '
   /* AGE GROUP                                                  */
'Under 25' '25 to 34' '35 to 44' '45 to 64' '65 or older' ' '
   /* MARITAL STATUS                                             */
'Single' 'Married' 'Divorced' 'Widowed'  ' '
   /* ANNUAL INCOME                                              */
'< $25,000' '$25,000-$49,999' '$50,000-$74,999' '$75,000-$99,999'
'$100,000 +')
label=none major=none style=0 length=75 pct
   offset=(5 pct,5 pct) value=(a=90 r=0);

axis2 order=1 to 5 label=none minor=none origin=(15,25 pct)
   length=55 pct offset=(5,5) pct value=(h=.9 a=90);

   /* Finally, produce the graph. A predefined format is used to */
   /* convert the coded survey values into their associated      */
   /* response levels along the vertical axis. The AUTOVREF and  */
   /* LVREF= options on the PLOT statement request dotted        */
   /* reference lines at each major tick mark along the vertical */
   /* axis. One ANNOTATE data set is specified on the PLOT       */
   /* statement, and the other is specified on the PLOT2         */
   /* statement. In this case, it doesn't matter which annotate  */
   /* data set is specified on which plot statement. Although a  */
   /* legend is produced automatically when a Y*X=Z plot request */
   /* format is used, it would not be useful on this particular  */
   /* graph. The legend is therefore suppressed with the         */
   /* NOLEGEND option.                                           */
   /*                                                            */
   /* The PLOT2 statement and the associated SYMBOL definition   */
   /* request that no plot line be drawn on the graph. The plot  */
   /* request is necessary to allow other options on the PLOT2   */
   /* statement to be utilized. The VREF= and LVREF= options on  */
   /* the PLOT2 statement are used to produce a dashed reference */
   /* line at the overall mean value.  The plot request on the   */
   /* PLOT2 statement could also be used to produce a horizontal */
   /* line at the mean value as long as an appropriate SYMBOL    */
   /* definition is specified with INTERPOL=JOIN and LINE= for   */
   /* the desired linestyle. The resulting line would not extend */
   /* across any offsets that were requested on that axis,       */
   /* therefore this example chose to use the VREF= option       */
   /* instead. Because the axes produced by the PLOT2 statement  */
   /* are not needed, the NOAXES option is used to suppress them */
   /* from being drawn.                                          */
proc gplot data=all;
   note a=90 move=(97,2) pct h=.9
   "200 Customers surveyed. Plot reflects MEAN +/- 2 
      STANDARD DEVIATIONS.";
   format overall respfmt.;
   plot overall*category=group / anno=anno1 haxis=axis1 vaxis=axis2
                                 nolegend lvref=34 autovref;
   plot2 mean*category=5 / anno=anno2 haxis=axis1 vaxis=axis2
                           noaxes vref=&mean lvref=2;
run;
quit;

%mend stdplot;

   /* Invoke the macro with parameters                           */

%stdplot(jan95,January 1995);