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

最近,出了几张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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容