title; data x; input age f; datalines; 1 . 2 20 3 10 ; proc format; value agefmt 1 = 'Age' 2 = "< 12" 3 = "(*ESC*){Unicode '2265'x} 12"; run; ods graphics on / width=2in height=1.5in; proc sgplot data=x; yaxistable age / position=left nolabel valuejustify=left valueattrs=(size=15); hbarparm category=age response=f / barwidth=0.3; format age agefmt.; yaxis display=none; xaxis display=none; run; data x2; input Age $ 1-8 f; AxisVar = _n_; datalines; Age . < 12 20 >= 12 10 ; data cntlin(keep=type fmtname start label); set x2; Type = 'n'; FmtName = "NewAgeFmt"; Start = axisvar; Label = tranwrd(age, '>=', "(*ESC*){Unicode '2265'x}"); run; proc format cntlin=cntlin; quit; proc print; run; proc sgplot data=x2; yaxistable axisvar / position=left nolabel valuejustify=left valueattrs=(size=15); hbarparm category=age response=f / barwidth=0.3; format axisvar newagefmt.; yaxis display=none; xaxis display=none; run; %macro cntlin( /*--------------------------------------------*/ data=_last_, /* Input data set. */ out=, /* Output data set. Default: &data.2. */ fmtname=myfmt, /* Format name. */ var=, /* Name of input variable for the format. */ axisvar=AxisVar, /* Name of output numeric row number variable.*/ lablen=500); /* Length of Label variable in format. */ /*--------------------------------------------*/ %if &data=_last_ %then %let data=&syslast; %if %nrbquote(&out) eq %then %let out = &data.2; data __cntlin(keep=_fmtname _start _type _label rename=(_fmtname=FmtName _start=Start _type=Type _label=Label)) &out(drop=_fmtname _type _label rename=(_start=&axisvar)); set &data; length _label $ &lablen; _type = 'n'; _fmtname = "&fmtname"; if &var ne ' ' then _start = _n_; _label = &var; %do i = 1 %to 24; %let l = %scan(alpha beta gamma delta epsilon zeta eta theta iota kappa lambda mu nu xi omicron pi rho sigma tau upsilon phi chi psi omega, &i); %let u = %sysfunc(propcase(&l,)); _label = tranwrd(_label, "\&l", "(*ESC*){Unicode &l}"); _label = tranwrd(_label, "\&u", "(*ESC*){Unicode &l._u}"); %end; _label = tranwrd(_label, '\inf', "(*ESC*){Unicode '221e'x}"); * Infinity; _label = tranwrd(_label, '\deg', "(*ESC*){Unicode '00B0'x}"); * Degree; _label = tranwrd(_label, '\eur', "(*ESC*){Unicode '20AC'x}"); * Euro; _label = tranwrd(_label, '\cen', "(*ESC*){Unicode '00A2'x}"); * Cent; _label = tranwrd(_label, '\cop', "(*ESC*){Unicode '00a9'x}"); * Copyright; _label = tranwrd(_label, '\bul', "(*ESC*){Unicode '2022'x}"); * Bullet; _label = tranwrd(_label, '\mid', "(*ESC*){Unicode '00B7'x}"); * Middle dot; _label = tranwrd(_label, '\tim', "(*ESC*){Unicode '00D7'x}"); * Multiply; _label = tranwrd(_label, '\emd', "(*ESC*){Unicode '2014'x}"); * Em dash (long dash); _label = tranwrd(_label, '\smi', "(*ESC*){Unicode '263a'x}"); * Smile; _label = tranwrd(_label, '\lra', "(*ESC*){Unicode '2194'x}"); * Left-right arrow; _label = tranwrd(_label, '\la', "(*ESC*){Unicode '2190'x}"); * Left arrow; _label = tranwrd(_label, '\ra', "(*ESC*){Unicode '2192'x}"); * Right arrow; _label = tranwrd(_label, '\ua', "(*ESC*){Unicode '2191'x}"); * Up arrow; _label = tranwrd(_label, '\da', "(*ESC*){Unicode '2193'x}"); * Down arrow; _label = tranwrd(_label, '\tm', "(*ESC*){Unicode '2122'x}"); * Trade mark; _label = tranwrd(_label, '\b', "(*ESC*){Unicode '00A0'x}"); * Nonbreaking space; _label = tranwrd(_label, '<=', "(*ESC*){Unicode '2264'x}"); * Less than or equal; _label = tranwrd(_label, '>=', "(*ESC*){Unicode '2265'x}"); * Greater than or equal; _label = tranwrd(_label, '~=', "(*ESC*){Unicode '2248'x}"); * Approximately equal; _label = tranwrd(_label, '^2', "(*ESC*){Unicode '00B2'x}"); * Superscript 2; _label = tranwrd(_label, '_i', "(*ESC*){Unicode '1D62'x}"); * Subscript i; _label = tranwrd(_label, '+-', "(*ESC*){Unicode '00B1'x}"); * Plus or minus; _label = tranwrd(_label, '^=', "(*ESC*){Unicode '2260'x}"); * Not equal; output &out; if n(_start) then output __cntlin; run; proc format cntlin=__cntlin; quit; %mend; data syms; input l $ 30.; n = _n_; len = length(l); datalines; le <= 12 ge >= 13 2 ~= 2.0001 x^2 x squared y_i y sub i 7 +- 2 haunted by an integer 2 ^= 4 not equal \inf infinity n\deg n degrees \eur20 20 Euros 25\cen two bits Copyright\cop \bul bullet point Non\b\bBreaking\b\b\bSpaces \mid Middle dot \tim Multiply \emd Em dash \tm Trade mark \la Left arrow \ra Right arrow \ua Up arrow \da Down arrow \lra Left-right arrow \smi Smile \alpha alpha \beta beta \gamma gamma \delta delta \epsilon epsilon \zeta zeta \eta eta \theta theta \iota iota \kappa kappa \lambda lambda \mu mu \nu nu \xi xi \omicron omicron \pi pi \rho rho \sigma sigma \tau tau \upsilon upsilon \phi phi \chi chi \psi psi \omega omega Alpha \Alpha Beta \Beta Gamma \Gamma Delta \Delta Epsilon \Epsilon Zeta \Zeta Eta \Eta Theta \Theta Iota \Iota Kappa \Kappa Lambda \Lambda Mu \Mu Nu \Nu Xi \Xi Omicron \Omicron Pi \Pi Rho \Rho Sigma \Sigma Tau \Tau Upsilon \Upsilon Phi \Phi Chi \Chi Psi \Psi Omega \Omega ; %cntlin(data=syms, var=l) ods graphics on / width=4in height=10in; proc sgplot data=syms2; yaxistable axisvar / position=left nolabel valueattrs=(family="Arial Unicode MS1"); hbarparm response=len category=n / barwidth=0.5; format axisvar myfmt.; yaxis display=none type=discrete type=discrete; xaxis display=none; run; data x3; input l1 $ l2 $ l3 $; len = length(l1) + length(l2) + length(l3); datalines; \alpha \Alpha <= \beta \Beta >= \mu \Mu ^= \omega \Omega ~= ; %cntlin(data=x3, out=x4, var=l1, fmtname=fmta, axisvar=v1) %cntlin(data=x4, out=x5, var=l2, fmtname=fmtb, axisvar=v2) %cntlin(data=x5, out=x6, var=l3, fmtname=fmtc, axisvar=v3) ods graphics on / width=2in height=1.5in; proc sgplot data=x6; format v1 fmta. v2 fmtb. v3 fmtc.; yaxistable v1 / position=left nolabel valuejustify=left valueattrs=(size=15); yaxistable v2 / position=left nolabel valuejustify=left valueattrs=(size=15); yaxistable v3 / position=left nolabel valuejustify=left valueattrs=(size=15); hbarparm category=v1 response=len / barwidth=0.3; yaxis display=none; xaxis display=none; run; /*--Add "Id" to identify subgroup headings from values--*/ data forest_subgroup; label PCIGroup='PCI Group' Group='Therapy Group'; input Id Subgroup $3-27 Count Percent Mean Low High PCIGroup Group PValue; label countpct='No. (%) of Patients'; indentWt=1; ObsId=_n_; if count ne . then CountPct=put(count, 4.0) || "(" || put(percent, 3.0) || ")"; 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 Randomization . . . . . . . 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 . ; /*--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_-1, 6); if val eq 1 or val eq 2 or val eq 3 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, count, percent, mean, low, high, pcigroup, group, countpct, indentwt, val, ref); obsid=n+1; xl=0.4; yl=n+1; text='P'; output;; xl=1.7; yl=n+1; text='T'; output; end; run; /*--Define Format with Unicode for the left and right arrows--*/ proc format;; value $txt "T" = "Therapy Better (*ESC*){Unicode '2192'x}" "P" = "(*ESC*){Unicode '2190'x} PCI Better"; run; /*--Attribute maps for Subgroup Test attributes--*/ data attrmap; length textweight $10; id='text'; value='1'; textcolor='Black'; textsize=7; textweight='bold'; output; id='text'; value='2'; textcolor='Black'; textsize=5; textweight='normal'; output; run; /*--Forest Plot--*/ data mine; set forest_subgroup_2; if indentwt then subgroup = repeat('\b', 5) || subgroup; run; %cntlin(data=mine, var=subgroup) options missing=' '; title j=r h=7pt '4-Yr Cumulative Event Rate'; ods graphics / width=5in height=3in; proc sgplot data=mine2 nowall noborder nocycleattrs dattrmap=attrmap noautolegend; format text $txt. axisvar myfmt.; 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 axisvar / location=inside position=left textgroup=id labelattrs=(size=7) textgroupid=text valuejustify=left label='Subgroup' labeljustify=left; 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; 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;