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

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

 

jtcowder_0-1630507550618.png

 

and the larger data set that does not result in clipping

 

jtcowder_1-1630507611192.png

["Overall" can clearly be read in the second graphic.]

 

Thank you

 

1 ACCEPTED SOLUTION

Accepted Solutions
ballardw
Super User

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.

View solution in original post

10 REPLIES 10
ballardw
Super User

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.

jtcowder
Fluorite | Level 6

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;
jtcowder
Fluorite | Level 6

I can make it fit by inserting a dummy observation before "Overall".

It works, but I would rather not have to employ workarounds.

ballardw
Super User

@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;

 

jtcowder
Fluorite | Level 6

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 

jtcowder_0-1630529443026.png

 

ballardw
Super User

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.

jtcowder
Fluorite | Level 6

That did it.  

Thank you.

jtcowder
Fluorite | Level 6

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.

jtcowder
Fluorite | Level 6

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.

Reeza
Super User

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

 

jtcowder_0-1630507550618.png

 

and the larger data set that does not result in clipping

 

jtcowder_1-1630507611192.png

["Overall" can clearly be read in the second graphic.]

 

Thank you

 


 

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 10 replies
  • 1008 views
  • 0 likes
  • 3 in conversation