BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
antor82
Obsidian | Level 7

Hi All

 

I'm reproducing a Kaplan-Meier stepplot in layout lattice.

 

Here is the result.

 

 

Unknown.png

 

 

I'm wondering why in the right graph, the axis table with patients at risk is located a bit higher than the corresponding table on the left.

 

I attach the code I used, if of any help.

 

proc template;
	define statgraph Fig_2_KM;
		begingraph / collation=binary designheight=480 designwidth=1280;
		layout lattice / rows=1 columns=2 rowgutter=10 columngutter=10 ;

		/*Unmatched population*/
		legenditem type=text name="log" / label="Logrank p=0.0007" 
			lineattrs=(color=black);
		layout overlay / xaxisopts=(Label="Years of Follow-up" 
			LabelAttrs=(Weight=normal) type=linear) y2axisopts=(labelFitPolicy=Split) 
			yaxisopts=(Label=" " labelFitPolicy=Split 
			LabelAttrs=(Weight=normal) type=linear linearopts=(viewmin=0) ) 
			y2axisopts=(labelFitPolicy=Split);
		entry "in the Unmatched Population" / valign=top location=outside 
			textattrs=(weight=bold);
		entry "Product-Limit Survival Estimates"/ valign=top location=outside 
			textattrs=(weight=bold size=12);
		StepPlot X=Time Y=Survival / primary=true Group=Stratum Lineattrs=(Pattern=1 
			Thickness=1) LegendLabel="Survival Probability" NAME="STEP";
		scatterplot x=time y=censored / markerattrs=(symbol=plus) name='c';
		scatterplot x=time y=censored / markerattrs=(symbol=plus) GROUP=stratum;
		discretelegend 'c' 'log' / location=inside halign=right valign=top 
			order=columnmajor valueattrs=(size=10) border=false;
		drawtext textattrs=(size=10) 'Survival Probability' / x=-8 y=60 anchor=bottom 
                   xspace=wallpercent yspace=wallpercent rotate=90 width=50;	

		/*--Subjects at risk-Unmatched--*/
		InnerMargin / align=bottom opaque=true;
		AxisTable Value=AtRisk X=tAtRisk / labelPosition=min Class=Stratum
			LabelAttrs=(Weight=normal) ValueAttrs=(Size=10) colorGroup=Stratum
			Display=(Label Values) title="Subjects at risk" titleattrs=(size=10);
		EndInnerMargin;
		DiscreteLegend "STEP";
		endlayout;

		/*Matched population*/
		legenditem type=text name="log2" / label="Logrank p=0.9417" 
			lineattrs=(color=black);
		layout overlay / xaxisopts=(Label="Years of Follow-up" 
			LabelAttrs=(Weight=normal) type=linear) y2axisopts=(labelFitPolicy=Split) 
			yaxisopts=(Label=" " labelFitPolicy=Split 
			LabelAttrs=(Weight=normal) type=linear linearopts=(viewmin=0) ) 
			y2axisopts=(labelFitPolicy=Split);
		entry "in the Matched Population" / valign=top location=outside 
			textattrs=(weight=bold);
		entry "Product-Limit Survival Estimates"/ valign=top location=outside 
			textattrs=(weight=bold size=12);
		StepPlot X=Time2 Y=Survival2 / primary=true group=Stratum2
			Lineattrs=(Pattern=1 Thickness=1) LegendLabel="Survival Probability" 
			NAME="STEP2";
		scatterplot x=time2 y=censored2 / markerattrs=(symbol=plus) name='c2' 
			legendlabel="Censored";
		scatterplot x=time2 y=censored2 / markerattrs=(symbol=plus) GROUP=stratum2;
		discretelegend 'c2' 'log2' / location=inside halign=right valign=top  
			order=columnmajor valueattrs=(size=10) border=false;
		drawtext textattrs=(size=10) 'Survival Probability' / x=-8 y=60 anchor=bottom 
                   xspace=wallpercent yspace=wallpercent rotate=90 width=50;	
		/*--Subjects at risk-Unmatched--*/
		InnerMargin / align=bottom opaque=true;
		AxisTable Value=AtRisk2 X=tAtRisk2 / labelPosition=min  class=Stratum2
			LabelAttrs=(Weight=normal) ValueAttrs=(Size=10) colorGroup=Stratum2
			Display=(Label Values) title="Subjects at risk" titleattrs=(size=10);
		EndInnerMargin;
		DiscreteLegend "STEP";
		endlayout;
		endlayout;
		endgraph;
	end;
run;

Thanks in advance

 

 

Sincerely

 

A

1 ACCEPTED SOLUTION

Accepted Solutions
JeffMeyers
Barite | Level 11

Hello,

   I was able to fix this by adding the INCLUDEMISSINGCLASS=FALSE option to the AXISTABLE statement.

 

SGRender.png

 

Also putting out a plug for my macro NEWSURV that can make these kind of lattice of survival plots for you:

https://communities.sas.com/t5/SAS-Communities-Library/Kaplan-Meier-Survival-Plotting-Macro-NEWSURV/...

View solution in original post

8 REPLIES 8
Rick_SAS
SAS Super FREQ

Can you provide the data?

Without the data, I can't test my idea, but it's possible that the data ranges are slightly different. Try adding 

columndatarange=union rowdatarange=union

to the LAYOUT LATTICE options.

 

 

antor82
Obsidian | Level 7
Sorry…. It doesn’t work….

However, if I exclude the class=Stratum2 from the code, I obviously obtain one single line with patients at risk BUT on the same level as the red one on the graph of the left.
Rick_SAS
SAS Super FREQ

Without the data, this could take all day. Try this...try that.

 

The question in my mind is whether it is a data issue (the data are responsible for the difference) or whether it is a template issue (like a font difference that we aren't noticing).  To determine whether the data are responsible, try this:

1. Temporarily modify the template so that the second plot uses Time, Survival, and Censored variables instead of  Time2, Survival2, and Censored2. Any change?

2. If the problem still persists, put back Time2, Survival2, and Censored2, but now temporarily modify the template to use AtRisk, tAtRisk, and Stratum in the second AXISTABLE statement? Any change?

3. You can combine 1 and 2 so that you have identical plots on the left and the right. Hopefully, they will be identical in this case.

4. Notice that the first axistable has a three-digit number (147) whereas the second axistable does not. Play around with various alignment, justification, and formatting options to see whether that is the issue. (#2 should reveal whether it is an issue.) I'm not very familiar with AXISTABLE options, but I'd start with VALUEFORMAT=3. or try to right-align the numbers.

 

antor82
Obsidian | Level 7

@Rick_SAS  I've attached the data.

 

When I change Stratum2 with StratumNum2 --> I can see three different rows, namely

1

2

.

 

therefore I think that there is some missing value in Stratum2 and StratumNum2 that creates this problems.

 

Suggestion #1: nothing happens;

Suggestion #2: number of its at risk is correctly placed!

Suggestion #3: two identical plots.

Suggestion #4: I don't thin it is a problem of digits.

Because the problem manifests when I use the Stratum2 or StratumNum2 (which can be used alternatively, it's only a metter of how the two strata appear on the graph).

 

Tks!

 

 

Rick_SAS
SAS Super FREQ

I don't know why the axis tables are not aligned.

 

However, if you are interested in solving the problem another way, I suggest that you 

1. Restructure the data from wide to long. That will get rid of the missing values in STRATUM2.

2. Use ODS Graphics Designer to mock up a template that creates the main features, then customize it by hand.

 

This will allow you to use the DATALATTICE layout, which is preferred if you are creating a panel like this with equated axes.

 

Here is a start, if you want to pursue it:

 

/* convert from wide to long */
data s1;
set lib.survival_unified;
keep Time Survival AtRisk Event Censored tAtRisk Stratum StratumNum;
run;
data s2;
set lib.survival_unified;
keep Time2 Survival2 AtRisk2 Event2 Censored2 tAtRisk2 Stratum2 StratumNum2;
rename Time2=Time
       Survival2=Survival
       AtRisk2=AtRisk
       Event2=Event
       Censored2=Censored
       tAtRisk2=tAtRisk
       Stratum2=Stratum
       StratumNum2=StratumNum;
run;

data survival;
set s1(in=in1) s2;
if in1 then Group=1;
else Group=2;
run;


/* some sample code from ODS designer to get you started */
proc template;
define statgraph sgdesign;
dynamic _TIME _CENSORED _STRATUM _GROUP _TIME2 _SURVIVAL _STRATUM2 _TATRISK _ATRISK _STRATUM3 _GROUP2;
dynamic _panelnumber_;
begingraph / designwidth=1162 designheight=480;
   entrytitle halign=center 'Type in your title...';
   entryfootnote halign=left 'Type in your footnote...';
   layout datalattice columnvar=_GROUP / cellwidthmin=1 cellheightmin=1 rowgutter=3 columngutter=3 rowdatarange=unionall row2datarange=unionall columndatarange=unionall column2datarange=unionall headerlabeldisplay=value rowaxisopts=( offsetmin=0.2 linearopts=( viewmin=0.0));
      layout prototype / ;
         scatterplot x=_TIME y=_CENSORED / group=_STRATUM name='scatter';
         stepplot x=_TIME2 y=_SURVIVAL / group=_STRATUM2 name='step' connectorder=xaxis grouporder=data clusterwidth=0.85;
         axistable x=_TATRISK value=_ATRISK / class=_STRATUM3 colorgroup=_GROUP2 stat=mean name='axistable_h2' labelposition=min;
      endlayout;
   endlayout;
endgraph;
end;
run;

proc sgrender data=WORK.SURVIVAL template=sgdesign;
dynamic _TIME="TIME" _CENSORED="CENSORED" _STRATUM="STRATUM" _GROUP="GROUP" _TIME2="TIME" _SURVIVAL="SURVIVAL" _STRATUM2="STRATUM" _TATRISK="TATRISK" _ATRISK="ATRISK" _STRATUM3="STRATUM" _GROUP2="GROUP";
run;
JeffMeyers
Barite | Level 11

Hello,

   I was able to fix this by adding the INCLUDEMISSINGCLASS=FALSE option to the AXISTABLE statement.

 

SGRender.png

 

Also putting out a plug for my macro NEWSURV that can make these kind of lattice of survival plots for you:

https://communities.sas.com/t5/SAS-Communities-Library/Kaplan-Meier-Survival-Plotting-Macro-NEWSURV/...

Rick_SAS
SAS Super FREQ

Great job, Jeff.

 

I also wondered why the OP is constructing these plots by hand. There is a chapter in the SAS/STAT doc dedicated to creating these plots.  If the issue is wanting to arrange them side-by-side, then look into the ODS LAYOUT statement, which enables you to arrange multiple graphs or tables into a grid.

 

Anyway, problems solved (I hope)

antor82
Obsidian | Level 7
Thank You very much!!!!

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 8 replies
  • 4441 views
  • 2 likes
  • 3 in conversation