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 run time:
%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 run time, using dynamics and macro variables.
For more information about 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.