SAS如何生成箱型图(Box-Plot) 3--临床试验分析具体

2020-08-18  本文已影响0人  野藤_

在上一篇文章SAS如何生成箱型图(Box-Plot) 2--SAS代码介绍中介绍了,SAS中生成Boxplot的4种方法,示例代码生成的图形比较简单。在临床试验分析中,我们通常使用GTL来生成“复杂精美”的图形,下面分享运用GTL生成Boxplot的具体案例代码。

Boxplot template

这张图形是,某项目中各访视某指标的基线变化值的箱型图。图形中,X轴为试验访视,Y轴为基线变化值;在每一访视中,Boxplot按试验用药进行分组;在Y=0处,有一条灰色的参考线;在每一访视分组中,需要计算各组的描述统计量。

如何实现上图的效果?我是用sashelp.class数据集进行展示,考虑到需要访视信息,我将数据集重复Set 4次,添加访视信息。

data class;
  set sashelp.class( in = a )
    sashelp.class( in = b)
    sashelp.class( in = c)
    sashelp.class( in = d);

    if a then avisitn = 1;
    else if b then avisitn = 2;
    else if c then avisitn = 3;
    else if d then avisitn = 4;
run;

用GTL模板出图,首先要制作模板,先把模板框架写好,不断向框架中添加图形中需要的元素。

proc template;
   define statgraph boxplot_;
    begingraph;
      ···
      ···
    endgraph;
  end;
run;

先在模板中定义坐标轴的属性,考虑到坐标轴需要覆盖数据的所有范围,Y轴需要确定范围,最小值设为50,最大值设为90,间隔为5;X轴为研究访视,数目是确定的,但需要指定每一个访视的名称。tickdisplaylist=()选项需要和tickvaluelist=()选项一起使用,并且这两个选项只能用于线性轴 (linear axes only).

layout overlay/ 
yaxisopts=(
label = "Height"  labelattrs = (size = 7)  tickvalueattrs=(size=7pt)
linearopts=(ViewMin=50 ViewMax=90 tickValueSequence=(start = 50 end = 90 increment = 5))
)

xaxisopts=(
label = "Study Visit" labelattrs = (size = 7)  tickvalueattrs=(size=7pt)  type=linear
linearopts=(tickvaluelist=(1 2 3 4)  tickdisplaylist=("M6" "M12" "M18" "M24"))
);
···
···

endlayout;

坐标轴属性设置后,进行Boxplot图形的设置。groupdisplay=选项有两个可选值Stack、Cluster。Stack选项使各组堆叠显示;Cluster选项使各组分散显示。

layout overlay/ 
···
···
boxplot y = height  x = avisitn /
    display=(caps mean median outliers)
    group = sex groupdisplay=cluster name = "Boxplot";
···
···
endlayout;

将参考线设为Y=65:

layout overlay/ 
···
···
referenceline y = 65 / lineattrs=(color=grey);
···
···
endlayout;

设置图标属性,这里的图标名称与Boxplot语句中的name一致:

layout overlay/ 
···
···
discretelegend "Boxplot" / location=inside halign=left valign=top across=1 border=false;
···
···
endlayout;

以上属性设置后,生成的图形为如下:

Boxplot1

图形的上半部分已经完成,现在需要完成图形下半部分中各组别的统计量。按照avisitn*sex分组来看 ,这个图形有8个子组。考虑到Boxplot已经使用avisitn作为X轴,这样的话X轴上只要4个“展示位”,我们需要将同一访视中的不同男女性别的统计量合并起来。

proc means data=class ;
  class avisitn sex;
  var height;
  output n=n mean=mean std=sd  median=median q1=q1 q3=q3 min=min max=max out=stat(where =(_type_=3));
run;

data stat_m;
  set stat(rename = (n=m_n mean=m_mean sd=m_sd median=m_median q1=m_q1 q3=m_q3 min=m_min max=m_max) drop = _:);
  where sex = "M";
run;

data stat_f;
  set stat(rename = (n=f_n mean=f_mean sd=f_sd median=f_median q1=f_q1 q3=f_q3 min=f_min max=f_max) drop = _:);
  where sex = "F";
run;

data stat_final;
    merge stat_m(drop=sex) stat_f(drop=sex);
    by avisitn ;
    length n mean sd median q1q3 minmax $40;
    n = put(m_n, 5.)||"    "||put(f_n, 5.);
    mean = put(m_mean, 8.3)||"    "|| put(f_mean, 8.3);
    sd = put(m_sd, 8.3)||"    "||put(f_sd, 8.3);
    median = put(m_median, 8.3)||"    "|| put(f_median, 8.3);
    q1q3 = put(m_q1, 8.3)||", "||put(m_q3, 8.3)||"    "||put(f_q1, 8.3)||", "||put(f_q3, 8.3);
    minmax = put(m_min, 8.3)||", "||put(m_max, 8.3)||"    "||put(f_min, 8.3)||", "||put(f_max, 8.3);

    drop  f_:  m_: ;
    proc sort data = stat_final;
        by avisitn;
run;

data class_stat;
    merge class(in = a) stat_final;
    by avisitn;
    if a;
run;

统计量是直接放置在Boxplot图形下方区域,这个区域需要innermargin / align=bottom; -- endinnermargin;语句进行创建;具体的统计量数值,需要blockplot语句进行放置。示例代码中,开头是一个宏变量Size的赋值,这是因为编程中每一个block内的数字大小需要根据出图的结果进行不断调整,使用宏变量后,不需要一个一个调整Blockplot语句中的Size。

%let size = 5pt;
innermargin / align=bottom;
  blockplot x=avisitn block = n / label="n"  display=(label values) repeatedvalues=true
   valuehalign = start valuefitpolicy= none labelposition=left labelattrs=graphdata1(size=6pt)
   valueattrs=graphdata1(size=&size.)

blockplot x=avisitn block = mean / label="Mean"  display=(label values) repeatedvalues=true
   valuehalign = start valuefitpolicy= none labelposition=left labelattrs=graphdata1(size=6pt)
   valueattrs=graphdata1(size=&size.)

blockplot x=avisitn block = sd/ label="SD"  display=(label values) repeatedvalues=true
   valuehalign = start valuefitpolicy= none labelposition=left labelattrs=graphdata1(size=6pt)
   valueattrs=graphdata1(size=&size.)

blockplot x=avisitn block = media/ label="Median"  display=(label values) repeatedvalues=true
   valuehalign = start valuefitpolicy= none labelposition=left labelattrs=graphdata1(size=6pt)
   valueattrs=graphdata1(size=&size.)

blockplot x=avisitn block = q1q3/ label="Q1, Q3"  display=(label values) repeatedvalues=true
   valuehalign = start valuefitpolicy= none labelposition=left labelattrs=graphdata1(size=6pt)
   valueattrs=graphdata1(size=&size.)

blockplot x=avisitn block = minmax/ label="Min, Max"  display=(label values) repeatedvalues=true
   valuehalign = start valuefitpolicy= none labelposition=left labelattrs=graphdata1(size=6pt)
   valueattrs=graphdata1(size=&size.)
endinnermargin;

模板设置基本完成,我们来看一下调用模板后运行的结果:

proc sgrender data=class_stat template=boxplot_;
run;
Boxplot2

图形的内容已经都展现出来,不过有以下几个问题:

  1. 底部区域中的Q1Q3、Minmax内容重叠;
  2. 图标(M/F)应该在Y轴坐标范围之上;
  3. X轴两侧空白区域太大,需要扩大(扩大后可以解决底部区域重叠的问题);
  4. Y轴坐标上限值太大,可以缩小;
  5. 示例图片中,Y轴有密集的小坐标,现在图形中没有。

前3个问题,其实可以归为一类,都是坐标轴范围问题,可以用轴选项OFFSETMIN=/OFFSETMAX=进行设置。这两个选项的作用是,在坐标轴的最小末端或最大末端保留一块区域,区域内不显示数据内容 (Reserves an area at the minimum/maximum end of the axis. No tick marks are displayed in the reserved area.)。目前图形中的问题是,Y轴上端保留的区域过小,X轴左右两端保留的区域过大。

Y轴坐标数值过大,可以直接设置显示最大值为80。为保证参考线Y=65左侧有数字65显示,将Y轴坐标数字间隔设为5。

关于坐标轴的小坐标,可以使用minorticks=true/false选项来控制。minorticks=true默认添加一个小坐标,如果想要小坐标更密集一点,可以使用minortickcount=选项,自定义小坐标的数目。

修改后的结果如下:

layout overlay/ 
yaxisopts=(
label = "Height"  labelattrs = (size = 7)  tickvalueattrs=(size=7pt)
linearopts=(minorticks=true minortickcount=5 ViewMin=50 ViewMax=80 tickValueSequence=(start = 50 end = 80 increment = 5))
offsetmin=0.08 offsetmax=0.15
)

xaxisopts=(
label = "Study Visit" labelattrs = (size = 7)  tickvalueattrs=(size=7pt)  type=linear
linearopts=(tickvaluelist=(1 2 3 4)  tickdisplaylist=("M6" "M12" "M18" "M24"))
offsetmin=0.15 offsetmax=0.15
);
···
···

endlayout;
Boxplot3

X轴坐标值范围扩大后,Boxplot箱体部分显得有些宽,这个可以在Bolplot语句中通过boxwidth=进行调节,这里就不做代码分享了。

关于图标M/F, 在一些项目中会要求显示各组总人数,例如:Male (N = XXX)。这里分享两个思路:

legenditem type=line name="M" /label = "Male (N = XXX)" lineattrs = (pattern = solid color=blue);
legenditem type=line name="F" /label = "Female (N = XXX)" lineattrs = (pattern = solid color=red);
layout overlay/ 
···
···
discretelegend "M" "F" / location=inside halign=left valign=top across=1 border=false;
···
···
endlayout;

这里有一个小的注意点,通常N的值我们是保存在宏变量中的,直接调用的话前后可能会有空格,需要处理一下去掉空格。

legenditem type=line name="M" /label = "Male (N = %sysfunc(strip(&N_M.)))" lineattrs = (pattern = solid color=blue);
legenditem type=line name="F" /label = "Female (N = %sysfunc(strip(&N_F.)))" lineattrs = (pattern = solid color=red);
Boxplot4

至此,Boxplot系列分享结束。如有疑问,欢迎留言反馈。

GTL语法问题可以参考:SAS® 9.4 Graph Template Language Reference, Fifth Edition
)

相关文章:
SAS如何生成箱型图(Box-Plot) 1--箱型图简介
SAS如何生成箱型图(Box-Plot) 2--SAS代码介绍

上一篇下一篇

猜你喜欢

热点阅读