前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SAS-时药曲线的绘制(完)

SAS-时药曲线的绘制(完)

作者头像
Setup
发布2019-10-20 14:31:37
2.7K0
发布2019-10-20 14:31:37
举报

欢迎来到SAS程序分享号

本文是上一篇的推文的续篇,本篇推文将主要介绍GTL绘制受试者维度的时药曲线(画拼图),并分享小编刚出炉的,还热腾腾的自动画图的宏程序。点击

【前文回顾】

授人以鱼不如授人以渔

授人以渔

既然决定授人以渔,那么小编打算从程序设计的原理开始分享。

1.数据集结构的处理(将数据集转置,并保留SUBJID、PKTPT、GROUP作为公共变量,每个受试者编号作为一个新的变量)

2.编写Template语句(利用column、rows来设置每页拼图数量,利用dynamic将template中的Y轴的变量开放出来,便于后面修改dynamic后的变量的值进行控制输出。稍后会列举一个2x1图开放式的代码作为例子,便于观察理解)

3.循环proc sgrender过程,每次修改dynamic后变量的值,即可实现。

程序的设计思路大概就是上面的那个样子的。下面看一个简单的例子。

自动输出宏程序

宏参数设置

小编写宏的时候,一般会事先考虑宏的功能,然后将一些参数进行开放出来。当然一些不太好自动处理的地方小编也是图省事,将其开放出来。下面来看看小编设置的宏参数。

/*************************************************************************************************************************
宏名称    : drw_pk

目的      : GTL语句画 colunms X rows图

参数说明:    inds     输入数据集
      subjid     受试者编号/随机号 
      pktpt      计划时间点的变量
      pkorres        药物浓度
      group      组别
      xvalue     X轴坐标轴数据
      yvalue     Y轴坐标轴数据
      colunms    拼图列数
      rows      拼图行数
      width     每个子图的宽度(cm)
      height    每个子图的高(cm)
      outpath    RTF输出的路径
__________________________________________________________________________________________________________________________
版本     日期           修改人             修改描述
---     -----------    ------------     ----------------------------------------------------------------------------------
1.0     2018.12.10      setup           SAS程序分享号号号(微信号:xiaocgn)创建
****************************************************************************************************************************************/

定义线条颜色类型等

小编预先设定分组用到的标记符号、颜色、线条类型等,并根据数据中实际分组数进行自动获取分组标记,赋值给宏变量。便于后面在Template语句中调用。代码如下。

%macro  drw_pk(inds=,subjid=,pktpt=%str(),pkorres=%str(),group=%str(),xvalue=%str(),yvalue=%str(),colunms=%str(),rows=%str(),width=%str(),
height=%str(),outpath=);

options  nocenter  nodate nonumber nobyline missing=' ';
/*解除变量名称限制*/
options validvarname=any;
/********************************************************************************************
*设置散点形状、线条类型、颜色;
*******************************************************************************************/

*获取分组;
proc sql noprint;
    select distinct(&group.) into:gplist separated by "|" from &inds.  ;
quit;
%let color=blue|red|green|Black|Purple|Orange;
%let lintype=solid|shortdash|mediumdash|longdash|mediumdashshortdash|dashdashdot;
%let marktype=circle|triangle|triangledown|triangleleft|triangleright|circlefilled;
%let _mgp=1;

%do %while(%qscan(&gplist,&_mgp,|)^=%str());
  %let _gp&_mgp=%qscan(&gplist,&_mgp,|);
  %let _color&_mgp=%qscan(&color,&_mgp,|);
  %let _lintype&_mgp=%qscan(&lintype,&_mgp,|);
  %let _marktype&_mgp=%qscan(&marktype,&_mgp,|);
  %let _mgp=%eval(&_mgp+1);
%end;    
  %let _tmp=%eval(&_mgp-1);

上面代码控制的是下面圈起来的部分。实现根据组别,自动设置颜色、形状、线条类型等。

数据集转置

接下来,对数据集进行自动转置。最开始写原理的时候提到了,会将数据集进行转置。

/********************************************************************************************
*将数据集进行转置,一个受试者一列
*******************************************************************************************/

proc sort data=&inds.  out=have2(keep=&subjid. &group. &pktpt. &pkorres.) ;by &pktpt. &group. &subjid. ;quit;
/*数据集转置将*/
proc transpose data=have2 out=have3 prefix=C_;
by  &pktpt. &group.;
var &pkorres.;
id &subjid. ;
run;
/*获取循环次数:受试者个数、以及受试者名称并赋值给宏变量*/
proc sql noprint;
select count(distinct &subjid. ) into: _loop from &inds.;
select distinct &subjid.  into: name1-:name%left(&_loop.)  from &inds. order by &subjid.;
quit;

这部分会将数据集实现下图的转换。也就是一个受试者是一列。

一些计算及分组

写程序的时候,难免有一些考量,需要进行计算或者判断。比如,2*4图如果是50个受试者,一页放8张子图,所以一定有一页是放不满8个的,这个时候就需要根据是否有余数再设置一个Template(余数部分,也就是最后一页的受试者进行特殊处理)。

/********************************************************************************************
*根据受试者个数设置图像  (colunms*rows)  
*******************************************************************************************/
*一页图片个数;
%let  page_num_gif=%sysevalf(&colunms*&rows);
*计算(colunms*rows)页数;
%let _out_loop=%sysfunc(int(&_loop./&page_num_gif));
*计算余数(最后一页不够(colunms*rows));
%let _out_mod=%sysfunc(mod(&_loop.,&page_num_gif));
%let sum_width=%sysevalf(&width.*&colunms+&colunms-1);
%let sum_height=%sysevalf(&height.*&rows+&rows-1);
/********************************************************************************************
*根据 (colunms*rows) 将受试者划分组
*******************************************************************************************/
proc sort data=&inds.(keep=&subjid)  out=_codds  sortseq=linguistic(numeric_collation=on) nodupkey;by &subjid. ;quit;
data _codds;
  set _codds;
  _outgp=ceil(_n_/&page_num_gif.);
  _outmod=mod(_n_,&page_num_gif.);
  if _outmod=0 then _outmod=&page_num_gif.;
  _title=strip('Ytitle')||strip(_outmod)||strip('="')||STRIP("&subjid.")||strip('=')||strip(&subjid.)||strip('"');
  _dyn=strip('Yvar')||strip(_outmod)||strip('="C_')||strip(&subjid.)||strip('"');
run;
data _codds1  _codds2;
  set _codds;
  length finala finalb $4000.;
  by _outgp  notsorted;
  retain finala finalb;
  if first._outgp then do;
  finala=_title;
  finalb=_dyn;
  end;
  else do;
  finala=catx(" ",finala,_title);
  finalb=catx(" ",finalb,_dyn);
  end;
  %if &_out_loop. ne 0 %then %do;
  if _N_<=%eval(&_loop.-&_out_mod.) and last._outgp  then  output _codds1;
  else if last._outgp   then  output  _codds2;
  %end;
  %if &_out_loop.  eq 0 %then %do;
  if last._outgp   then output _codds2;
  %end;
run;

上面这段处理会生成2个数据集,_codds1(非余数部分的人)与_codds2(余数部分的人)。然后会将他们的值赋值给宏变量,用于后面的循环。

Template过程

template过程的代码,其实不多。主要是几个循环,循环的次数会根据前面的设置进行确定的。

ods graphics / width=&sum_width. cm height=&sum_height. cm  border=off;

%if &_out_loop. ne 0 %then %do;

  data _null_;
    set _codds1;
    call symput('_lista'||compress(put(_n_,best.)),strip(finala));
    call symput('_listb'||compress(put(_n_,best.)),strip(finalb));
  run;

  proc template;
    define statgraph drwa;
      begingraph/backgroundcolor=white border=false ;
          dynamic %do i=1 %to &page_num_gif. ;%sysfunc(compress(YVAR&i.)) %end;%do i=1 %to &page_num_gif. ;%sysfunc(compress(Ytitle&i.)) %end;; ;

  *循环实现 散点形状、线条类型、颜色; ;
  discreteattrmap name="temp1" / ignorecase=true;
  %do  i=1 %to &_tmp.;
  value "&&_gp&i." /markerattrs=GraphData1(color=&&_color&i.  symbol=&&_marktype&i.) lineattrs=GraphData1(color=&&_color&i. pattern=&&_lintype&i.);
  %end;
  enddiscreteattrmap;
  discreteattrvar attrvar=markers var=&group.   attrmap="temp1";
        layout lattice /columns=&colunms. rows=&rows. columngutter=1cm rowgutter=1cm     border=false   ;
      %do i=1 %to &page_num_gif.;
          layout OVERLAY/CYCLEATTRS=TRUE
            Xaxisopts=(gridDisplay=off LABEL="时间(h)"   LABELATTRS=( size=7pt)/*坐标轴标签属性修改*/ TICKVALUEATTRS=( size=7pt)/*坐标轴值属性修改*/   %if  %length(&xvalue.)  %then %do;linearopts=( TICKVALUELIST=(&xvalue. ) )  %end; ) 
            Yaxisopts=(gridDisplay=off LABEL="血药浓度(ng/mL)"   LABELATTRS=(size=7pt)/*坐标轴标签属性修改*/   TICKVALUEATTRS=( size=7pt)/*坐标轴值属性修改*/  %if  %length(&yvalue.)  %then %do;  linearopts=( TICKVALUELIST=(&Yvalue. ) )  %end;  );
            seriesplot x=&PKTPT y=YVAR&i. / group=markers  name="series&i." lineattrs=(thickness=2) display=(markers) ;
            discretelegend "series&i." /   valueattrs=(family="arial" size=7pt) title=Ytitle&i. titleattrs=GraphValueText(color=black size=8pt ) location=inside autoalign=(topright topleft) opaque=true  border=false across=1;
          endlayout;
      %end;
      endlayout;
    Endgraph; end;
  run;
%end;

%if &_out_mod. ne 0 %then %do;

  data _null_;
    set _codds2;
    call symput('_mlista'||compress(put(_n_,best.)),strip(finala));
    call symput('_mlistb'||compress(put(_n_,best.)),strip(finalb));
  run;

  proc template;
    define statgraph drwb;
      begingraph/backgroundcolor=white border=false ;
          dynamic %do i=1 %to &_out_mod. ;%sysfunc(compress(YVAR&i.)) %end;%do i=1 %to &_out_mod. ;%sysfunc(compress(Ytitle&i.)) %end;; 
  *循环实现 散点形状、线条类型、颜色; ;
  discreteattrmap name="temp1" / ignorecase=true;
  %do  i=1 %to &_tmp.;
  value "&&_gp&i." /markerattrs=GraphData1(color=&&_color&i.  symbol=&&_marktype&i.) lineattrs=GraphData1(color=&&_color&i. pattern=&&_lintype&i.);
  %end;
  enddiscreteattrmap;
  discreteattrvar attrvar=markers var=&group.   attrmap="temp1";
        layout lattice /columns=&colunms. rows=&rows. columngutter=1cm rowgutter=1cm     border=false   ;
      %do i=1 %to &_out_mod.;
          layout OVERLAY/CYCLEATTRS=TRUE
            Xaxisopts=(gridDisplay=off LABEL="时间(h)"   LABELATTRS=( size=7pt)/*坐标轴标签属性修改*/ TICKVALUEATTRS=( size=7pt)/*坐标轴值属性修改*/   %if  %length(&xvalue.)  %then %do;linearopts=( TICKVALUELIST=(&xvalue. ) )  %end; ) 
            Yaxisopts=(gridDisplay=off LABEL="血药浓度(ng/mL)"   LABELATTRS=(size=7pt)/*坐标轴标签属性修改*/   TICKVALUEATTRS=( size=7pt)/*坐标轴值属性修改*/  %if  %length(&yvalue.)  %then %do;  linearopts=( TICKVALUELIST=(&Yvalue. ) )  %end;  );
            seriesplot x=&PKTPT y=YVAR&i. / group=markers  name="series&i." lineattrs=(thickness=2) display=(markers) ;
            discretelegend "series&i." /   valueattrs=(family="arial" size=7pt) title=Ytitle&i. titleattrs=GraphValueText(color=black size=8pt ) location=inside autoalign=(topright topleft) opaque=true  border=false across=1;
          endlayout;
      %end;
      endlayout;
    Endgraph; end;
  run;
%end;

ods rtf file="&outpath.";
%if &_out_loop. ne 0 %then %do;
  %do i=1 %to  &_out_loop.;
  proc sgrender data=have3 template=drwa;
  dynamic &&_lista&i.;
  dynamic &&_listb&i.;
  run;
  %end;
%end;

%if &_out_mod. ne 0 %then %do;
proc sgrender data=have3 template=drwb;
dynamic &_mlista1;
dynamic &_mlistb1;
run;
%end;
ods rtf close;
proc delete data=have3 have2 _codds _codds1 _codds2;quit;
%mend;
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 SAS程序分享号号号 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档