*
;
/*Recently there was a flurry of questions about how to put multiple graphs on
a page and add titles to graphs in a catalog. Warren Sarle has kindly
provided some macros that are helpful for such things.

Although these macros are not officially supported, I know that Warren will
try to fix bugs and make improvements as time permits, so please send bug
reports and suggestions to saswss@unx.sas.com.
*/
 /********************************************************************

       name: grid
      title: Replay graphs in a regular grid
    product: graph
     system: all
      procs: greplay gslide
    support: saswss                      update:  10jul95

 DISCLAIMER:

       THIS INFORMATION IS PROVIDED BY SAS INSTITUTE INC. AS A SERVICE
 TO ITS USERS.  IT IS PROVIDED "AS IS".  THERE ARE NO WARRANTIES,
 EXPRESSED OR IMPLIED, AS TO MERCHANTABILITY OR FITNESS FOR A
 PARTICULAR PURPOSE REGARDING THE ACCURACY OF THE MATERIALS OR CODE
 CONTAINED HEREIN.

 The %GRID macro lets you easily replay graphs in a regular grid with
 one or more rows and one or more columns. The %GRID macro also
 supports titles and footnotes for the entire replayed graph. For
 example, if you have run GPLOT four times and want to replay these
 graphs in a 2-by-2 grid with the title 'Four Marvelous Graphs', you
 could submit the following statements:

    title 'Four Marvelous Graphs';
    %grid( gplot*4, rows=2, cols=2);

 The %GRID macro allows 10% of the vertical size of the graph for
 titles by default. You can adjust this percentage via the TOP=
 argument in %GRID. Determining the best value for TOP= requires
 trial and error in most cases. To allow space for footnotes, use
 the BOTTOM= argument.

 The graphs to replay must be stored in a graphics catalog with
 library and member names specified by the macro variables &glibrary
 and &gout. By default, SAS/GRAPH stores graphs in WORK.GSEG, which
 is the catalog that the %GRID macro uses by default.  If your
 graphs are in another catalog, you must specify &glibrary and/or
 &gout using %LET statements as shown below.

 Each graph that is stored in a catalog has a name. Each procedure
 assigns default names such as GPLOT, GPLOT1, GPLOT2, etc. Most
 SAS/GRAPH procedures let you specify the name via a NAME= option
 which takes a quoted string that must be a valid SAS name. However,
 if a graph by that name already exists in the catalog, SAS/GRAPH
 appends a number to the name; it does not replace the previous graph
 by the same name unless you specify GOPTIONS GOUTMODE=REPLACE, but
 this option causes _all_ entries in the catalog to be deleted
 everytime you save a new graph, so it is not very useful. If you want
 to replace a single graph in a catalog, sometimes you can use the
 %GDELETE macro to delete the old one and later recreate a graph with
 the same name, but this does not work reliably due to a bug in
 SAS/GRAPH. By default, %GDELETE deletes _everything_ in the catalog;
 this does seem to work reliably.

 When you use BY processing, SAS/GRAPH appends numbers to the graph
 name to designate graphs for each BY group. For example, if you run
 GPLOT with three BY groups and NAME='HENRY', the graphs are named
 HENRY, HENRY1, and HENRY2. The %GRID macro lets you abbreviate this
 list of names as HENRY*3, where the repetition factor following the
 asterisk is the total number of graphs, not the number of the last
 graph.

 *********************************************************************/

%let glibrary=WORK;
%let gout=GSEG;

%macro grid(  /* replay graphs in a rectangular grid */
   list,      /* list of names of graphs, separated by blanks;
                 a name may be followed by an asterisk and a
                 repetition factor with no intervening blanks;
                 for example, ABC*3 is expanded to: ABC ABC1 ABC2 */
   rows=1,    /* number of rows in the grid */
   cols=1,    /* number of columns in the grid */
   top=10,    /* percentage at top to reserve for titles */
   bottom=0); /* percentage at bottom to reserve for footnotes */

   %gtitle;
   %greplay;
   %tdef(rows=&rows,cols=&cols,top=&top,bottom=&bottom)
   %trep(&list,rows=&rows,cols=&cols)
   run; quit;
%mend grid;


%macro gdelete(list); /* delete list of graphs from the catalog;
                         default is _ALL_ */

   %if %bquote(&list)= %then %let list=_ALL_;
   proc greplay igout=&glibrary..&gout nofs;
      delete &list;
   run; quit;
%mend gdelete;


%macro gtitle; /* create graph with titles and footnotes only */

   %global titlecnt;
   %if %bquote(&titlecnt)= %then %let titlecnt=1;
                           %else %let titlecnt=%eval(&titlecnt+1);
   goptions nodisplay;
   proc gslide gout=&glibrary..&gout name="title&titlecnt";
   run;
   goptions display;
%mend gtitle;


%macro greplay( /* invoke PROC GREPLAY */
   tc);         /* template catalog; default is JUNK */

   %if %bquote(&tc)= %then %let tc=junk;
   proc greplay nofs tc=&tc;
      igout &glibrary..&gout;
%mend greplay;


%macro tdef(  /* define a template for a rectangular grid */
   rows=1,    /* number of rows in the grid */
   cols=1,    /* number of columns in the grid */
   top=10,    /* percentage at top to reserve for titles */
   bottom=0); /* percentage at bottom to reserve for footnotes */
   %global tdefname; /* returned: name of template */

   %local height width n row col lower upper left right;
   %let height=%eval((100-&top-&bottom)/&rows);
   %let width =%eval(100/&cols);
   %let tdefname=t&rows._&cols;
   tdef &tdefname
      0/ulx=0 uly=100 llx=0 lly=0 urx=100 ury=100 lrx=100 lry=0
   %let n=1;
   %do row=1 %to &rows;
      %let lower=%eval(100-&top-&row*&height);
      %let upper=%eval(&lower+&height);
      %do col=1 %to &cols;
         %let right=%eval(&col*&width);
         %let left =%eval(&right-&width);
         &n/ulx=&left uly=&upper llx=&left lly=&lower
            urx=&right ury=&upper lrx=&right lry=&lower
         %let n=%eval(&n+1);
      %end;
   %end;
   ;
   template &tdefname;
%mend tdef;


%macro trep( /* replay graphs using template defined by %TDEF */
   list,     /* list of names of graphs, separated by blanks;
                a name may be followed by an asterisk and a
                repetition factor with no intervening blanks;
                for example, ABC*3 is expanded to: ABC ABC1 ABC2 */
   rows=,    /* (optional) number of rows in template */
   cols=);   /* (optional) number of columns in template */
             /* rows= and cols= default to values set with %TDEF */

   %global titlecnt;
   %local i l n row col name root suffix nrep;
   %if %bquote(&rows)= %then %let rows=%scan(&tdefname,1,t_);
   %if %bquote(&cols)= %then %let cols=%scan(&tdefname,2,t_);
   treplay 0:title&titlecnt
   %let nrep=0;
   %let l=0;
   %let n=0;
   %do row=1 %to &rows;
      %do col=1 %to &cols;
         %let n=%eval(&n+1);
         %if &nrep %then %do;
            %let suffix=%eval(&suffix+1);
            %if &suffix>=&nrep %then %do;
               %let nrep=0;
               %goto tryagain;
            %end;
            %let name=&root&suffix;
            %goto doit;
         %end;
%tryagain:
         %let l=%eval(&l+1);
         %let name=%qscan(&list,&l,%str( ));
         %if &name= %then %goto break;
         %let i=%index(&name,*);
         %if &i %then %do;
            %let nrep=%substr(&name,&i+1);
            %if &nrep<=0 %then %goto tryagain;
            %let root=%substr(&name,1,&i-1);
            %let name=&root;
            %let suffix=0;
         %end;
%doit:
         &n:&name
      %end;
   %end;
%break:
   ;
%mend trep;

 /****************** Examples for the %GRID macro *******************/
/*
%inc greplay;

data trig;
   do n=1 to 100;
      x1=sin(n/16);
      x2=sin(n/8);
      y1=cos(n/16);
      y2=cos(n/8);
      output;
   end;
run;

goptions nodisplay;
proc gplot data=trig;
   title 'Y1 by X1';
   plot y1*x1;
run;
   title 'Y1 by X2';
   plot y1*x2;
run;
   title 'Y2 by X1';
   plot y2*x1;
run;
   title 'Y2 by X2';
   plot y2*x2;
run;

title 'Four Marvelous Graphs';
%grid( gplot*4, rows=2, cols=2);


title 'Adding a Title to a Single Graph';
footnote 'And a Footnote';
%grid( gplot, top=12, bottom=5);
*/

*
;