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

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

作者: 野藤_ | 来源:发表于2020-08-18 18:00 被阅读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)。这里分享两个思路:

    • 第一个,直接将变量Sex的"M"值修改为“Male (N = XXX)”;
    • 第二个,新建一个图标,discretelegend语句中直接展示新建的图标。
    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代码介绍

    相关文章

      网友评论

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

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