最近,出了几张Table,参考代码是用Gplot过程步输出的。一般出图,我习惯GTL设置Template后,使用Sgrender过程步进行调用。这次统计师要得比较急,我就先照着参考程序进行更新。这篇文章用以梳理一下,这个过程中遇到的问题。
看一下参考的图形:
- 输出的图形是两个PCHG变量的散点图和回归直线;
- 涉及到的统计量有每个治疗组的BigN、回归直线的r方、每个象限的频数占比;
- 两组图形是同排并列放置的。
这里就先不讨论统计量的具体生成过程,看到参考图形的第一眼,我是想到用Template中的layout lattice
处理两组图形并列的问题。当前的任务跟参考的图形有一点不同,参考图形只需要输出Month 36一个访视图形,而目前是需要输出Month 12、Month 24、Month 36三个访视。因此,并列的图形上还需要加上访视的信息。
输出3个访视图形,在Template中,我想到2个处理方法:
- 通过3个条件语句将同样的图形输出3遍(这个可以通过宏程序来实现,以便简化代码);
- 在输出图形时使用By语句进行分组处理。
以上是我在没有看到参考程序时的想法,看了程序之后发现,其实现思路跟我的有所不同。
参考程序两次调用gplot过程步,同时使用gout
选项将两个试验组的图形输出到同一个图形目录下。之后,使用greplay过程步重新调用这个图形目录下的图形,并设置好图形的展现属性,输出到RTF中。程序的逻辑框架如下:
***Create figures and save figures in the graphics catalog - temp;
proc gplot data = anldata gout = temp ;
plot var1*var2;
where trt = "A";
run;
proc gplot data=data1 gout = temp ;
plot var1*var2;
where trt = "B";
run;
quit;
***Set figures display(设置调用图形的4个角的坐标);
proc greplay nofs tc = tempcat;
tdef temp
1/llx = 6 lly=16 ulx=6 uly=90 urx=49 ury=90 lrx=49 lry=16
2/llx = 54 lly=16 ulx=54 uly=90 urx=97 ury=90 lrx=97 lry=16;
run;
***Display figures;
proc greplay nofs tc = tempcat igout = temp;
list igout;
template temp;
treplay 1:1 2:2;
delete _all_;
run;
quit;
之前,我从没有接触过这样的出图设置。我照着参考代码的逻辑,也成功输出一个组别的并列图形。但是目前的任务,还需要输出额外其他两组的并列图形,这3组图形需要分别输出到RTF文件的3个页面中。我尝试了不短的时间,一下子没办法实现,考虑到时间紧迫,我就改用GTL的方法,重写程序。
回过头看,当时自己其实是可以用参考程序的方法,粗略地输出3组图形的——将成功输出的第一组地代码,复制两遍,筛选好对应组别的数据,进行输出。
但是,当时这个方法有两个瑕疵,第一,每个组别的图形上部需要加上组别的Label,直接将图形输出3遍无法处理这个问题;第二,参考代码中的每个图形中的统计量的输出属性都是单独设置的,也就是说,参考这样的代码,我至少进行3*2*N种属性设置(N为单独一张图形中统计量的个数),这个过程太繁琐了。于是,我选择重写代码。
1. Graph Template Language (GTL)——重复输出3次
1.1 处理原始数据
以SASHELP.CLASS数据集为例,分析变量取Height和Weight,演示图形输出。因为有多个访视组,需要提前对数据处理,治疗组变量就选用Sex。考虑到两试验分组并列输出,在同一个Template语句中,需要根据分析的组别进行拆分分析变量。
***1. Get data from SASHELP.CLASS;
data class;
set sashelp.class(in = a)
sashelp.class(in = b)
sashelp.class(in = c);
**Create analysis visit for display;
if a then do;
avisit = "Month 12";
avisitn = 12;
end;
if b then do;
avisit = "Month 24";
avisitn = 24;
end;
if c then do;
avisit = "Month 36";
avisitn = 36;
end;
**Create analysis var;
if sex = "M" then do;
height_m = height;
weight_m = weight;
end;
if sex = "F" then do;
height_f = height;
weight_f = weight;
end;
run;
1.2 设置Template并输出单个访视的图形
数据处理好后,开始Template的设置。使用的方法是,设置同一个Template,每个访视分别调用一次。
3个访视的图形输出在同一个RTF文件中,每一个图形都需要有各自的组别标志,这个一般也有两种方式进行实现:
- 在Begingraph区域,使用
Entrytitle
语句;- 使用
Legenditem
语句新建一个文字类型的Legend,调用时设置为居中放置图形外部 (手动实现Title的效果)。
在Template过程步中,图形的并排输出使用Layout Lattice
语句。该语句创建图形网格,使各个单元内图形输出内容自动对齐,方便比较。这个任务需要输出两列,在Layout Lattice
内部进行各列图形的设置。本次代码中,两组并列图形的设置完全相同。
***2. Create a macro for one avisit figure output;
%macro figure(avisitn = , label = );
**Create a Template;
proc template;
define statgraph plot;
begingraph;
entrytitle "&label";
layout lattice / columns = 2 ;
**Set column headers;
column2headers;
entry textattrs=(weight=bold size=9pt) "Male N = (xxx)";
entry textattrs=(weight=bold size=9pt) "Female N = (xxx)";
endcolumn2headers;
**Column 1 content;
layout overlay/ xaxisopts=(label="Weight") yaxisopts=(label="Height") ;
*Plots of scatterplot and regression;
scatterplot x=weight_m y=height_m / markerattrs=(size = 5pt color=blue symbol=CircleFilled);
regressionplot x=weight_m y=height_m / lineattrs=(color=blue);
endlayout;
**Column 2 content;
layout overlay/ xaxisopts=(label="Weight") yaxisopts=(label="Height") ;
*Plots of scatterplot and regression;
scatterplot x=weight_f y=height_f / markerattrs=(size = 5pt color=blue symbol=CircleFilled);
regressionplot x=weight_f y=height_f / lineattrs=(color=blue);
endlayout;
endlayout;
endgraph;
end;
run;
**Render a Template;
proc sgrender data = class template=plot;
where avisitn = &avisitn.;
run;
%mend figure;
1.3 输出3个访视的图形
针对一个访视的图形输出后,根据访视组别重复3次就可以输出。输出时设置需要的Title 和Footnotes,以及对应的输出路径。
***3. Run macros to creeate figures for 3 avisits;
title "Template for Output";
footnote "Data Generated: &sysdate &systime";
ods rtf file = "&out_dir.test.rtf" nogtitle bodytitle;
ods listing close;
ods select all;
%figure(avisitn = 12, label =Month 12);
%figure(avisitn = 24, label =Month 24);
%figure(avisitn = 36, label =Month 36);
ods rtf close;
ods graphics off;
ods listing;
2. Graph Template Language (GTL)——使用By 语句
2.1 处理原始数据
与1.1内容完全相同,参照前面内容。
2.2 设置Template并按访视变量分组输出图形
跟1.2相比,这一部分代码的改动也不算大。
在Sgplot
过程步中使用By语句,就不需要单独筛选某个访视。1.2中,重复调用宏程序3次,改变每次宏参数的值 (&label
),能够通过entrytitle
语句分别输出3个访视组别的标志内容。使用By语句之后,只调用一次宏程序,如果用宏参数来控制输出组别的标志内容,只能输出一个值,显然这不能满足三个访视的输出。
通过控制宏参数来输出组别的标志内容,参考如下:(这里直接将entrytitle
语句的输出内容设置为“Label”)
***2. Create a macro for one avisit figure output;
%macro figure;
**Create a Template;
proc template;
define statgraph plot;
begingraph;
entrytitle "label";
layout lattice / columns = 2 ;
**Set column headers;
column2headers;
entry textattrs=(weight=bold size=9pt) "Male N = (xxx)";
entry textattrs=(weight=bold size=9pt) "Female N = (xxx)";
endcolumn2headers;
**Column 1 content;
layout overlay/ xaxisopts=(label="Weight") yaxisopts=(label="Height") ;
*Plots of scatterplot and regression;
scatterplot x=weight_m y=height_m / markerattrs=(size = 5pt color=blue symbol=CircleFilled);
regressionplot x=weight_m y=height_m / lineattrs=(color=blue);
endlayout;
**Column 2 content;
layout overlay/ xaxisopts=(label="Weight") yaxisopts=(label="Height") ;
*Plots of scatterplot and regression;
scatterplot x=weight_f y=height_f / markerattrs=(size = 5pt color=blue symbol=CircleFilled);
regressionplot x=weight_f y=height_f / lineattrs=(color=blue);
endlayout;
endlayout;
endgraph;
end;
run;
**Render a Template;
proc sgrender data = class template=plot;
where avisitn = &avisitn.;
run;
%mend figure;
title "Template for Output";
footnote "Data Generated: &sysdate &systime";
ods rtf file = "&out_dir.test.rtf" nogtitle bodytitle;
ods listing close;
ods select all;
%figure;
ods rtf close;
ods graphics off;
ods listing;
程序运行后,我们可以看到By语句会自动在图形之上,输出具体对应这个图形的亚组。显然,avisitn=12
是不符合输出要求的,对于此,可以可以通过控制分组变量的Label和Format来更新此处输出的内容,这一部分我在前面文章中有过介绍,读者可以参考SAS编程:特殊字符-空格的应用 。
不过,这种方法输出的效果调整也只能输出成类似Analysis Visit = Month 12。这里需要与统计师进行沟通,如果统计师不能介绍这样的输出,并且鉴定的要求输出成“Month 12”,那只能另寻其他方法了。
以宏参数控制entrytitle
语句输出,会使3个访视输出结果相同,并且也会与前面By变量的显示冲突。所以,使用By语句是需要移除entrytitle
语句的。
结语:
这篇文章介绍了GTL语言输出分组并列的Figure的方法,更细一步讲,是介绍GTL语言输出分组Figure的方法(重复输出或使用By语句),以及介绍GTL语言输出并列Figure的方法(layout lattice
语句)。
关于具体的坐标轴的属性设置,文章并没有介绍。这一块属性的调试也会花费不少时间。具体的语法介绍,读者可以参考SAS的官方文档:SAS Help Center: SAS 9.4 Graph Template Language: Reference, Fifth Edition。