• Print  |
  • Feedback  |

FOCUS AREAS

Return to SAS 9

Base SAS

Enhancements to Procedures for SAS 9.2


Introduction

This topic demonstrates some of the new features for Base SAS procedures in SAS 9.2.


SPANROWS Option in PROC REPORT

The new SPANROWS option in PROC REPORT improves the appearance of your output when you have GROUP and ORDER variables. The blank cells under GROUP and ORDER variables are combined, and the rules between the cells are eliminated. The SPANROWS option also permits GROUP and ORDER variable values to repeat when the values break across pages in PDF, PS, and RTF destinations. For more information, see the SPANROWS option in PROC REPORT in the Base SAS Procedures Guide.

The following code produces a PDF table without SPANROWS and the same table with SPANROWS:

%macro spanrows_demo(spanrows) ;
  proc report data=sashelp.prdsale nowd &spanrows;
  col region country division prodtype year product actual predict ;
     define region / group;
     define country / group;
     define division / group;
     define year / group;
     define prodtype/ group;
     define product /group;
  run;
%mend;

ods listing close;
ods pdf file="no_spanrows.pdf";
%spanrows_demo();
ods pdf close;
ods pdf file="spanrows.pdf";
%spanrows_demo(spanrows);
ods listing;
ods pdf close;


Variable Name List Shortcuts in PROC TABULATE

This new feature responds to a SASWare ballot item. In SAS 9.2, you can specify variable name list shortcuts in the TABLE statement of PROC TABULATE. These shortcuts are already supported in the CLASS and VAR statements. Here is some example code:

  data one(type=distance);
     input (group x1-x10) (f2. 10*f3.);
     cards;
  1  0
  1 96  0
  1 53 42  0
  1  2 25 95  0
  1 12 10 45 80  0
  1 37 74 87 49  4  0
  1 48 70 60 14 53 11  0
  1 31  6 74 79 98 70 98  0
  1 44  4 75 89 69 50 64  3  0
  1 17 89 55  9 79 15 11 56 65  0
  2  0
  2 25  0
  2 33 15  0
  2 53 65 56  0
  2 11 97 90 55  0
  2 98 71 30 46  5  0
  2 96 98 57 40 44 89  0
  2  7 89 97 47 60 13 11  0
  2 35 41  6  7 84 40 94 78  0
  2 47 73  8 54  1 21 59 52 20  0
  3  0
  3 95  0
  3  1 34  0
  3 34 10 23  0
  3 51 99  3 40  0
  3 90 35 42 17 70  0
  3  8  1 69 79 84 70  0
  3 31 93  9 94 86 77 50  0
  3 59 35 90  8  2  4 60  9  0
  3 84 17 51  8 14 20 77  2 96  0
  ;
  run;

  title 'Test x1-xn';

  proc tabulate;
     class x1-x10;
     table x1-x10;
     table (x10-x1);
     table x1-x10*n;
     table x1-x10,n;
     table x1*pctn x2-x7*(n pctn);
     table x:;
     table x1:;
  run;


MODE Statistic in PROC TABULATE and PROC REPORT

The mode is the value that occurs most often in the data. This statistic is now available in the TABULATE and REPORT procedures. The procedure counts repetitions of the values of the analysis variables. If a tie occurs for the most frequent value, the procedure reports the lowest mode. When no repetitions occur in the data (as with truly continuous data), the procedure does not report the mode (i.e., sets it to missing).

The mode calculation is not performed if QMETHOD=P2 or if a WEIGHT variable is defined. In those cases the mode is set to missing.

Here is some example code:

  data first;
  input x;
  datalines;
  1
  2
  3
  4
  4
  5
  6
  ;

  proc tabulate data=first;
     var x;
     table x*(q1 median q3 mode);
  run;


BLANKLINE Option in PROC PRINT

The BLANKLINE option in the PRINT procedure enables you to insert a blank line after every n observations. Two forms of syntax are supported:

PROC PRINT BLANKLINE = n
where n specifies the number of observations

PROC PRINT BLANKLINE = (COUNT = n <STYLE = [style-attribute-specification(s)] > )
where the style-attribute-specification uses the same syntax as documented in the STYLE option on the procedure statement. Any attribute can be specified, but the only one that is meaningful in this context is BACKGROUND=. You can use BACKGROUND= to change the color of the blank line, making it even more visible. The default style element is DATA. In other words, by default the blank line uses the same style as the data cell. Note that style attributes do not apply to the Listing destination.

The count of observations before inserting a blank line is reset at the beginning of each page and at the beginning of each new BYGROUP. This may result in less than n observations at the end of a page or BYGROUP. For example, if you specify n=10 and you have 52 observations on the page, then a blank line prints after observation 50, followed by 2 observations. The following page starts with the next 10 observations, followed by a blank line.

This option is valid for all destinations. However, the pagination for destinations such as RTF is done by the viewing application, not by PROC PRINT. In those cases, the count of observations before inserting a blank line is only reset at the beginning of a new BYGROUP, not at the beginning of each page.

Example 1: Insert a Blank Line Every Ten Observations

  ods pdf file="blankline.pdf";

  /* create a data set */
  data a;
   do i=1 to 55; output;
   end;
  run;

  proc print blankline=10;
  run;

  ods pdf close;

Example 2: Insert a Blue Blank Line Every Four Observations

  ods pdf file="blankline.pdf";

  /* create a data set */
  data a;
   do i=1 to 10; output;
   end;
  run;

  /* specify a destination other than Listing to see the style specification used */

  proc print blankline=(count=4 style=[background=blue]);
  run;

  ods pdf close;


SUMLABEL Option in PROC PRINT

The SUMLABEL option in the PRINT procedure enables you to display the label of the BY variable on the summary line, if a label exists. The syntax is as follows:

  PROC PRINT SUMLABEL;

When the SUMLABEL option is specified in conjunction with the SUM or SUMBY statements, the variable label of the BY variable is used on each summary line instead of the variable name, if a label exists.

Example 1: Using the SUMLABEL Option

  /* create a data set */
  data a;
     do i=1 to 7;
        do j=1 to 5;
           output;
        end;
     end;
  run;

  proc print data=a sumlabel;
     label i = "My Summing Variable";
     by i;
     sum j;
  run;

Example 2: Using More Than One BY Variable

  /* create a data set */
  data exprev;
  input Region $ State $ Month monyy5.
        Expenses Revenues;
     format month monyy5.;
  datalines;
  Southern GA JAN95 2000  8000
  Southern GA FEB95 1200  6000
  Southern FL FEB95 8500 11000
  Northern NY FEB95 3000  4000
  Northern NY MAR95 6000  5000
  Southern FL MAR95 9800 13500
  Northern MA MAR95 1500  1000
  ;

  proc sort data=exprev;
     by region state;
  run;

  proc print data=exprev noobs sumlabel
       n='Number of observations for the state: '
      'Number of observations for the data set: ';

     sum expenses revenues;
     by region state;
     label region = "Regional Amount";
     label state = "State Amount";
     format revenues expenses comma10.;
     title 'Revenue and Expense Totals for the #byval(region) Region';
  run;


Crosstabs Template in PROC FREQ

New for SAS 9.2 is a crosstabs template for the FREQ procedure. It is written in a dialect of the standard table template language that is both a subset (not everything in the table template language is supported) and a superset (you can do things in the crosstabs template that you can't do in other table templates).

The default template produces a table that is 99.9% identical to the current table. However, using the template you can perform these additional tasks:

Here is some example code. View output.

  ods path (prepend) work.templat(write);
  proc template;
     define style white;
        parent=styles.default;
        style body /
              background=white;
        style systemtitle /
              background=white
              font_size=6
              font_weight=bold
              font_style=italic;
        style systemfooter /
              background=white
              font_size=2
              font_style=italic;
        style proctitle /
              background=white
              foreground=#6078bf
              font_weight=bold
              font_style=italic;
     end;
     define crosstabs Base.Freq.CrossTabFreqs;
        notes "Crosstabulation table";

        define header TableOf;
           text "Table of " _ROW_LABEL_  " by " _COL_LABEL_;
           style=header {background=#BFCFFF foreground=#6078bf font_style=italic};
        end;

        define header ControllingFor;
           /* To use labels in this header substitute `StrataVariableLabels' in the TEXT statement. */
           dynamic StratNum StrataVariableNames StrataVariableLabels;
           text "Controlling for" StrataVariableNames / StratNum > 0;
           style=header;
        end;

        define header RowsHeader;
           text _ROW_LABEL_ / _ROW_LABEL_ ^= '';
           style=header {background=#BFCFFF foreground=#6078bf font_style=italic};
           space=0;
        end;

        define header ColsHeader;
           text _COL_LABEL_ / _COL_LABEL_ ^= '';
           text _COL_NAME_;
           style=header {background=#BFCFFF foreground=#6078bf font_style=italic};
           space=1;
        end;

        define footer Missing;
           dynamic FMissing;
           text "Frequency Missing = " FMissing -12.99 / FMissing ^= 0;
              style=header {background=#BFCFFF foreground=#6078bf font_style=italic};
              space=1;
        end;

        define footer NoObs;
           dynamic SampleSize;
              text "Effective Sample Size = 0" / SampleSize = 0;
              space=1;
              style=header;
        end;

        define cellvalue Frequency;
           header="";
           label="Frequency Count";
           format=BEST7. data_format_override=on print=on;
           cellstyle _val_ < 10 as datastrong {foreground=green},
                     _val_ > 40 & _val_ < 50 as datastrong {foreground=orange},
                     _val_ >= 50 as datastrong {foreground=red};
        end;

        define cellvalue Expected;
           header="";
           label="Expected Frequency";
           format=BEST6. data_format_override=on print=on;
        end;

        define cellvalue Deviation;
           header="";
           label="Deviation from Expected Frequency";
           format=BEST6. data_format_override=on print=on;
        end;

        define cellvalue CellChiSquare;
           header="";
           label="Cell Chi-Square";
           format=BEST6. print=on;
        end;

        define cellvalue TotalPercent;
           header="";
           label="Percent of Total Frequency";
           format=6.2 print=on;
        end;

        define cellvalue Percent;
           header="";
           label="Percent of Two-Way Table Frequency";
           format=6.2 print=on;
        end;

        define cellvalue RowPercent;
           header="";
           label="Percent of Row Frequency";
           format=6.2 print=on;
        end;

        define cellvalue ColPercent;
           header="";
           label="Percent of Column Frequency";
           format=6.2 print=on;
        end;

        define cellvalue CumColPercent;
           header="";
           label="Cumulative Percent of Column Frequency";
           format=6.2 print=on;
        end;

        style=table {background=#BFCFFF}
              cell_style=data {background=#FFFFF0}
              row_var_style=rowheader {background=#BFCFFF  foreground=rowfg.}
              col_var_style=header {background=#BFCFFF  foreground=colfg.}
              row_total_style=data {background=#F0F0F0}
              col_total_style=data {background=#F0F0F0}
              grand_total_style=datastrong {background=#F0F0F0}
              legend_style=header {background=#BFCFFF foreground=#6078bf font_style=italic};

        rows_header=RowsHeader cols_header=ColsHeader;
        label = "Frequency Counts and Percentages";
        header /*TableOf*/ ControllingFor;

        cellvalue
              Frequency Expected Deviation
              CellChiSquare TotalPercent Percent
              RowPercent ColPercent CumColPercent;

        footer NoObs Missing;
     end;

  run;

  proc format;
     Value Govtfmt -3='Council Manager'
                    0='Commission'
                    3='Mayor Council'
                   .N='Not Applicable'
                    .='   ?';
     Value rowfg   -3='red'
                    0='purple'
                    3='blue'
                   .N='green'
                    .='black'
                    other='black';

     Value Robfmt   1='100 or  Less'
                    2='101-200'
                    3='201-300'
                    4='Over 300'
                   .N='Not     Known'
                    .='   ?';
      Value colfg   1='yellow'
                    2='red'
                    3='blue'
                    4='purple'
                   .N='green'
                    .='black'
                    other='black';

  ods html file=test style=white;

  DATA ONE;
     Label Citygovt='City Government Form'
           Robgrp='Number of Citizens Robbed';
     Input Citygovt Robgrp Weight;  Missing N;
     Format Citygovt Govtfmt. Robgrp Robfmt.;
     LOOP: OUTPUT; WEIGHT=WEIGHT-1; IF WEIGHT>0 THEN GOTO LOOP;
     DROP WEIGHT; CARDS;
   0 1  6
   0 3  3
   0 2  7
   0 4  5
   N N 10
  -3 1 47
  -3 3 49
  -3 2 63
  -3 4 52
   . 2  1
   3 1 31
   3 2 37
   3 3 27
   3 4 55
   3 .  1
   ;

  title "City Government Form by Number of Citizens Robbed";
  footnote "Frequency";
  footnote2 "Percent";
  footnote3 "Row Percent";
  footnote4 "Column Percent";
  ods noproctitle;
  proc freq;
     tables citygovt*robgrp / missprint;
  run;

  ods html close;