When creating a forest plot in SGPLOT, if the number of rows in the input data set is relatively small [13 in my example], the top line appears to be "out of frame".
Adding three more rows to be displayed, and the top line is displayed correctly.
Is there a way to avoid this from happening, other than adding more display rows?
The problem seems to happen across different outputs [results window, PDF, RTF]
this is the clipped top line version
and the larger data set that does not result in clipping
["Overall" can clearly be read in the second graphic.]
Thank you
Try adjusting the offsetmin to value like 0.1 or 0.05 in the YAXIS statement instead of 0.0 .
When you use REVERSE the smallest value appearing at the top has the offset applied. I think what may be happening with the fewer observations is the algorithm setting the space for each row allocates things differently when the number of rows is even and odd. With the offset you specify when the number of rows is "just right" then the offset of 0 is on the border of the graph and only "half" is shown because that is the upper limit with reverse.
Code. Really need to see the options you are using. Better would be include a data step with the data used so we can test the code and see about suggestions that work with your data.
Post code into a text box or code box opened on the forum with the </> or "running man" icons.
I replied with the code, and got a message that the reply was removed as spam. I will try again.
data forest_subgroup;
input
Id Subgroup $3-27 Event Total HR Low High PVal;
indentWt =1;
ObsId =_n_;
length EvenTot $30.;
if Event ne .
then EvenTot= catx("/",put(Event,4.0),put(Total,4.0));
length EvenTot $30.;
if Event ne .
then HRres =
compress(put( HR,8.2))||" ("||
compress(put( Low,8.2))||"-"||
compress(put(High,8.2))||")"
;
datalines;
1 Overall 100 150 0.50 0.45 0.65 .
1 Region . . . . . 0.5555
2 Here 10 20 0.40 0.20 0.9 .
2 there 100 200 0.32 0.25 0.75 .
1 Color . . . . . 0.6666
2 Red 150 180 0.20 0.10 0.30 .
2 Yellow 60 70 0.50 0.40 1.20 .
1 Pet . . . . . 0.7777
2 Dog 40 60 0.30 0.05 0.65 .
2 Cat 70 80 0.45 0.30 0.75 .
1 Another . . . . . 0.8888
2 This 70 90 0.50 0.30 0.90 .
2 That 50 60 0.10 0.05 0.45 .
1 Region2 . . . . . 0.5555
2 Here2 10 20 0.40 0.20 0.9 .
2 there2 100 200 0.32 0.25 0.75 .
;
run; quit;
/*--Set indent weight, add insets and horizontal bands--*/
data forest_subgroup_2;
set forest_subgroup nobs=n end=last;
length text $20.;
val=mod(_N_, 2);
if val gt 0 then ref=obsid;
/*--Separate Subgroup headers and obs into separate columns--*/
indentwt=1;
if id=1 then indentWt=0;
output;
if last then do;
call missing (
Subgroup ,Event ,Total ,HR ,Low
,High ,PVal ,indentWt ,ObsId ,EvenTot
,HRres ,val ,ref ,indentwt
);
obsid=n+1;
xl=0.77; yl=n+1; text='P'; output; /*Experimental arm */
xl=1.17; yl=n+1; text='T'; output; /*SOC */
end;
run; quit;
/*--Define Format with Unicode for the left and right arrows--*/
proc format;
value $txt
"T" = "SOC Better (*ESC*){Unicode '2192'x}"
"P" = "(*ESC*){Unicode '2190'x} Other Better";
run;
/*--Attribute maps for Subgroup Test attributes--*/
data attrmap;
length textweight $10;
id='text'; value='1'; textcolor='Black'; textsize=5; textweight='bold'; output;
id='text'; value='2'; textcolor='Black'; textsize=5; textweight='normal'; output;
run;
/*--Forest Plot--*/
proc sgplot data=forest_subgroup_2 nowall noborder nocycleattrs dattrmap=attrmap noautolegend;
format text $txt.;
styleattrs axisextent=data;
refline ref / lineattrs=(thickness=10 color=cxf0f0f7);
highlow y=obsid low=low high=high/ highcap=serif lowcap=serif lineattrs=(thickness=1px) ;
scatter y=obsid x=HR / markerattrs=(symbol=diamondfilled size=4pt);
scatter y=obsid x=HR / markerattrs=(size=0) x2axis;
refline 1 / axis=x;
text x=xl y=obsid text=text / position=bottom contributeoffsets=none strip;
yaxistable subgroup / location=inside position=left textgroup=id labelattrs=(size=7)
textgroupid=text indentweight=indentWt;
yaxistable EvenTot / location=inside titlehalign=right position=left labelattrs=(size=7) valueattrs=(size=7) pad=(left=0px right=0px);
yaxistable HRres pval / location=inside position=right pad=(right=5px)
labelattrs=(size=7) valueattrs=(size=7);
yaxis reverse display=none colorbands=odd colorbandsattrs=(transparency=1) offsetmin=0.0;
xaxis display=(nolabel) values=(0.0 0.5 1.0 1.2);
x2axis label='Hazard Ratio (95% CI)' display=(noline noticks novalues) labelattrs=(size=8);
label
subgroup="Stratification Factor"
pval="Homogeneity P-value"
EvenTot = "Events/Total"
HRres = ''
;
format pval 8.3;
run; quit;
I can make it fit by inserting a dummy observation before "Overall".
It works, but I would rather not have to employ workarounds.
@jtcowder wrote:
I replied with the code, and got a message that the reply was removed as spam. I will try again.
data forest_subgroup; input Id Subgroup $3-27 Event Total HR Low High PVal; indentWt =1; ObsId =_n_; length EvenTot $30.; if Event ne . then EvenTot= catx("/",put(Event,4.0),put(Total,4.0)); length EvenTot $30.; if Event ne . then HRres = compress(put( HR,8.2))||" ("|| compress(put( Low,8.2))||"-"|| compress(put(High,8.2))||")" ; datalines; 1 Overall 100 150 0.50 0.45 0.65 . 1 Region . . . . . 0.5555 2 Here 10 20 0.40 0.20 0.9 . 2 there 100 200 0.32 0.25 0.75 . 1 Color . . . . . 0.6666 2 Red 150 180 0.20 0.10 0.30 . 2 Yellow 60 70 0.50 0.40 1.20 . 1 Pet . . . . . 0.7777 2 Dog 40 60 0.30 0.05 0.65 . 2 Cat 70 80 0.45 0.30 0.75 . 1 Another . . . . . 0.8888 2 This 70 90 0.50 0.30 0.90 . 2 That 50 60 0.10 0.05 0.45 . 1 Region2 . . . . . 0.5555 2 Here2 10 20 0.40 0.20 0.9 . 2 there2 100 200 0.32 0.25 0.75 . ; run; quit; /*--Set indent weight, add insets and horizontal bands--*/ data forest_subgroup_2; set forest_subgroup nobs=n end=last; length text $20.; val=mod(_N_, 2); if val gt 0 then ref=obsid; /*--Separate Subgroup headers and obs into separate columns--*/ indentwt=1; if id=1 then indentWt=0; output; if last then do; call missing ( Subgroup ,Event ,Total ,HR ,Low ,High ,PVal ,indentWt ,ObsId ,EvenTot ,HRres ,val ,ref ,indentwt ); obsid=n+1; xl=0.77; yl=n+1; text='P'; output; /*Experimental arm */ xl=1.17; yl=n+1; text='T'; output; /*SOC */ end; run; quit; /*--Define Format with Unicode for the left and right arrows--*/ proc format; value $txt "T" = "SOC Better (*ESC*){Unicode '2192'x}" "P" = "(*ESC*){Unicode '2190'x} Other Better"; run; /*--Attribute maps for Subgroup Test attributes--*/ data attrmap; length textweight $10; id='text'; value='1'; textcolor='Black'; textsize=5; textweight='bold'; output; id='text'; value='2'; textcolor='Black'; textsize=5; textweight='normal'; output; run; /*--Forest Plot--*/ proc sgplot data=forest_subgroup_2 nowall noborder nocycleattrs dattrmap=attrmap noautolegend; format text $txt.; styleattrs axisextent=data; refline ref / lineattrs=(thickness=10 color=cxf0f0f7); highlow y=obsid low=low high=high/ highcap=serif lowcap=serif lineattrs=(thickness=1px) ; scatter y=obsid x=HR / markerattrs=(symbol=diamondfilled size=4pt); scatter y=obsid x=HR / markerattrs=(size=0) x2axis; refline 1 / axis=x; text x=xl y=obsid text=text / position=bottom contributeoffsets=none strip; yaxistable subgroup / location=inside position=left textgroup=id labelattrs=(size=7) textgroupid=text indentweight=indentWt; yaxistable EvenTot / location=inside titlehalign=right position=left labelattrs=(size=7) valueattrs=(size=7) pad=(left=0px right=0px); yaxistable HRres pval / location=inside position=right pad=(right=5px) labelattrs=(size=7) valueattrs=(size=7); yaxis reverse display=none colorbands=odd colorbandsattrs=(transparency=1) offsetmin=0.0; xaxis display=(nolabel) values=(0.0 0.5 1.0 1.2); x2axis label='Hazard Ratio (95% CI)' display=(noline noticks novalues) labelattrs=(size=8); label subgroup="Stratification Factor" pval="Homogeneity P-value" EvenTot = "Events/Total" HRres = '' ; format pval 8.3; run; quit;
Is this supposed to be an example that clips the data or not? If this is an example that doesn't clip then post one that does the clipping. It may help to provide the ODS Style in effect though. I know that I am using the Meadow style because the default fonts tend to be a bit smaller than several other styles.
When I run this I do not have anything clipped.
You might try ODS Graphics / reset; to restore defaults in case something you have set other than the dimensions is causing the clipping.
A minor suggestion: A custom format for your Pval might look a bit cleaner so that missing values don't display the dot in the axis table.
Proc format; value mypval . = ' ' other=[8.3] ; run;
Sorry about this.
I posted the code with a disclaimer up front about what to do to create the problem.
It did not make it into my updated post.
As posted, this code will not clip.
Delete the last three lines of the data set.
Get rid of
1 Region2 ...
2 Here2
2 There2
and run it again, please.
My top line looks like
Try adjusting the offsetmin to value like 0.1 or 0.05 in the YAXIS statement instead of 0.0 .
When you use REVERSE the smallest value appearing at the top has the offset applied. I think what may be happening with the fewer observations is the algorithm setting the space for each row allocates things differently when the number of rows is even and odd. With the offset you specify when the number of rows is "just right" then the offset of 0 is on the border of the graph and only "half" is shown because that is the upper limit with reverse.
That did it.
Thank you.
I tried posting the code, and the post was removed as spam.
I notified the moderators.
As soon as this is cleared up I will try again.
I will try is this way.
I attached the code as a file instead of in-line.
Maybe that will keep it from being flagged.
How are you controlling the size of your graphics and page?
Please show your code.
@jtcowder wrote:
When creating a forest plot in SGPLOT, if the number of rows in the input data set is relatively small [13 in my example], the top line appears to be "out of frame".
Adding three more rows to be displayed, and the top line is displayed correctly.
Is there a way to avoid this from happening, other than adding more display rows?
The problem seems to happen across different outputs [results window, PDF, RTF]
this is the clipped top line version
and the larger data set that does not result in clipping
["Overall" can clearly be read in the second graphic.]
Thank you
Available on demand!
Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.
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.