Customizing the Kaplan-Meier Survival Plot

Modifying the Data Object

The second way to approach this problem requires you to modify the data object and use the ODS document. The first things you must do are to open an ODS document, save the results of the PROC LIFETEST analysis, save the data object that underlies the graph into a SAS data set, and close the ODS document. The following code illustrates:

ods document name=MyDoc (write);
proc lifetest data=sashelp.BMT plots=survival(cb=hw atrisk(outside maxlen=13));
   ods output survivalplot=sp;
   time T * Status(0);
   strata Group;
run;
ods document close;

The ODS document contains all the tables, graphs, titles, notes, and other components of the output. The following step lists the contents of the ODS document:

proc document name=MyDoc;
   list / levels=all;
quit;

The contents are displayed in Figure 42.

Figure 42: Contents of the ODS Document

Listing of: \Work.Mydoc\
Order by: Insertion
Number of levels: All
Obs Path Type
1 \Lifetest#1 Dir
2 \Lifetest#1\Stratum1#1 Dir
3 \Lifetest#1\Stratum1#1\ProductLimitEstimates#1 Table
4 \Lifetest#1\Stratum1#1\TimeSummary#1 Dir
5 \Lifetest#1\Stratum1#1\TimeSummary#1\SummaryNote#1 Note
6 \Lifetest#1\Stratum1#1\TimeSummary#1\Quartiles#1 Table
7 \Lifetest#1\Stratum1#1\TimeSummary#1\Means#1 Table
8 \Lifetest#1\Stratum2#1 Dir
9 \Lifetest#1\Stratum2#1\ProductLimitEstimates#1 Table
10 \Lifetest#1\Stratum2#1\TimeSummary#1 Dir
11 \Lifetest#1\Stratum2#1\TimeSummary#1\SummaryNote#1 Note
12 \Lifetest#1\Stratum2#1\TimeSummary#1\Quartiles#1 Table
13 \Lifetest#1\Stratum2#1\TimeSummary#1\Means#1 Table
14 \Lifetest#1\Stratum3#1 Dir
15 \Lifetest#1\Stratum3#1\ProductLimitEstimates#1 Table
16 \Lifetest#1\Stratum3#1\TimeSummary#1 Dir
17 \Lifetest#1\Stratum3#1\TimeSummary#1\SummaryNote#1 Note
18 \Lifetest#1\Stratum3#1\TimeSummary#1\Quartiles#1 Table
19 \Lifetest#1\Stratum3#1\TimeSummary#1\Means#1 Table
20 \Lifetest#1\CensoredSummary#1 Table
21 \Lifetest#1\StrataHomogeneity#1 Dir
22 \Lifetest#1\StrataHomogeneity#1\HomogeneityNote#1 Note
23 \Lifetest#1\StrataHomogeneity#1\HomStats#1 Table
24 \Lifetest#1\StrataHomogeneity#1\LogrankHomCov#1 Table
25 \Lifetest#1\StrataHomogeneity#1\WilcoxonHomCov#1 Table
26 \Lifetest#1\StrataHomogeneity#1\HomTests#1 Table
27 \Lifetest#1\SurvivalPlot#1 Graph


In the following step, you copy and paste the ODS document path for the survival plot into the OBDYNAM statement to create an ODS output data set that contains all the dynamic variables for the survival plot:

proc document name=MyDoc;
   ods output dynamics=dynamics;
   obdynam \Lifetest#1\SurvivalPlot#1;
quit;

The dynamic variables and their values are displayed in Figure 43.[24]

Figure 43: Dynamic Variables

Dynamics for: \Work.Mydoc\Lifetest#1\SurvivalPlot#1
Name Value Type Namespace
NSTRATA 3 Data  
PLOTHW 1 Data  
PLOTEP 0 Data  
PLOTCL 0 Data  
PLOTCENSORED 1 Data  
Transparency 0.7 Data  
PLOTTEST 0 Data  
_BYTITLE_   Data  
_BYLINE_   Data  
_BYFOOTNOTE_   Data  
METHOD Product-Limit Data  
ROWWEIGHTS PREFERRED Data  
XNAME T Data  
LABELHW 95% Hall-Wellner Band Data  
SECONDTITLE With Number of Subjects at Risk and 95% Hall-Wellner Bands Data  
GROUPNAME Disease Group Data  
___NOBS___ 156 Data  
___NOBS___ 156 Column HW_UCL
___NOBS___ 156 Column HW_LCL
___NOBS___ 156 Column Time
___NOBS___ 156 Column Survival
___NOBS___ 156 Column AtRisk
___NOBS___ 156 Column Event
___NOBS___ 156 Column Censored
___NOBS___ 156 Column tAtRisk
___NOBS___ 156 Column Stratum
CLASSATRISK Stratum Column Stratum
___NOBS___ 156 Column StratumNum


You can use a DATA step as follows to generate a PROC SGRENDER statement; specify the ODS output data set, the template, and the format; and specify the names and values of all the dynamic variables:

data _null_;
   set dynamics(where=(label1 ne '___NOBS___')) end=eof;
   if _n_ = 1 then
      call execute('proc sgrender data=sp
                    template=Stat.Lifetest.Graphics.ProductLimitSurvival2;
                    format stratum $dfmt.;
                    dynamic');
   if cvalue1 ne ' ' then
      call execute(catx(' ', label1, '=',
                   ifc(n(nvalue1), cvalue1, quote(trim(cvalue1)))));
   if eof then call execute('; run;');
run;

This DATA step generates and executes a PROC SGRENDER step that creates the graph. The DATA step uses a series of CALL EXECUTE statements to populate the list of dynamic variables. The DATA step generates and submits to SAS the following code (which has been reformatted for display here):

proc sgrender data=sp
   template=Stat.Lifetest.Graphics.ProductLimitSurvival2;
   format stratum $dfmt.;
   dynamic
      NSTRATA = 3
      PLOTHW = 1
      PLOTEP = 0
      PLOTCL = 0
      PLOTCENSORED = 1
      Transparency = 0.7
      PLOTTEST = 0
      METHOD = "Product-Limit"
      ROWWEIGHTS = "PREFERRED"
      XNAME = "T"
      LABELHW = "95% Hall-Wellner Band"
      SECONDTITLE = "With Number of Subjects at Risk and 95% Hall-Wellner Bands"
      GROUPNAME = "Disease Group"
      CLASSATRISK = "Stratum";
run;

The survival plot, which now contains the long dashes, is displayed in Figure 44.

Figure 44: Unicode in the Legend

Unicode in the Legend


This example shows that you can save the data object and dynamic variables into SAS data sets. Then you can apply a format to the Stratum variable as you create the graph from those data sets. The advantage of this approach is that it provides full flexibility. For example, you can use it with multiple strata variables.



[24] Some dynamic variables have numeric values, and some have character values. The ODS output data set (not shown) stores the character and formatted numeric values in the variable cValue1 and the unformatted numeric values in nValue1.

Last updated: March 08, 2022