163:泳道图(swimmer plot)---(一)

swimmer plot:游泳图;泳道图,也叫作Napoleon plot.(拿破仑图?拿破仑做错了什么了?他不就拿了一个破轮子)

泳道图因为看起来像一条条泳道,就像下面的图形一样。因此得名。泳道图最常用的用途就是用来展示肿瘤研究中的评估结果,但是其实泳道图还能用来展示治疗/观察周期、事件发生、事件持续时间或受试者状态。下面这张图它展示的就不是肿瘤总体评估的数据,而是不同剂量组给药时长的数据。


但是一般来说,我们做项目也不会要你画给药的泳道图,大多数都是肿瘤总体评估的泳道图,所以,我还是以肿瘤评估数据举例怎么画泳道图。

介绍下泳道图各个部位代表的意思,以一张经典的泳道图为例(有些会有些许差异,具体还是按照shell画吧)。然后总体评估(Overall Response我在后面都用OR代替,少打点字

1)泳道图的X轴代表试验进行的duration,至于刻度单位是weeks还是months,可以参考shell,但是我觉得如果试验只进行了很短的一段的时间,用monhths作为X轴的单位的话,泳道会很短,不美观,用WEEKS稍微合理一点,然后一般也都是从0开始,不像图中的还有负坐标轴。

2)泳道图的Y轴是具体的受试者编号,也就是subjid,一个subjid一条泳道。

3)接着就是图里面的这些标志(三角形、方形、圆形等),大家可以看右下角的标签,不同的形状代表受试者在对应的周期,肿瘤总体评估结果是什么?比如我们看第一条泳道,这个受试者在第6-7个月的时候,肿瘤总体评估结果是CR,用红色的三角形表示。

需要注意的是,这张图三角形的标签是CR start,但是我目前的做的项目只要标明这个点是CR/PR/PD/SD就行了,不用标明start/end;所以泳道图有些细节还是需要和统计师确认了,比如有的还要求在OR和OR之间用横线表示,像下面这样,但是发现下面这张图只求CR和PR,然后求CR和PR的持续时间,也就是图上三角形和圆形之间的横线。

今天只简单地展示各个周期的OR,不展示持续时间,看下以后再讲(其实我不会,哈哈),然后这次只用GTL,不用SGPLOT,因为SGPLOT我也不会,哈哈哈。

4)然后泳道的长度代表什么?泳道的终点代表什么?一般来说,泳道的起点都是首次给药日期,然后泳道的终点要跟统计师确认一下,因为终点可能为治疗结束日期(EOT),也可能为研究结束日期(EOS),而且如果统计师看EOS,但是医学却要看EOT,所以最好确认一下,先按统计师的来,如果统计和医学不一致,开会讨论一下呗。

如果受试者既没有EOT,也没有EOS或者Death,那么这个subjid就是continued,一般用箭头表示,像下面这样:

那么这时候泳道的长度就是RFPENDTC或者受试者已知的最大存活时间。

5)然后你们看上面几张图每条泳道的颜色都不一样,这是因为把不同组别的受试者都放到一张图里面,所以X轴下面还加了一个标签表明不同颜色代表不同组别(或治疗阶段),如果一个组别有很多受试者,我们就可以分组别出图,比如3组就3张图。然后泳道的颜色就一样。

泳道图的重点就上面几个点,下面我们开始画图了:

先创建数据:一般一项肿瘤试验,会在基线测量靶病灶、非靶病灶的信息,以便和给药后的肿瘤状态进行比较,进而得出总体评估疗效,一般可能是4周一次,6周一次,这个看方案。然后总体评估数据一般做到ADRS里面,一般是直接拿CRF上收集的总体评估数据画图,但是我也遇到过医学想用confimed后的结果拿去画图,这个最好确认下。

然后我从如何创建画图的数据集开始讲起,手把手教,假设你的ADRS已经做好了。如下(代码我看下直接上传到简书吧,简书好像可以markdown

上面的就像我们已经生成的ADaM数据集之ADRS,接着我们对数据集进行处理,生成画图需要的变量。生成的变量作用已经注释出来了,其中我们是根据是否EOT判断continued。

数据已经准备好了,接着我们就开始画图了

data adrs;

subjid="S001";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-15";RSDTC="2022-01-10";avisit="肿瘤评估周期1";avalc="SD";rfpendtc="2022-06-10";output;

subjid="S001";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-15";RSDTC="2022-02-15";avisit="肿瘤评估周期2";avalc="PR";rfpendtc="2022-06-10";output;

subjid="S001";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-15";RSDTC="2022-03-15";avisit="肿瘤评估周期3";avalc="SD";rfpendtc="2022-06-10";output;

subjid="S001";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-15";RSDTC="2022-04-18";avisit="肿瘤评估周期4";avalc="SD";rfpendtc="2022-06-10";output;

subjid="S001";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-15";RSDTC="2022-05-10";avisit="肿瘤评估周期6";avalc="CR";rfpendtc="2022-06-10";output;

subjid="S002";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-10";RSDTC="2022-01-10";avisit="肿瘤评估周期1";avalc="SD";rfpendtc="2022-05-10";output;

subjid="S002";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-10";RSDTC="2022-02-15";avisit="肿瘤评估周期2";avalc="SD";rfpendtc="2022-05-10";output;

subjid="S002";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-10";RSDTC="2022-03-15";avisit="肿瘤评估周期3";avalc="PD";rfpendtc="2022-05-10";output;

subjid="S002";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-10";RSDTC="2022-04-18";avisit="肿瘤评估周期4";avalc="PD";rfpendtc="2022-05-10";output;

subjid="S003";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-01";RSDTC="2022-01-01";avisit="肿瘤评估周期1";avalc="CR";rfpendtc="2022-09-10";output;

subjid="S003";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-01";RSDTC="2022-02-15";avisit="肿瘤评估周期2";avalc="PR";rfpendtc="2022-09-10";output;

subjid="S003";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-01";RSDTC="2022-03-15";avisit="肿瘤评估周期3";avalc="PR";rfpendtc="2022-09-10";output;

subjid="S003";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-01";RSDTC="2022-04-18";avisit="肿瘤评估周期4";avalc="PR";rfpendtc="2022-09-10";output;

subjid="S003";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-01";RSDTC="2022-05-15";avisit="肿瘤评估周期5";avalc="SD";rfpendtc="2022-09-10";output;

subjid="S003";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-01";RSDTC="2022-06-18";avisit="肿瘤评估周期6";avalc="SD";rfpendtc="2022-09-10";output;

subjid="S003";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-01";RSDTC="2022-07-15";avisit="肿瘤评估周期7";avalc="PD";rfpendtc="2022-09-10";output;

subjid="S003";TRTA="A组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-01";RSDTC="2022-08-18";avisit="肿瘤评估周期8";avalc="PD";rfpendtc="2022-09-10";output;

subjid="S004";TRTA="B组";PARAMCD="OVRLRESP";TRTSDTC="2022-06-01";RSDTC="2022-07-15";avisit="肿瘤评估周期1";avalc="PD";dthdtc="2022-10-20";rfpendtc="2022-10-20";output;

subjid="S004";TRTA="B组";PARAMCD="OVRLRESP";TRTSDTC="2022-06-01";RSDTC="2022-08-18";avisit="肿瘤评估周期2";avalc="PD";dthdtc="2022-10-20";rfpendtc="2022-10-20";output;

subjid="S005";TRTA="B组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-21";RSDTC="2022-01-19";avisit="肿瘤评估周期1";avalc="CR";EOTDTC="2022-05-01";rfpendtc="2022-05-21";output;

subjid="S005";TRTA="B组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-21";RSDTC="2022-02-21";avisit="肿瘤评估周期2";avalc="PR";EOTDTC="2022-05-01";rfpendtc="2022-05-21";output;

subjid="S005";TRTA="B组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-21";RSDTC="2022-03-22";avisit="肿瘤评估周期3";avalc="PR";EOTDTC="2022-05-01";rfpendtc="2022-05-21";output;

subjid="S005";TRTA="B组";PARAMCD="OVRLRESP";TRTSDTC="2021-12-21";RSDTC="2022-04-18";avisit="肿瘤评估周期4";avalc="SD";EOTDTC="2022-05-01";rfpendtc="2022-05-21";output;

subjid="S006";TRTA="B组";PARAMCD="OVRLRESP";TRTSDTC="2022-01-01";RSDTC="2022-01-29";avisit="肿瘤评估周期1";avalc="CR";EOTDTC="2022-06-01";dthdtc="2022-11-20";rfpendtc="2022-11-20";output;

subjid="S006";TRTA="B组";PARAMCD="OVRLRESP";TRTSDTC="2022-01-01";RSDTC="2022-02-21";avisit="肿瘤评估周期2";avalc="PR";EOTDTC="2022-06-01";dthdtc="2022-11-20";rfpendtc="2022-11-20";output;

subjid="S006";TRTA="B组";PARAMCD="OVRLRESP";TRTSDTC="2022-01-01";RSDTC="2022-03-25";avisit="肿瘤评估周期3";avalc="PR";EOTDTC="2022-06-01";dthdtc="2022-11-20";rfpendtc="2022-11-20";output;

subjid="S006";TRTA="B组";PARAMCD="OVRLRESP";TRTSDTC="2022-01-01";RSDTC="2022-04-28";avisit="肿瘤评估周期4";avalc="SD";EOTDTC="2022-06-01";dthdtc="2022-11-20";rfpendtc="2022-11-20";output;

RUN;

data adrs2;

set adrs;

resp=avalc;

id=subjid;

*这种做法是画多个散点图,将散点分好几种情况;

/* if avalc="CR" then CRDUR=round((input(RSDTC,YYMMDD10.)-input(TRTSDTC,YYMMDD10.))/7,0.1);*/

/* if avalc="PR" then PRDUR=round((input(RSDTC,YYMMDD10.)-input(TRTSDTC,YYMMDD10.))/7,0.1);*/

/* if avalc="SD" then SDDUR=round((input(RSDTC,YYMMDD10.)-input(TRTSDTC,YYMMDD10.))/7,0.1);*/

/* if avalc="PD" then PDDUR=round((input(RSDTC,YYMMDD10.)-input(TRTSDTC,YYMMDD10.))/7,0.1);*/

if RSDTC^="" then resp_dur=round((input(RSDTC,YYMMDD10.)-input(TRTSDTC,YYMMDD10.))/7,0.1); *每个OR据首次给药的间期;

if EOTDTC="" then ONGODUR=round((input(rfpendtc,YYMMDD10.)-input(TRTSDTC,YYMMDD10.))/7,0.1);  *continued标帜;

if DTHDTC^="" then DTHDUR=round((input(DTHDTC,YYMMDD10.)-input(TRTSDTC,YYMMDD10.))/7,0.1); *死亡标志;

if EOTDTC^="" then totdur=round((input(EOTDTC,YYMMDD10.)-input(TRTSDTC,YYMMDD10.))/7,0.1); *泳道的长度;

else if EOTDTC="" and rfpendtc^="" then totdur=round((input(rfpendtc,YYMMDD10.)-input(TRTSDTC,YYMMDD10.))/7,0.1); *泳道的长度;

proc sort;by trta totdur;

run;

ods listing close;

ods rtf file = "&project\graph\swimplot.rtf" ;

proc template;

define statgraph swimmplot;

begingraph/;

discreteattrmap name='restype';

value 'SD' / markerattrs=(symbol=squarefilled color=blue size=10);

value 'PR' / markerattrs=(symbol=squarefilled color=yellow size=10);

value 'CR' / markerattrs=(symbol=squarefilled color=green size=10);

value 'PD' / markerattrs=(symbol=squarefilled color=red size=10);

enddiscreteattrmap;

discreteattrvar attrvar=resp_map var=resp attrmap='restype';

entrytitle "Swim Plot of Overall Response ";

layout overlay/ walldisplay=(fill)

xaxisopts=(label='Duration in Weeks' offsetmin=0 linearopts=(tickvaluesequence=(start=0 end=50 increment=5) viewmin=0 viewmax=60))

yaxisopts=(label='Subject' offsetmax=0.25);

barchart category=id response=totdur/ group=trta  orient=horizontal name='bar' stat=mean barwidth=0.2  fillattrs= (transparency=0.2) INCLUDEMISSINGGROUP=FALSE;

scatterplot X=resp_dur Y=id/group=resp_map name="res";

scatterplot x=ONGODUR y=id / markerattrs=(symbol=trianglerightfilled color=orange size=8) name='ongo' legendlabel="Continued";

scatterplot x=DTHDUR y=id / markerattrs=(symbol=squarefilled color=black size=8) name='dth' legendlabel="Death";

discreteLegend  "bar" "res" "ongo" "dth"/across=1 autoalign=(topright) location=inside valueattrs=(size=8pt ) border=false;

endlayout;

endgraph;

end;

run;

proc sgrender data=adrs2 template=swimmplot;

run;

ods rtf close;

ods listing;


靠,MARKDOWN在哪里设置,算了,我先复制成文本吧

下面我们简单介绍一些关键参数,后面有时间再慢慢介绍一些选项

①:discreteattrmap:定义一组可与用户定义的值集关联的图形属性。

也就是我们看上面,如果Avalc,它的值是CR/PR/SD/PD,那么它它们分别就由不同的形状和颜色,这是我们告诉SAS我们要定义成这样,如果图中用到这些值,那么你就给我展示成我设定的样式

②:discreteattrvar:在用户定义的离散属性映射和输入数据列之间创建命名关联。

2.1ATTRVAR:为属性映射和输入列之间的关联指定SAS名称。

2.2VAR:指定要在运行时与属性映射关联的输入数据列。我们这里用的就是数据集里面的RESP变量

2.3ATTRVAR:为属性映射和输入列之间的关联指定SAS名称。

这几个看起来有点抽象,但是你们看例子就明白了,如果我只用

discreteattrvar attrvar=resp_map var=resp attrmap='restype';

把discreteattrmap注释掉就这一段可以吗?


没问题,SAS也不会报错,然后你们看输出

这时候那么OR都变成SAS自己默认的样式,所以说discreteattrmap和discreteattrvar联用可以自己定义输出值的样式。

③:entrytitle :SAS明明说The maximum length for the title text is 512 characters,但是我的标题却被截断了,可能是因为我的图的宽度的问题,这个我后面看下是什么原因。

接下来就是定义X轴Y轴的标签等属性,这个简答就不说了。

其实泳道图就是条形图和散点图的结合,所以我们画图就用barchart和scatterplot两个选项就够了。至于barchart和scatterplot我们后面有时间单独讲讲。

Plus:总说有时间有时间,什么叫做有时间,渣男,一次次这样欺骗自己和别人,有意思吗?

③:barchart:category用的就是subjid,response就是泳道的长度,也即是我们上面求得totdur变量。同时注意我用了一个stat=mean,这个选项的作用是相当于让SAS展示成它原来的长度,因为用了response=选项后,stat的默认选项是sum,也就是把

response=变量的值都加起来。所以我们可以看下面的比较,比如S004,两个totdur相加是40多,但是实际上泳道的长度只有20多,


未加stat=mean


加stat=mean

所以这是需要注意的一个点,同时实际画图的时候需要对条形图的宽度样式那些进行一些调整,这里就不讲了。

接着就是散点图,我们需要分OR评估的散点和Continued的散点分别出图,因为Continued的散点是需要我们根据EOT自己判断的,X轴的值就是我们上面的各个OR  DUR和totdur,Y轴的值还是subjid。

后面我还自己加上了判断是否死亡的标帜,做法跟continued一样的。


大致的泳道图就长这样了,然后可以的话,我们可以提前对数据集排个序,因为现在的图泳道不是很整齐,我们可以按照泳道长度从长到短,从上到下输出,像下面这样:

然后我们没有区分组别,就像文章一开始讲的,你可以根据有多少个组别分多张图画,但是如果我们想在一张图里面都展示出来呢?没问题,我加个班:

数据集里面我们加上TRTA变量,

然后在GTL里面加上group=trta就可以了,这时候用的是SAS默认的颜色,但是我们也可以用discreteattrmap自己定义,这个你们自己去尝试就行了。

输出如下:按照组别和TOTDUR排序


如果文中有哪些错误欢迎指正

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

推荐阅读更多精彩内容