BookmarkSubscribeRSS Feed
dave_inman
Fluorite | Level 6

I am looking to produce a forest plot with YAXISTABLES using SAS 9.04.01M3

The labels for the table are not splitting in the correct place and I'd like to dictate where the splits occur (i'd like Placebo/Active on first line, N=XX on second and n/M (%) on third)

Plot examples belowforest1.png

 

I have tried various escape character options:

 

  • (*ESC*){UNICODE '0D0A'X} - Did not decode
  • (*ESC*){UNICODE '000A'X} - Did not decode
  • It does not appear possible to include a split character.

SAS Code:

 

 

 data WORK.PLOTDATA3;
   infile datalines dsd truncover;
   input sgval:32. indentl:32. plab:$40. n_pbo:$15. n_act:$15. valtab:$18. OddsRatioEst:ODDSR8.3 LowerCL:ODDSR8.3 UpperCL:ODDSR8.3 yval:32. orref:32. xl:32. text:$1.;
   format OddsRatioEst ODDSR8.3 LowerCL ODDSR8.3 UpperCL ODDSR8.3;
   label OddsRatioEst="Odds Ratio" LowerCL="Wald Lower Confidence Limit for Odds Ratio" UpperCL="Wald Upper Confidence Limit for Odds Ratio";
 datalines;
 1 0 Overall       . . . 1 . .  
 2 1 Overall xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 1.713 1.288 2.279 2 1.7130795416 .  
 1 0 Baseline Clinical Status       . . . 3 . .  
 2 1 Hosp. HF Oxy, NIV xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 1.714 1.073 2.738 4 . .  
 2 1 Hosp. Int, MV xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 1.712 1.195 2.454 5 . .  
 1 0 Age Group       . . . 6 . .  
 2 1 <60 years xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 1.580 1.055 2.366 7 . .  
 2 1 60 to <70 years xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 2.197 1.361 3.545 8 . .  
 2 1 70 to <80 years xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 1.211 0.569 2.577 9 . .  
 1 0 Baseline Clinical Status, Age Group       . . . 10 . .  
 2 1 Hosp. HF Oxy, NIV, <60 years xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 1.634 1.166 2.290 11 . .  
 2 1 Hosp. HF Oxy, NIV, 60 to <70 years xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 1.634 1.166 2.290 12 . .  
 2 1 Hosp. HF Oxy, NIV, 70 to <80 years xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 1.634 1.166 2.290 13 . .  
 2 1 Hosp. Int, MV , <60 years xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 1.634 1.166 2.290 14 . .  
 2 1 Hosp. Int, MV , 60 to <70 years xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 2.433 1.412 4.191 15 . .  
 2 1 Hosp. Int, MV , 70 to <80 years xxx/xxx (xxx%) xxx/xxx (xxx%) x.xx (x.xx,x.xx) 0.984 0.431 2.248 16 . .  
 . .         . . . 17 . 2 O
 . .         . . . 17 . 0.5 P
 ;;;;

PROC SGPLOT DATA=plotdata3 DATTRMAP=attrmap NOBORDER NOWALL NOAUTOLEGEND;
  FORMAT text $txt.;
  STYLEATTRS axisextent=data;
  REFLINE 1 / AXIS=x LINEATTRS=(THICKNESS=2 COLOR=grey);
  REFLINE orref / AXIS=x LINEATTRS=(THICKNESS=1 COLOR=grey PATTERN=2);
  SCATTER X=oddsratioest Y=yval / XERRORLOWER=lowercl XERRORUPPER=uppercl MARKERATTRS=(SYMBOL=CIRCLEFILLED SIZE=9 COLOR="BLACK") ERRORBARATTRS=(COLOR="BLACK") ;
  YAXISTABLE plab / POSITION=left LOCATION=inside INDENTWEIGHT=indentl  TEXTGROUP=sgval TEXTGROUPID=text  VALUEATTRS=(size=9) NOLABEL;
  YAXISTABLE n_pbo n_act valtab / POSITION=right LOCATION=inside VALUEATTRS=(size=9) VALUEHALIGN=center LABELATTRS=(SIZE=9);
  TEXT x=xl y=yval text=text / POSITION=bottom CONTRIBUTEOFFSETS=none STRIP TEXTATTRS=(SIZE=9);
  
  YAXIS DISPLAY=none REVERSE FITPOLICY=NONE OFFSETMAX=0.04 OFFSETMIN=0;
  XAXIS LABEL="Odds Ratio" LABELPOS=DATACENTER VALUEATTRS=(SIZE=10) MIN=0 MAX=8 TYPE=log VALUES=(0.25, 0.5, 1.0, 2.0, 4.0, 8.0);
  LABEL valtab = "OR (95% CI)"
        n_pbo = "Placebo N=XX n/M (%)"
        n_act = "Active N=XX n/M (%)";
RUN;

 

 

4 REPLIES 4
ballardw
Super User

Please copy your data step from your post, paste into your SAS editor and run the data step.

 

Then check if you really meant to use ODDSR8.3 as an informat. Since ODDSR is not a SAS supplied informat we can't use that and in many cases you really do not want to include a decimal bit with the informat unless you want SAS to imply a non-existant decimal position.

Reading a value like 123456 with an informat of 6.2 yields a value o f1234.56

 

When you can provide a data step that will run completely then we'll be in a better position to answer questions.

 

 

dave_inman
Fluorite | Level 6

I used the supplied code to generate the datastep, shame it doesn't work...: https://communities.sas.com/t5/SAS-Communities-Library/How-to-create-a-data-step-version-of-your-dat... As I didn't create the informat it must be a SAS supplied informat (perhaps in SAS Stat)?

 

Anyway new code below:

 data WORK.PLOTDATA3;
   infile datalines dsd truncover delimiter='#';
   input sgval:32. indentl:32. plab:$40. n_pbo:$15. n_act:$15. valtab:$18. OddsRatioEst:8.3 LowerCL:8.3 UpperCL:8.3 yval:32. orref:32. xl:32. text:$1.;
  
   label OddsRatioEst="Odds Ratio" LowerCL="Wald Lower Confidence Limit for Odds Ratio" UpperCL="Wald Upper Confidence Limit for Odds Ratio";
 datalines;
 1#0#Overall####.#.#.#1#.#.  
 2#1#Overall#xxx/xxx (xxx%)#xxx/xxx (xxx%)#x.xx (x.xx,x.xx)#1.713#1.288#2.279#2#1.7130795416#. 
 1#0#Baseline Clinical Status#####.#.#3#.#.# 
 2#1#Hosp. HF Oxy, NIV#xxx/xxx (xxx%)#xxx/xxx (xxx%)#x.xx (x.xx,x.xx)#1.714#1.073#2.738#4#.#.  
 2#1#Hosp. Int, MV#xxx/xxx (xxx%)#xxx/xxx (xxx%)#x.xx (x.xx,x.xx)#1.712#1.195#2.454#5#.#.  
 1#0#Age Group####.#.#.#6#.#.  
 2#1#<60 years#xxx/xxx (xxx%)#xxx/xxx (xxx%)#x.xx (x.xx,x.xx)#1.580#1.055#2.366#7#.#. 
 2#1#60 to <70 years#xxx/xxx (xxx%)#xxx/xxx (xxx%)#x.xx (x.xx,x.xx)#2.197#1.361#3.545#8#.#.  
 2#1#70 to <80 years#xxx/xxx (xxx%)#xxx/xxx (xxx%)#x.xx (x.xx,x.xx)#1.211#0.569#2.577#9#.#.  
 .#.#####.#.#.#10#.#2#O
 .#.#####.#.#.#10#.#0.5#P
 ;;;;

 

WarrenKuhfeld
Ammonite | Level 13

https://www.pharmasug.org/proceedings/2017/DV/PharmaSUG-2017-DV03.pdf

 

You might be interested in my paper with Mary Beth Herring.  Search for "split".

dave_inman
Fluorite | Level 6

Thanks, that appears to work for Rowlabels, and I suppose you could convert the "labels" into rows in your yaxistable when you want a column label, but that seems a bit clumsy I was hoping there was a simple way...

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

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
  • 4 replies
  • 2382 views
  • 0 likes
  • 3 in conversation