当前位置: 首页>大数据>正文

SAS编程:如何实现Figure的分组并列输出?(1)

最近,出了几张Table,参考代码是用Gplot过程步输出的。一般出图,我习惯GTL设置Template后,使用Sgrender过程步进行调用。这次统计师要得比较急,我就先照着参考程序进行更新。这篇文章用以梳理一下,这个过程中遇到的问题。

看一下参考的图形:

  • 输出的图形是两个PCHG变量的散点图回归直线
  • 涉及到的统计量有每个治疗组的BigN、回归直线的r方、每个象限的频数占比;
  • 两组图形是同排并列放置的。
SAS编程:如何实现Figure的分组并列输出?(1),第1张
Output 1

这里就先不讨论统计量的具体生成过程,看到参考图形的第一眼,我是想到用Template中的layout lattice处理两组图形并列的问题。当前的任务跟参考的图形有一点不同,参考图形只需要输出Month 36一个访视图形,而目前是需要输出Month 12、Month 24、Month 36三个访视。因此,并列的图形上还需要加上访视的信息。

输出3个访视图形,在Template中,我想到2个处理方法:

  1. 通过3个条件语句将同样的图形输出3遍(这个可以通过宏程序来实现,以便简化代码);
  2. 在输出图形时使用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文件中,每一个图形都需要有各自的组别标志,这个一般也有两种方式进行实现:

  1. 在Begingraph区域,使用Entrytitle语句;
  2. 使用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;
SAS编程:如何实现Figure的分组并列输出?(1),第2张
Month 12

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语句的。

SAS编程:如何实现Figure的分组并列输出?(1),第3张
Result 2

结语:

这篇文章介绍了GTL语言输出分组并列的Figure的方法,更细一步讲,是介绍GTL语言输出分组Figure的方法(重复输出或使用By语句),以及介绍GTL语言输出并列Figure的方法(layout lattice语句)。

关于具体的坐标轴的属性设置,文章并没有介绍。这一块属性的调试也会花费不少时间。具体的语法介绍,读者可以参考SAS的官方文档:SAS Help Center: SAS 9.4 Graph Template Language: Reference, Fifth Edition。


https://www.xamrdz.com/bigdata/7sv1996091.html

相关文章: