PROC TEMPLATE is great for defining reusable named style elements.
However, when a named style element is used in a PROC REPORT DEFINE statement, and then a CALL DEFINE is used to modify the style, the named style element is ignored and the default style element (Data) is used instead.
Is there a way to enable inheritance so that CALL DEFINE honors the style element that was specified in the DEFINE statement?
For example, the following code shows how CALL DEFINE does not inherit the DEFINE statement's style element and instead implicitly reverts back to the "Data" style element:
data test;
input id $ num pct;
cards;
A 7777 0.831
B 8888 0.123
C 9999 0.014
;
run;
ods path(prepend) work.templat(update);
proc template;
define style example / store=work.templat(update);
parent = styles.printer;
class data / color=red;
style data_text from data / color=cyan tagattr='format:@ type:string';
style data_number from data / color=purple tagattr='format:#,##0' fontweight=bold;
style data_percent from data / color=magenta tagattr='format:0.0%' fontstyle=italic;
end;
quit;
%let xlfile=%sysfunc(pathname(work))/test.xlsx;
options device=png;
ods excel file="&xlfile" style=example;
* When named style elements are used in DEFINE, they are not inherited in
* CALL DEFINE. Instead, the style element reverts back to the default, Data. ;
proc report data=test;
columns id num pct;
define id / display style(column)=data_text;
define num / display style(column)=data_number;
define pct / display style(column)=data_percent;
compute pct;
if id='C' then do;
call define(_row_, 'style/merge', 'style=[backgroundcolor=yellow]');
end;
endcomp;
run;
ods excel close;
There are of course workarounds to get the desired styles, but none have the simple elegance and efficiency of proper inheritance.
For example, one workaround is to redundantly re-specify the style elements using additional CALL DEFINE statements:
proc report data=test;
columns id num pct;
define id / display style(column)=data_text;
define num / display style(column)=data_number;
define pct / display style(column)=data_percent;
compute pct;
if id='C' then do;
call define(_row_, 'style/merge', 'style=[backgroundcolor=yellow]');
call define('id', 'style/merge', 'style=data_text');
call define('num', 'style/merge', 'style=data_number');
call define('pct', 'style/merge', 'style=data_percent');
end;
endcomp;
run;
Another workaround is to abandon named style elements altogether, since any hard-coded styles on the DEFINE statement do properly inherit in CALL DEFINE:
proc report data=test;
columns id num pct;
define id / display style(column)=[color=cyan tagattr='format:@ type:string'];
define num / display style(column)=[color=purple tagattr='format:#,##0' fontweight=bold];
define pct / display style(column)=[color=magenta tagattr='format:0.0%' fontstyle=italic];
compute pct;
if id='C' then do;
call define(_row_, 'style/merge', 'style=[backgroundcolor=yellow]');
end;
endcomp;
run;
Are workarounds like these really the only way? Do named style elements truly suffer from such a fundamental lack of inheritance when CALL DEFINE comes into play? Or is there some way to enable that inheritance...?
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.