The main difference between dynamics
and macro variables is that they are initialized differently.
For dynamics,
use the DYNAMIC statement with PROC SGRENDER. Values for dynamics
that resolve to column names or strings should be quoted. Numeric
values should not be quoted:
proc sgrender data=financial template=timeseries;
dynamic yvar="inflation" ylabel="Inflation Rate";
run;
For macro variables, use the
current symbol table (local or global) to look up the macro variable
values at runtime:
%let locate=inside;
%let trans=.3;
proc sgrender data=financial template=timeseries;
dynamic yvar="inflation" ylabel="Inflation Rate";
run;
No initialization is needed
for automatic macro variables like the system date and time value
SYSDATE.
It is
the responsibility of the person or process that initializes the dynamics
or macro variables to ensure that the expected value type and value
that is supplied is appropriate for the substitution context. If necessary,
you can use conditional logic to evaluate the supplied values of dynamics
or macro variables. Conditional logic
is discussed in Using Conditional Logic and Expressions.
If a dynamic
is used to supply a GTL option with a specific value and the supplied
value is not valid or it is not initialized, then the option specification
is ignored and the option's default value is used. For example, the
HALIGN= option accepts the values RIGHT, CENTER, and LEFT. If the
dynamic variable ALIGN is defined and then the template code specifies
HALIGN=ALIGN, the ALIGN dynamic must be initialized with one of the
values RIGHT, CENTER, or LEFT. If it is initialized with another value,
TOP for example, the HALIGN= specification in the template is ignored,
the default setting for HALIGN= is used, and you might see a warning
in the SAS log.
If a dynamic
is used to supply a required argument such as a column name, and the
name is misspelled or not provided, then a warning is issued and that
plot statement drops out of the final graph. A graph will still be
produced, but it might be a blank graph, or it might show the results
of all statements except those that are in error.
The following
example shows how to create a generalized template that can be used
to show the distribution of any numeric variable. The dynamic named
VAR must be set, but the other dynamics are optional: BINS (sets
the number of histogram bins) and FOOTNOTE. In the example, the DYNAMIC
and MVAR variables are highlighted to emphasize where they are being
used.
proc template;
define statgraph distribution;
dynamic VAR BINS FOOTNOTE ;
mvar SYSDATE ;
begingraph;
entrytitle "Distribution of " VAR " with Normal Density Curve";
entryfootnote halign=left FOOTNOTE halign=right "Created " SYSDATE ;
layout lattice / rowweights=(.9 .1) columndatarange=union
rowgutter=2px;
columnaxes;
columnaxis / display=(ticks tickvalues);
endcolumnaxes;
layout overlay / yaxisopts=(offsetmin=.04 griddisplay=auto_on);
histogram VAR / scale=percent nbins=BINS ;
densityplot VAR / normal( ) name="Normal";
fringeplot VAR / datatransparency=.7;
endlayout;
boxplot y=VAR / orient=horizontal primary=true boxwidth=.9;
endlayout;
endgraph;
end;
run;
The following
execution of the template initializes the dynamic variables VAR and
FOOTNOTE, but it does not initialize BIN:
proc sgrender data=sashelp.heart template=distribution;
dynamic var="Cholesterol"
footnote="From Framingham Heart Study (SASHELP.HEART)";
run;
In this
case, the template option
bins=BINS
drops
out because the BINS dynamic has not been initialized.
This next
execution of the template assigns values to each of the dynamics VAR,
BIN, and FOOTNOTE, using different values from the previous example:
proc sgrender data=sashelp.cars template=distribution;
dynamic var="Invoice" bins=20 footnote="From SASHELP.CARS";
run;
The next
example shows a simplified version of the previous graph, this time
adding an inset. The inset statistics are computed external to the
template and passed into the template at runtime, using dynamics and
macro variables. For more information on coding insets in graphs,
see Adding Insets to a Graph.
proc template;
define statgraph inset;
dynamic VAR FOOTNOTE;
mvar N MEAN STD;
begingraph;
entrytitle "Distribution of " VAR;
entryfootnote halign=left FOOTNOTE;
layout overlay / yaxisopts=(griddisplay=on);
histogram VAR / scale=percent;
layout gridded / columns=2
autoalign=(topleft topright) border=true
opaque=true backgroundcolor=GraphWalls:color;
entry halign=left "N"; entry halign=left N ;
entry halign=left "Mean"; entry halign=left MEAN ;
entry halign=left "Std Dev"; entry halign=left STD ;
endlayout;
endlayout;
endgraph;
end;
run;
We will
now define a macro that can pass values to this template. For a given
numeric variable, the macro computes the number of observations, the
mean, and the standard deviation, storing these statistics in macro
variables N, MEAN, and STD. The macro variables are available to the
SGRENDER step when the macro executes. Here is the definition for
the macro, which we will name HIST:
%macro hist(dsn,numvar,footnote);
/* these macro variables are declared in the template */
%local N MEAN STD;
proc sql noprint;
select put(n(&numvar),12. -L),
put(mean(&numvar),12.2 -L),
put(std(&numvar),12.2 -L) into :N, :MEAN, :STD
from &dsn;
quit;
/* remove trailing blanks */
%let N=&N; %let MEAN=&MEAN; %let STD=&STD;
proc sgrender data=&dsn template=inset;
dynamic VAR="&numvar" FOOTNOTE="&footnote";
run;
%mend;
Here are
results of two executions of the macro with different input data.
Notice the placement of the inset might change on based on the amount
of space that is available and the setting for the AUTOALIGN= option.
%hist(sashelp.heart, cholesterol, From SASHELP.HEART)
%hist(sashelp.cars, Weight, From SASHELP.CARS)
If you
are familiar with the macro facility, you can create macros that
validate the parameters before executing the template. It is also
possible to validate the parameters within the compiled template,
using the conditional logic syntax of GTL. For more information,
see Using Conditional Logic and Expressions.
GTL supports
user-defined computed expressions within compiled templates. This
means that the inset statistics could have been computed directly
within template, eliminating the need to pass them in with dynamics
or macro variables. An example of how to do this is also
discussed in Using Conditional Logic and Expressions.
For developers
who would like to create a library of reusable templates, see the
discussion on creating shared templates
in Creating Shared Templates.