Monday, January 4, 2016

Forest Plot of Hazard Ratios by Patient Subgroups using SAS






















The original paper can be found here: 
Base SAS: GTL Template Language
SAS 9.4 GTL feature: Value statement's TextAttrs option

%let graphs='.';

%let dpi=100;
%let w=8in;
%let h=4.5in;

/*--Leading blanks in the subgroup variable must be non--blank spaces  --*/
/*--Use character value 'A0', or copy from Windows System Character Map--*/
/*--Regular leading blanks will be stripped, losing the indentation    --*/
data forest;
  input Indent Subgroup $3-27 Count Percent Mean  Low  High  PCIGroup Group PValue;
  format PCIGroup Group PValue 7.2;
  zero=0; 
  if count ne . then CountPct=put(count, 4.0) || "(" || put(percent, 3.0) || ")";
  datalines;
0 Overall..................2166  100  1.3   0.9   1.5  17.2  15.6  .
0 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   .
0 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   . 
0 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.6   1.6  16.7  15.0   . 
0 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   .
0 Infract-related artery....     .    .     .     .    .     .     0.38
2 LAD...................... 781   36  1.4   0.9   1.9  20.1  16.2   .
2 Other....................1385   64  1.1   0.8   1.4  15.6  15.3   . 
0 Ejection Fraction.........     .    .     .     .    .     .     0.48
2 < 50%....................1151   54  1.2   0.8   1.5  22.6  20.4   .
2 >= 50%................... 999   46  0.9   0.6   1.4  10.7  11.1   . 
0 Diabetes..................     .    .     .     .    .     .     0.41
2 Yes...................... 446   21  1.4   0.9   2.0  29.3  23.3   .
2 No.......................1720   79  1.1   0.8   1.5  14.4  13.5   . 
0 Killip class..............     .    .     .     .    .     .     0.39
2 I........................1740   81  1.2   0.8   1.6  15.2  13.1   .
2 II-IV.................... 413   19  0.95  0.6   1.5  25.3  26.9   . 
;
run;

/*--Replace '.' in subgroup with blank--*/
data forest2;
  set forest;
  subgroup=translate(subgroup, ' ', '.');
  val=mod(_N_-1, 6);
  indent=ifn(indent eq 2, 1, 0);
  if val eq 1 or val eq 2 or val eq 3 then ref=subgroup;
  run;

/*--Create font with smaller fonts for axis label, value and data--*/
proc template;
  define style listingSF; 
    parent = Styles.Listing; 
    style GraphFonts from GraphFonts                                                      
      "Fonts used in graph styles" /                                       
      'GraphDataFont' = (", ",7pt)                                
      'GraphValueFont' = (", ",6pt)
      'GraphLabelFont' = (", ",6pt, bold); 
  end;
run;

/*--Define templage for Forest Plot--*/
/*--Template uses a Layout Lattice of 6 columns--*/
proc template;
  define statgraph Forest;
  dynamic _show_bands _color _thk;
    begingraph;
      entrytitle 'Forest Plot of Hazard Ratios by Patient Subgroups ';
      discreteattrmap name='text';
        value '0' / textattrs=(weight=bold);
        value other;
      enddiscreteattrmap;
      discreteattrvar attrvar=type var=indent attrmap='text';

      layout lattice / columns=6 columnweights=(0.25 0.1 0.4 0.08 0.08 0.09);

      /*--Column headers--*/
      sidebar / align=top;
        layout lattice / rows=2 columns=4 columnweights=(0.2 0.25 0.25 0.3);
          entry textattrs=(size=8) halign=left "Subgroup";
          entry textattrs=(size=8) halign=left " No.of Patients (%)";
          entry textattrs=(size=8) halign=left "Hazard Ratio";
          entry halign=center textattrs=(size=8) "4-Yr Cumulative Event Rate" ;
          entry " "; 
          entry " "; 
          entry " "; 
          entry halign=center textattrs=(size=8) "Medical Therapy";
        endlayout;
      endsidebar;

      /*--First Subgroup column, shows only the Y2 axis--*/
      layout overlay / walldisplay=none xaxisopts=(display=none) 
          yaxisopts=(reverse=true display=none 
                     tickvalueattrs=(weight=bold));
        referenceline y=ref / lineattrs=(thickness=_thk color=_color);
        axistable y=subgroup value=subgroup / indentweight=indent textgroup=type;
       endlayout;

       /*--Second column showing Count and percent--*/
       layout overlay / xaxisopts=(display=none) 
            yaxisopts=(reverse=true display=none) walldisplay=none;
         referenceline y=ref / lineattrs=(thickness=_thk color=_color);
         axistable y=subgroup value=countpct;
       endlayout;

       /*--Third column showing odds ratio graph--*/
       layout overlay / xaxisopts=(label='   <---PCI Better----  ----Medical Therapy Better--->'  
           linearopts=(tickvaluepriority=true 
                       tickvaluelist=(0.0 0.5 1.0 1.5 2.0 2.5)))
           yaxisopts=(reverse=true display=none) walldisplay=none;
         referenceline y=ref / lineattrs=(thickness=_thk color=_color);
         scatterplot y=subgroup x=mean / xerrorlower=low xerrorupper=high 
           markerattrs=(symbol=squarefilled);
         referenceline x=1;
       endlayout;

       /*--Fourth column showing PCIGroup--*/
       layout overlay / x2axisopts=(display=(tickvalues) offsetmin=0.25 offsetmax=0.25) 
            yaxisopts=(reverse=true display=none) walldisplay=none;
         referenceline y=ref / lineattrs=(thickness=_thk color=_color);
         axistable y=subgroup value=PCIGroup / display=(label) labelposition=max;
       endlayout;

       /*--Fifth column showing Group--*/
       layout overlay / x2axisopts=(display=(tickvalues) offsetmin=0.25 offsetmax=0.25) 
            yaxisopts=(reverse=true display=none) walldisplay=none;
         referenceline y=ref / lineattrs=(thickness=_thk color=_color);
         axistable y=subgroup value=group / display=(label) labelposition=max;
       endlayout;

       /*--Sixth column showing P-Values--*/
       layout overlay / x2axisopts=(display=(tickvalues) offsetmin=0.25 offsetmax=0.25) 
           yaxisopts=(reverse=true display=none) walldisplay=none;
         referenceline y=ref / lineattrs=(thickness=_thk color=_color);
         axistable y=subgroup value=pvalue / display=(label) labelposition=max;
       endlayout;

     endlayout;
     entryfootnote halign=left textattrs=(size=7) 
       'The p-value is from the test statistic for testing the interaction between the '
       'treatment and any subgroup variable';
     entryfootnote halign=left 'This graph uses the new AXISTABLE plot to display the textual columns';
   endgraph;
  end;
run;

/*--Need format to show missing as blank--*/
proc format;
  value misblank
    . = ' ';
run;

/*----Create Graph-----*/
ods listing style=htmlblue gpath=&graphs image_dpi=&dpi;
ods graphics / reset noscale width=&w height=&h imagename='GTL_ForestPlot';
proc sgrender data=Forest2 template=Forest;
format pvalue group pcigroup misblank7.2;
dynamic _color='cxf0f0f0' _thk=12;
run;

No comments:

Post a Comment