Paneled Box Plot - RhoInc/sas-sgplot GitHub Wiki
Contents
- The Goal
- Dummy Data
- Vbox Only
- Add Panels
- Make Panels Nice
- Make Axes Nice
- Style Modifications
- Fix Colaxis
The Paneled Box Plot will be developed in several steps. A succinct version of the code is available here.
The Goal
On this page, we will walk through the process of creating a paneled box plot, paneled by visit, with treatment comparisons within each visit.
Dummy Data
The dummy data used to produce this plot was created with the following data step. This data step is only included for the sake of completeness. Do not read, study, or obsess over this data step!
data derive.adlb;
length paramcd $8 param $100;
do paramcd = "ALT", "AST";
if paramcd = "ALT" then
param = "Alanine Aminotransferase (IU/L)";
else if paramcd = "AST" then
param = "Aspartate Transaminase (IU/L)";
do trtpn = 1 to 4;
trtp = propcase(put(trtpn,words.));
do subjid = 1 to 40;
do avisitn = 0, 1, 2, 4, 6, 8 to 24 by 4;
length avisit $20;
if avisitn = 0 then avisit = "B/L";
else avisit = 'Week ' || strip(put(avisitn,best.));
aval = 45 + rannor(1)*(1+avisitn/24)*(trtpn/4);
if ranuni(1) < (50-avisitn)/50 then output;
end;
end;
end;
end;
run;
Vbox Only
In this step, we will learn how to produce a "vbox only" plot.
In order to create a vbox (vertical box) plot, we first subset and sort our data. We sort it by avisitn
to order the panels. We sort by trtpn
to order the treatments within each panel.
proc sort data=derive.adlb out=pbp00;
by avisitn trtpn;
where paramcd = "ALT";
run;
If we are going to produce a figure for a commercial study, it is probably going to need to be saved as an RTF file. The typical options
, ods graphics
, and ods rtf
statements that surround the sgplot
code are as follows:
options
nonumber
nodate
orientation=landscape
;
ods graphics /
noborder
height=4in
width=8in
outputfmt=png
;
ods results off;
ods listing close;
ods rtf file="&PgmDir\vbox_only.rtf";
<<sgplot portion>>
ods rtf close;
ods listing;
ods results on;
The <<sgplot portion>>
contains a vbox
statement along with a couple of basic options.
proc sgplot data=pbp00;
*--- draw box plots ---;
vbox aval /
category=trtpn
fillattrs=(color=ltgray)
;
run;
Notice that we used the option category
instead of group
. Had we used group
we would have end up with a legend, which would require the use of colors (or worse, patterns) to differentiate the groups. Instead, we used category
so that the trtpn
values will be displayed on the xaxis.
Add Panels
An astute observer will have noticed that the above code did not produce a paneled plot. In this step, we switch from SGPLOT to SGPANEL. The vbox
statement remains unaltered. We add the aptly-named panelby
statement so that SGPANEL will know how to panel the data.
proc sgpanel data=pbp00;
*--- panel structure ---;
panelby avisitn;
*--- draw box plots ---;
vbox aval /
category=trtpn
fillattrs=(color=ltgray)
;
run;
Notice how the header labels for the panels are pretty crude. Also notice how the individual panels are drawn so large that only two can fit on a page.
Make Panels Nice
In this step we clean up the header labels and shrink the panels so that all visits fit on one page.
First we create a format for the header labels.
proc sql;
create table avisitn as
select distinct "avisitn" as fmtname,
avisitn as start,
avisit as label
from pbp00
;
quit;
proc format cntlin=avisitn;
run;
proc sql noprint;
alter table pbp00
modify avisitn format=avisitn.
;
quit;
Now we add a couple of options to the panelby
statement.
proc sgpanel data=pbp00;
*--- panel structure ---;
panelby avisitn /
rows=2
columns=5
novarname
;
*--- draw box plots ---;
vbox aval /
category=trtpn
fillattrs=(color=ltgray)
;
run;
The purpose of the novarname
option is to prevent the header labels from including the variable name (e.g., avisitn = Week 1
).
Make Axes Nice
Next we clean up the axes.
First we create a macro variable to hold the yaxis label.
proc sql noprint;
select distinct strip(param)
into :ylabel
from pbp00
;
quit;
%let ylabel = &ylabel;
%put &=ylabel;
And then we create a format to use on the xaxis values.
proc sql;
create table trtpn as
select distinct "trtpn" as fmtname,
trtpn as start,
trtp as label
from pbp00
;
quit;
proc format cntlin=trtpn;
run;
proc sql noprint;
alter table pbp00
modify trtpn format=trtpn.
;
quit;
The last part of this step is to add two axis statements. Notice how yaxis
and xaxis
from SGPLOT have become rowaxis
and colaxis
in SGPANEL.
proc sgpanel data=pbp00;
panelby ...
vbox ...
*--- axes ---;
rowaxis
label="&ylabel"
;
colaxis
label="Treatment"
;
run;
Style Modifications
As a penultimate step, we perform some style modifications to change fonts.
Changing fonts requires TEMPLATE code. Try not to have a panic attack.
proc template;
define style styles.pbpstyle;
parent=styles.rtf;
class GraphFonts /
"GraphDataFont" = ("Courier New", 7pt)
"GraphValueFont" = ("Courier New", 9pt)
"GraphLabelFont" = ("Courier New",10pt)
;
end;
run;
Having created this new style styles.pbpstyle
, we apply it on the ods rtf
statement.
ods rtf
style=styles.pbpstyle
file="&PgmDir\PBP_05_style_mods.rtf"
;
proc sgpanel data=pbp00;
panelby ...
vbox ...
rowaxis ...
colaxis ...
run;
ods rtf close;
Fix Colaxis
Unfortunately, changing the font resulted in the colaxis values being rotated. Unacceptable! We will use the fitpolicy
option to fix this.
proc sgpanel data=pbp00;
panelby ...
vbox ...
rowaxis ...
colaxis
label="Treatment"
fitpolicy=stagger
;
run;
Next page: Forest Plot with Subgroups