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

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

作者: 野藤_ | 来源:发表于2022-01-13 23:50 被阅读0次

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

    看一下参考的图形:

    • 输出的图形是两个PCHG变量的散点图回归直线
    • 涉及到的统计量有每个治疗组的BigN、回归直线的r方、每个象限的频数占比;
    • 两组图形是同排并列放置的。
    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;
    
    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语句的。

    Result 2

    结语:

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

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

    感谢阅读!若有疑问,欢迎评论区交流!

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/jyajcrtx.html