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!
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;
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.
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;
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.
Ready to level-up your skills? Choose your own adventure.