2018年5月27日

修改PROC LIFETEST以ODS所繪製存活曲線圖

用ODS GRAPHICS和PROC LIFETEST繪製存活曲線圖 (Survival Curve)』從2010年以來已經有超過9千次的瀏覽量,雖然用ODS繪製Kaplan-Meier Survival Plot(後簡稱KM PLOT)非常方便,但缺點是如果需要修改圖中的樣式必須使用Graph Template Language(GTL)語法修改版模,不過GTL語法似乎真的有點難啊~~

還好SAS很佛心的提供一系列的Macro和Macro Variable可以方便使用者修改「部分」的圖形元素。但是這一系列的寫法有些複雜和不直覺,而且只能修改「Survival plot」而不支援「Failure plot」,如果你剛好需就讓我們一起學習看看吧!

先秀出經過修改後的KM PLOT。


《預設的KM PLOT》

首先,先繪製一張未修改的圖,程式如下:

ods select SurvivalPlot;
proc lifetest data=sashelp.BMT notable plots=survival( test atrisk(maxlen=13));
time T * Status(0);
strata Group;
run;

結果如下圖:

針對原始圖,打算修改下列幾個部分,而每一部份的程式都會重複上一部份的內容。

1.圖的標題和副標題

2.圖例(Legend)的位置

3.修改同質性檢定說明文字框(Homogeneity Test Inset)的文字和樣式

4.Y軸和X軸的刻度值(Tick Value)和軸標題

5.增加Y軸的參考線(Reference Line)及修改存活曲線的顏色、樣式及設限(Censor)符號

在開始修圖前,先說明如何匯入巨集程式及使用規則。


《程式載入》

程式可以從透過兩種方式取得,第一種直接到SAS官網然後搜尋「Customizing the Kaplan-Meier Survival Plot」點取連結下載。第二種為直接在程式中下載,然後執行巨集程式。第二種的語法如下:

/*匯入Macrot程式*/
data _null_;
%let url = //support.sas.com/documentation/onlinedoc/stat/ex_code/131;
infile "http:&url/templft.html" device=url;
file 'e:\temp\macros.tmp';
input;
if index(_infile_, '</pre>') then stop;
if pre then put _infile_;
if index(_infile_, '<pre>') then pre + 1;
run;
%inc 'e:\temp\macros.tmp' / nosource;

匯入Macro程式要修改的部分為「infile “XXXX”」後面的路徑和檔案名稱。


《程式架構》

%ProvideSurvivalMacros
  修改圖形所需巨集程式或巨集變項
%CompileSurvivalTemplates

   proc lifetest data ‥‥‥;
   ‥‥‥;
   run;

%ProvideSurvivalMacros
proc template;
    delete Stat.Lifetest.Graphics.ProductLimitSurvival / store=sasuser.templat;
    delete Stat.Lifetest.Graphics.ProductLimitSurvival2 / store=sasuser.templat;
run;

第一步:執行「%ProvideSurvivalMacros」到「%CompileSurvivalTemplate」之間要放入需要修改的巨集程式或巨集變項,需要注意的,這兩個語法後面『不需要分號』。

第二步:執行PROC LIFETEST。

第三步:再次執行%ProvideSurvivalMacros,及PROC TEMPLATE,可恢復預設的巨集程式及巨集變項,和刪除已經修改的版模,讓環境回到預設的狀況。


《1.修改標題和副標題》

修改標題需要用到4個巨集變項,包括
tatters可以設定字大小、字型和字體。
titletext0設定標題文字內容。
titletext1如圖的分層只有一層(或一條線)使用該巨集變項。
titletext2如分層為多層(或多條線)則使用此巨集變項。

其中tatters的用法比較特別,設定完成後要放到titletext1或titletext2的後面,別忘了「/」。

%ProvideSurvivalMacros
    /*設定字大小、粗體和字型*/
    %let tatters = textattrs=(size=14pt weight=bold family='arial');
    /* 修改title */
    %let TitleText0 = "Kaplan-Meier Plot";
    /*如果分層只有一層的title*/
     %let TitleText1 = &titletext0 " for " STRATUMID  / &tatters;
    /*分層有多層的title*/
     %let TitleText2 = &titletext0  / &tatters;
    /*省略副標題*/
     %let nTitles = 1;
%CompileSurvivalTemplates

proc lifetest data=sashelp.BMT notable plots=survival( test atrisk(maxlen=13));
     time T * Status(0);
     strata Group;
run;

%ProvideSurvivalMacros

/* 刪除已修改的templates. */
proc template;
     delete Stat.Lifetest.Graphics.ProductLimitSurvival / store=sasuser.templat;
     delete Stat.Lifetest.Graphics.ProductLimitSurvival2 / store=sasuser.templat;
run;

程式執行後的結果如下圖


《2.修改圖例(Legend)的位置》

修改圖例這裡使用了1個巨集變項。
LegendOpts其中autoalign可定圖例的位置,預設值為「outside」;across=1設定每一行只放一個圖例。

%ProvideSurvivalMacros
    /*設定字大小、粗體和字型*/
    %let tatters = textattrs=(size=14pt weight=bold family='arial');
   
/* 修改title */
    %let TitleText0 = "Kaplan-Meier Plot";
    /*如果分層只有一層的title*/
     %let TitleText1 = &titletext0 " for " STRATUMID  / &tatters;
   
/*分層有多層的title*/
     %let TitleText2 = &titletext0  / &tatters;
   
/*省略副標題*/
     %let nTitles = 1;
    /*修改圖例的位置*/
 
   %let LegendOpts = title=GROUPNAME location=inside across=1 autoalign=(TopRight);
%CompileSurvivalTemplates

proc lifetest data=sashelp.BMT notable plots=survival( test atrisk(maxlen=13));
     time T * Status(0);
     strata Group;
run;

%ProvideSurvivalMacros

/* 刪除已修改的templates. */
proc template;
     delete Stat.Lifetest.Graphics.ProductLimitSurvival / store=sasuser.templat;
     delete Stat.Lifetest.Graphics.ProductLimitSurvival2 / store=sasuser.templat;
run;

程式執行後的結果如下圖


《3.修改改變檢定資訊》

這裡使用了1個巨集變項和1組巨集程式
InsetdOpts其中設定檢定說明的位置autoalign可設定位置,border可設定要不要外框線。
pValue巨集程式,這用來改變檢定資訊中原本的logrank p改變為「Log Rank p」。

%ProvideSurvivalMacros
    /*設定字大小、粗體和字型*/
    %let tatters = textattrs=(size=14pt weight=bold family='arial');
   
/* 修改title */
    %let TitleText0 = "Kaplan-Meier Plot";
    /*如果分層只有一層的title*/
     %let TitleText1 = &titletext0 " for " STRATUMID  / &tatters;
   
/*分層有多層的title*/
     %let TitleText2 = &titletext0  / &tatters;
   
/*省略副標題*/
     %let nTitles = 1;
    /*修改圖例的位置*/
 
   %let LegendOpts = title=GROUPNAME location=inside across=1 autoalign=(TopRight);
   /*改變log rank test名稱,位置,去框*/
      %let InsetOpts = autoalign=(BottomLeft) border=false BackgroundColor=GraphWalls:Color Opaque=true;
     %macro pValue;
         if (PVALUE < .0001)
         entry "Log Rank p " eval (PUT(PVALUE, PVALUE6.4))     ;
         else
        entry "Log Rank p = " eval (PUT(PVALUE, PVALUE6.4)) ;
        endif;
     %mend;
%CompileSurvivalTemplates

proc lifetest data=sashelp.BMT notable plots=survival( test atrisk(maxlen=13));
     time T * Status(0);
     strata Group;
run;

%ProvideSurvivalMacros

/* 刪除已修改的templates. */
proc template;
     delete Stat.Lifetest.Graphics.ProductLimitSurvival / store=sasuser.templat;
     delete Stat.Lifetest.Graphics.ProductLimitSurvival2 / store=sasuser.templat;
run;

程式執行後的結果如下圖


《4.修改修改Y和X軸》

這裡使用了2個巨集變項
yOptions可改變Y軸的標籤、刻度的範圍和間距,設定間距可用tickvaluelist設定,但這裡只能一個一個把需要設定的刻度寫入。 labelattrs可修改Y軸標籤文字的字型、粗體和大小等。

xOptions用來改變X軸的設定,大致上與yOptions差不多,但除了沒有Label的功能。這裡將X軸的刻度換成以365天為間距,所以除了需要修改tickvaluelist,如需呈現Patients-at-Risk Table,建議配合X軸的間距,因此需在PROC LIFETEST後增加相對應的語法。

%ProvideSurvivalMacros
    /*設定字大小、粗體和字型*/
    %let tatters = textattrs=(size=14pt weight=bold family='arial');
   
/* 修改title */
    %let TitleText0 = "Kaplan-Meier Plot";
    /*如果分層只有一層的title*/
     %let TitleText1 = &titletext0 " for " STRATUMID  / &tatters;
   
/*分層有多層的title*/
     %let TitleText2 = &titletext0  / &tatters;
   
/*省略副標題*/
     %let nTitles = 1;
    /*修改圖例的位置*/
 
   %let LegendOpts = title=GROUPNAME location=inside across=1 autoalign=(TopRight);
   /*改變log rank test名稱,位置,去框*/
      %let InsetOpts = autoalign=(BottomLeft) border=false BackgroundColor=GraphWalls:Color Opaque=true;
     %macro pValue;
         if (PVALUE < .0001)
         entry "Log Rank p " eval (PUT(PVALUE, PVALUE6.4))     ;
         else
        entry "Log Rank p = " eval (PUT(PVALUE, PVALUE6.4)) ;
        endif;
     %mend;

   /*修改Y軸*/
    %let yOptions = label="Survival"  labelattrs=(size=12pt weight=bold family='arial')
                linearopts=(viewmin=0.1 viewmax=1 tickvaluelist=(0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0));
   /*修改X軸*/
    %let xOptions = shortlabel=XNAME offsetmin=.05 labelattrs=(size=12pt weight=bold family='arial')
               linearopts=(
                       viewmax=MAXTIME tickvaluelist=(0 365 730 1095 1460 1825 2190 2555)
                       tickvaluefitpolicy=XTICKVALFITPOL
                              );
%CompileSurvivalTemplates

proc lifetest data=sashelp.BMT notable plots=survival( test atrisk(maxlen=13) atrisk=0 to 2700 by 365);
     time T * Status(0);
     strata Group;
run;

%ProvideSurvivalMacros

/* 刪除已修改的templates. */
proc template;
     delete Stat.Lifetest.Graphics.ProductLimitSurvival / store=sasuser.templat;
     delete Stat.Lifetest.Graphics.ProductLimitSurvival2 / store=sasuser.templat;
run;

程式執行後的結果如下圖


《5.增加參考線和修改修改LINE的風格 包括群組的顏色,線的樣式、Censro的樣式》

這裡使用了4個巨集變項和1個巨集程式。
StmtsTop巨集程式用來繪製參考線。
GraphOpts則用來改群組的顏色、修改線的樣式。
StepOpts修改線的粗細。
Censored修改censor的樣式,如於圖上的標籤圖形(這裡改成圓點)和大小。
Censorstr修改censort的文字標籤。

%ProvideSurvivalMacros
    /*設定字大小、粗體和字型*/
    %let tatters = textattrs=(size=14pt weight=bold family='arial');
   
/* 修改title */
    %let TitleText0 = "Kaplan-Meier Plot";
    /*如果分層只有一層的title*/
     %let TitleText1 = &titletext0 " for " STRATUMID  / &tatters;
   
/*分層有多層的title*/
     %let TitleText2 = &titletext0  / &tatters;
   
/*省略副標題*/
     %let nTitles = 1;
    /*修改圖例的位置*/
 
   %let LegendOpts = title=GROUPNAME location=inside across=1 autoalign=(TopRight);
   /*改變log rank test名稱,位置,去框*/
      %let InsetOpts = autoalign=(BottomLeft) border=false BackgroundColor=GraphWalls:Color Opaque=true;
     %macro pValue;
         if (PVALUE < .0001)
         entry "Log Rank p " eval (PUT(PVALUE, PVALUE6.4))     ;
         else
        entry "Log Rank p = " eval (PUT(PVALUE, PVALUE6.4)) ;
 
      endif;
     %mend;
   /*修改Y軸*/
    %let yOptions = label="Survival"  labelattrs=(size=12pt weight=bold family='arial')
                linearopts=(viewmin=0.1 viewmax=1 tickvaluelist=(0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0));
   /*修改X軸*/
    %let xOptions = shortlabel=XNAME offsetmin=.05  labelattrs=(size=12pt weight=bold family='arial')
               linearopts=(
                       viewmax=MAXTIME tickvaluelist=(0 365 730 1095 1460 1825 2190 2555)
                       tickvaluefitpolicy=XTICKVALFITPOL
                              );
   /*增加 參考線*/
    %macro StmtsTop;
       referenceline y=0.5;
      referenceline x=730;
    %mend;
    /*修改群組的顏色、修改線的樣式*/
    %let GraphOpts = DataContrastColors=(green red blue) DataColors=(green red blue)
                                 ATTRPRIORITY=NONE DataLinePatterns=(ShortDash MediumDash LongDash);
   /*修改線的粗細*/
    %let StepOpts = lineattrs=(thickness=2.5);
   /*修改Censor的樣式*/
    %let Censored = markerattrs=(symbol=circlefilled size=5px);
    %let Censorstr = "(*ESC*){Unicode '25cf'x} Censored" ;

%CompileSurvivalTemplates

proc lifetest data=sashelp.BMT notable plots=survival( test atrisk(maxlen=13) atrisk=0 to 2700 by 365);
     time T * Status(0);
     strata Group;
run;

%ProvideSurvivalMacros

/* 刪除已修改的templates. */
proc template;
     delete Stat.Lifetest.Graphics.ProductLimitSurvival / store=sasuser.templat;
     delete Stat.Lifetest.Graphics.ProductLimitSurvival2 / store=sasuser.templat;
run;

程式執行後的結果如下圖


希望這一篇能對大家有幫助,我沒有對所有指令做說明,其中一個原因是我對GTL的語法完全不懂,所以僅能對目前理解的部分與大家分享。

這一篇主要是參考「SAS/STAT® 14.1 User’s Guide Customizing the Kaplan-Meier Survival Plot」,有興趣的人可以自行閱讀。

3 則留言:

  1. 你好,想請問要如何改變圖形P-VALUE的大小。
    我試過從%let InsetOpts = autoalign=(BottomLeft) border=false BackgroundColor=GraphWalls:Color Opaque=true;去改,都沒辦法。

    回覆刪除
  2. 您好,想請教您,若是想使用FAILURE的方法並針對X、Y軸進行調整,該如何修改語法呢?謝謝您!

    回覆刪除