BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
SAS-questioner
Obsidian | Level 7

Below are the code to create a regular forest plot that I found online:

 

proc sgplot data=forest_subgroup_2 nowall noborder nocycleattrs dattrmap=attrmap noautolegend;
  format text $txt.;
  styleattrs axisextent=data;
  refline ref / lineattrs=(thickness=13 color=cxf0f0f7);
  highlow y=obsid low=low high=high;
  scatter y=obsid x=mean / markerattrs=(symbol=squarefilled);
  scatter y=obsid x=mean / 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 countpct / location=inside position=left labelattrs=(size=7) valueattrs=(size=7);
  yaxistable PCIGroup group pvalue / location=inside position=right pad=(right=15px)
                      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.5 2.0 2.5);
  x2axis label='Hazard Ratio' display=(noline noticks novalues) labelattrs=(size=8);
run;

This code put countpct on the left right after subgroup, then followed by the scatter plots. The PCIgroup, group, and pvalue are on the right side of the graph after the scatter plots. 

 

Based on this code, I want to create an new forest plot with two scatter plots on both left and right side, and subgroup in the middle. In case way I can show two different outcomes on one graph. Can anyone help me? Thank you!

1 ACCEPTED SOLUTION

Accepted Solutions
Ksharp
Super User

You want this ?


proc template;
define statgraph y2axis ;
begingraph;
layout lattice /  columns=3 columngutter=0 columnweights=(0.38 0.24 0.38) rowdatarange=union;

layout overlay/ walldisplay=none YAXISOPTS=(display=none reverse=true) XAXISOPTS=(type=log display=(line ticks tickvalues));
highlowplot y=ObsId low=low high=high / lineattrs=(color=black) lowcap=serif highcap=serif;
scatterplot x=mean y=ObsId/markerattrs=(symbol=squarefilled size=10 color=black);
textplot x=xl y=obsid text=text /format=$txt. /* splitchar='|' splitpolicy=splitalways */
        textattrs=(size=10) position=bottom contributeoffsets=none strip=true;
referenceline x=1 ;
referenceline y=flag/lineattrs=(thickness=23 ) datatransparency=0.8;
endlayout;

layout overlay/walldisplay=none  XAXISOPTS=(display=none) YAXISOPTS=(display=none reverse=true);
scatterplot x=x1 y=ObsId/datalabel=Subgroup1 datalabelattrs=(size=10 weight=bold ) datalabelposition=right markerattrs=(size=0);
scatterplot x=x2 y=ObsId/datalabel=Subgroup2 datalabelattrs=(size=10) datalabelposition=right markerattrs=(size=0);
referenceline y=flag/lineattrs=(thickness=23 ) datatransparency=0.8;
endlayout;

layout overlay/walldisplay=none YAXISOPTS=(display=none reverse=true)  XAXISOPTS=(type=log display=(line ticks tickvalues));
highlowplot y=ObsId low=low2 high=high2 / lineattrs=(color=black) lowcap=serif highcap=serif;
scatterplot x=mean2 y=ObsId/markerattrs=(symbol=squarefilled size=10 color=black);
textplot x=xl y=obsid text=text /format=$txt. /*splitchar='|' splitpolicy=splitalways */
         textattrs=(size=10) position=bottom contributeoffsets=none strip=true;
referenceline x=1 ;
referenceline y=flag/lineattrs=(thickness=23 ) datatransparency=0.8;
endlayout;

endlayout;
endgraph;
end;
run;





data forest_subgroup;
  input Id Subgroup $ 3-27 Count Percent Mean  Low  High  PCIGroup Group PValue;
  if id=1 then do;x1=0;Subgroup1=Subgroup; line+1; end;
  if id=2 then do;x2=0;Subgroup2='     '||strip(Subgroup);end;
  ObsId=_n_; 
  mean2=mean;
  low2=low;
  high2=high;
  if mod(line,2)=0 then flag=ObsId;
  datalines;
1 Overall                  2166  100  1.3   0.9   1.5  17.2  15.6  .
1 Age                      .     .    .     .     .    .     .     0.05
2   <= 65 Yr               1534   71  1.5   1.05  1.9  17.0  13.2   .
2   > 65 Yr                 632   29  0.8   0.6   1.25 17.8  21.3   .
1 Sex                      .     .    .     .     .    .     .     0.13
2   Male                   1690   78  1.5   1.05  1.9  16.8  13.5   .
2   Female                  476   22  0.8   0.6   1.3  18.3  22.9   . 
1 Race or ethnic group     .     .    .     .     .    .     .     0.52
2   Nonwhite                428   20  1.05  0.6   1.8  18.8  17.8   .
2   White                  1738   80  1.2   0.85  1.6  16.7  15.0   . 
1 From MI to Random        .     .    .     .     .    .     .     0.81
2   <= 7 days               963   44  1.2   0.8   1.5  18.9  18.6   .
2   > 7 days               1203   56  1.15  0.75  1.5  15.9  12.9   .
1 Diabetes                 .     .    .     .     .    .     .     0.41
2   Yes                     446   21  1.4   0.9   2.0  29.3  23.3   .
2   No                      720   79  1.1   0.8   1.5  14.4  13.5   . 
;
run;
data want;
 set forest_subgroup end=last;
 output;
   if last then do;
    call missing(of _all_);
    obsid=_n_+1; 
    xl=0.7; yl=_n_+1; text='P'; output;
    xl=1.6; yl=_n_+1; text='T'; output;
  end;
run;
proc format;;
  value $txt
  "T" = "Therapy Better(*ESC*){Unicode '2192'x}"
  "P" = "(*ESC*){Unicode '2190'x}PCI Better";
run;

ods graphics/ANTIALIAS=on;
proc sgrender data=want template=y2axis;
run;

Ksharp_0-1750399849060.png

 

 

View solution in original post

3 REPLIES 3
ballardw
Super User

Can you provide an link or other image similar to what you want to create? I can think of several ways to interpret this " with two scatter plots on both left and right side, and subgroup in the middle" and experience tells me that the first two tries seldom match the desired result.

 

 

Ksharp
Super User

You want this ?


proc template;
define statgraph y2axis ;
begingraph;
layout lattice /  columns=3 columngutter=0 columnweights=(0.38 0.24 0.38) rowdatarange=union;

layout overlay/ walldisplay=none YAXISOPTS=(display=none reverse=true) XAXISOPTS=(type=log display=(line ticks tickvalues));
highlowplot y=ObsId low=low high=high / lineattrs=(color=black) lowcap=serif highcap=serif;
scatterplot x=mean y=ObsId/markerattrs=(symbol=squarefilled size=10 color=black);
textplot x=xl y=obsid text=text /format=$txt. /* splitchar='|' splitpolicy=splitalways */
        textattrs=(size=10) position=bottom contributeoffsets=none strip=true;
referenceline x=1 ;
referenceline y=flag/lineattrs=(thickness=23 ) datatransparency=0.8;
endlayout;

layout overlay/walldisplay=none  XAXISOPTS=(display=none) YAXISOPTS=(display=none reverse=true);
scatterplot x=x1 y=ObsId/datalabel=Subgroup1 datalabelattrs=(size=10 weight=bold ) datalabelposition=right markerattrs=(size=0);
scatterplot x=x2 y=ObsId/datalabel=Subgroup2 datalabelattrs=(size=10) datalabelposition=right markerattrs=(size=0);
referenceline y=flag/lineattrs=(thickness=23 ) datatransparency=0.8;
endlayout;

layout overlay/walldisplay=none YAXISOPTS=(display=none reverse=true)  XAXISOPTS=(type=log display=(line ticks tickvalues));
highlowplot y=ObsId low=low2 high=high2 / lineattrs=(color=black) lowcap=serif highcap=serif;
scatterplot x=mean2 y=ObsId/markerattrs=(symbol=squarefilled size=10 color=black);
textplot x=xl y=obsid text=text /format=$txt. /*splitchar='|' splitpolicy=splitalways */
         textattrs=(size=10) position=bottom contributeoffsets=none strip=true;
referenceline x=1 ;
referenceline y=flag/lineattrs=(thickness=23 ) datatransparency=0.8;
endlayout;

endlayout;
endgraph;
end;
run;





data forest_subgroup;
  input Id Subgroup $ 3-27 Count Percent Mean  Low  High  PCIGroup Group PValue;
  if id=1 then do;x1=0;Subgroup1=Subgroup; line+1; end;
  if id=2 then do;x2=0;Subgroup2='     '||strip(Subgroup);end;
  ObsId=_n_; 
  mean2=mean;
  low2=low;
  high2=high;
  if mod(line,2)=0 then flag=ObsId;
  datalines;
1 Overall                  2166  100  1.3   0.9   1.5  17.2  15.6  .
1 Age                      .     .    .     .     .    .     .     0.05
2   <= 65 Yr               1534   71  1.5   1.05  1.9  17.0  13.2   .
2   > 65 Yr                 632   29  0.8   0.6   1.25 17.8  21.3   .
1 Sex                      .     .    .     .     .    .     .     0.13
2   Male                   1690   78  1.5   1.05  1.9  16.8  13.5   .
2   Female                  476   22  0.8   0.6   1.3  18.3  22.9   . 
1 Race or ethnic group     .     .    .     .     .    .     .     0.52
2   Nonwhite                428   20  1.05  0.6   1.8  18.8  17.8   .
2   White                  1738   80  1.2   0.85  1.6  16.7  15.0   . 
1 From MI to Random        .     .    .     .     .    .     .     0.81
2   <= 7 days               963   44  1.2   0.8   1.5  18.9  18.6   .
2   > 7 days               1203   56  1.15  0.75  1.5  15.9  12.9   .
1 Diabetes                 .     .    .     .     .    .     .     0.41
2   Yes                     446   21  1.4   0.9   2.0  29.3  23.3   .
2   No                      720   79  1.1   0.8   1.5  14.4  13.5   . 
;
run;
data want;
 set forest_subgroup end=last;
 output;
   if last then do;
    call missing(of _all_);
    obsid=_n_+1; 
    xl=0.7; yl=_n_+1; text='P'; output;
    xl=1.6; yl=_n_+1; text='T'; output;
  end;
run;
proc format;;
  value $txt
  "T" = "Therapy Better(*ESC*){Unicode '2192'x}"
  "P" = "(*ESC*){Unicode '2190'x}PCI Better";
run;

ods graphics/ANTIALIAS=on;
proc sgrender data=want template=y2axis;
run;

Ksharp_0-1750399849060.png

 

 

hackathon24-white-horiz.png

The 2025 SAS Hackathon Kicks Off on June 11!

Watch the live Hackathon Kickoff to get all the essential information about the SAS Hackathon—including how to join, how to participate, and expert tips for success.

YouTube LinkedIn

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
  • 3 replies
  • 729 views
  • 5 likes
  • 3 in conversation