Morning,
I'm trying to use proc gchart in conjunction with the annotation facility to generate a stacked bar graph with a table annotated below. An example of my desired result is below (produced in Excel):
The closest example I found was at http://support.sas.com/kb/35/774.html so this is what I modeled my code off of. I did get my data set up and was able to make the example code work and produce a graph similar to what is in the preceding link (two bars per response variable with the actual response values displayed in a grid under the bar graph). That result is below:
I then began adjusting my code to create stacked bars and got my table frame and legend set up appropriately. The issue I am running into now is that the response values are scrunched to the left of my annotated table (see highlighted portion):
My code is below. This is not complete (i.e. the pieces that define the raw data behind the graph are not included for brevity). I mainly need help with the /*Populate the table */ portion and curious if anyone sees anything obvious that I need to adjust to get my data annotations correctly displayed in the table. Or perhaps my gchart code is not set up correctly to do what I want. If needed I can re-post code to facility reproducibility.
data impact&spectype._forprint;
length mid $15.;
set impact&spectype._forprint;
if dx ne 'Total' then do;
response=&spectype.totreq; mid='totreq'; output; *use to display N in annotated data;
response=totremain; mid='totremain'; output; *use to display N in annotated data;
response=pctrequest; mid='pctrequest'; output; *use for % in y-axis of stacked bar;
response=pctremain; mid='pctremain'; output; *use for % in y-axis of stacked bar;
end;
keep dx response mid totremain &spectype.totreq pctrequest pctremain n;
run;
proc sort; by dx mid; run;
data impact&spectype._anno;
set impact&spectype._forprint;
by dx mid;
length function color $8 text $20 style $ 20;
/* Populate the table */
if first.dx then do;
function='move'; xsys='2'; ysys='1';
midpoint=mid; group=dx; y=0;
output;
function='cntl2txt'; output;
function='label'; xsys='A'; ysys='3';
x=+3; y=17.25;
text=trim(left(put(&spectype.totreq,8.1)));
color='black'; position='+'; when='a';
output;
function='move'; xsys='2'; ysys='1';
midpoint=mid; group=dx; y=0;
output;
function='cntl2txt'; output;
function='label'; xsys='A'; ysys='3';
x=+3; y=13.75;
text=trim(left(put(totremain,8.1)));
color='black'; position='+'; when='a';
output;
end;
/* Generate the table frame */
function='move'; xsys='3'; ysys='3';
x=3; y=12;
output;
function='bar'; xsys='1'; ysys='3';
x=100; y=19;
style='empty'; color='black'; line=0;
output;
/* Generate the row headers */
function='label'; xsys='3'; ysys='3';
style='marker'; text='U'; color='cxde7e6f';
x=4; y=17.25; position='6';
output;
function='label'; xsys='3'; ysys='3';
style="Albany AMT"; text='Total requested'; color='black';
x=7; y=17.5; position='6';
output;
function='label'; xsys='3'; ysys='3';
style='marker'; text='U'; color='cx7c95ca';
x=4; y=13.75; position='6';
output;
function='label'; xsys='3'; ysys='3';
style="Albany AMT"; text='Total remaining'; color='black';
x=7; y=14; position='6';
output;
/* Generate the vertical lines in the table */
function='move'; xsys='1'; ysys='1';
x=0; y=0;
output;
function='draw'; xsys='1'; ysys='3';
x=0; y=12;
line=1; color='black';
output;
function='move'; xsys='1'; ysys='1';
x=100; y=0;
output;
function='draw'; xsys='1'; ysys='3';
x=100; y=12;
line=1; color='black';
output;
/* Generate the horizontal line in the table */
function='move'; xsys='3'; ysys='3';
x=3; y=15.5;
output;
function='draw'; xsys='1'; ysys='3';
x=100; y=15.5;
line=1; color='black';
output;
run;
%mend impact;
%impact (spectype=frozen);
ods graphics;
title1 font='arial' height=10pt "Total frozen aliquots requested for R050, by final clinical diagnosis";
axis1 label=(a=90 '% Aliquots')
order=(80 to 100 by 2)
minor=none;
axis2 label=none
value=none
origin=(20pct,22pct)
offset=(4pct,4pct);
axis3 label=none;
footnote1 h=.5 ' ';
pattern1 value=solid color=cx7c95ca;
pattern2 value=solid color=cxde7e6f;
ods pdf file="X:\XXX\COMMON\Requests\test.pdf";
proc gchart data=impactfrozen_forprint (where=(mid in ('pctremain','pctrequest')));
vbar dx / sumvar=response subgroup=mid group=dx g100 nozero
coutline=black
space=0 gspace=5 width=4
cframe=white autoref clipref
raxis=axis1 maxis=axis2 gaxis=axis3 nolegend
annotate=impactfrozen_anno;
run; quit;
ods pdf close;
Here's one way to do it with gchart and annotate:
%let name=bar_table; filename odsout '.'; goptions device=png; goptions border; ODS LISTING CLOSE; ODS HTML path=odsout body="&name..htm" style=htmlblue; goptions gunit=pct htitle=6 ftitle="albany amt/bold" htext=4.25 ftext="albany amt"; gopitons ctext=gray33; data dx; input nmid $ pctmid $ dx $ nresponse pctresponse; datalines; totreq pctreq COPD 18 0.20 totrem pctrem COPD 8800 99.80 totreq pctreq Control 5 0.52 totrem pctrem Control 949 99.48 totreq pctreq ILD 0 0 totrem pctrem ILD 8124 100 totreq pctreq Other 200 12.93 totrem pctrem Other 1546 87.07 ; run; data dx; set dx; format pctresponse percentn7.0; pctresponse=pctresponse/100; run; data anno_values; set dx; xsys='2'; ysys='3'; hsys='3'; when='a'; function='label'; position='5'; xc=dx; if nmid='totreq' then do; y=15; text=trim(left(nresponse)); output; end; if nmid='totrem' then do; y=7; text=trim(left(nresponse)); output; end; run; data anno_lines; length function $8 color $8 style $35; when='b'; color='cx989ea1'; /* vertical lines */ xsys='1'; x=0; ysys='1'; y=0; function='move'; output; xsys='1'; x=0; ysys='3'; y=2; function='draw'; output; xsys='1'; x=25; ysys='1'; y=0; function='move'; output; xsys='1'; x=25; ysys='3'; y=2; function='draw'; output; xsys='1'; x=50; ysys='1'; y=0; function='move'; output; xsys='1'; x=50; ysys='3'; y=2; function='draw'; output; xsys='1'; x=75; ysys='1'; y=0; function='move'; output; xsys='1'; x=75; ysys='3'; y=2; function='draw'; output; xsys='1'; x=100; ysys='1'; y=0; function='move'; output; xsys='1'; x=100; ysys='3'; y=2; function='draw'; output; xsys='3'; x=3; ysys='3'; y=18; function='move'; output; xsys='3'; x=3; ysys='3'; y=2; function='draw'; output; /* horizontal lines */ xsys='3'; x=3; ysys='3'; y=18; function='move'; output; xsys='1'; x=100; ysys='3'; y=18; function='draw'; output; xsys='3'; x=3; ysys='3'; y=10; function='move'; output; xsys='1'; x=100; ysys='3'; y=10; function='draw'; output; xsys='3'; x=3; ysys='3'; y=2; function='move'; output; xsys='1'; x=100; ysys='3'; y=2; function='draw'; output; /* white-out some of the lines behind the 'Frozen' label */ xsys='1'; x=10; ysys='3'; y=18.1; function='move'; output; xsys='1'; x=90; ysys='3'; y=27; function='box'; style='solid'; color='white'; output; /* labels to left of table */ function='label'; position='6'; color=''; style=''; xsys='3'; x=10; ysys='3'; y=15; text='Total requested'; output; xsys='3'; x=10; ysys='3'; y=7; text='Total remaining'; output; style='marker'; text='U'; xsys='3'; x=5; ysys='3'; y=15-.5; color="cxc6514a"; output; xsys='3'; x=5; ysys='3'; y=7-.5; color="cx4a82bd"; output; run; data anno_all; set anno_lines anno_values; run; pattern1 v=s c=cx4a82bd; pattern2 v=s c=cxc6514a; axis1 label=none order=(0 to 1 by 1) minor=none offset=(0,0); axis2 label=('Frozen') order=('ILD' 'COPD' 'Control' 'Other'); title1 a=90 h=20 ' '; /* blank space to the left of the bar chart */ footnote1 height=15pct ' '; /* blank space for the annotated table */ proc gchart data=dx anno=anno_all; vbar dx / type=sum sumvar=pctresponse subgroup=nmid nolegend raxis=axis1 maxis=axis2 coutline=gray77; run; quit; ODS HTML CLOSE; ODS LISTING;
Move to the modern graphing system - sgplot/GTL. Examples:
https://blogs.sas.com/content/?s=stacked
And you will find everything you ever wanted to know about graphs at:
Thanks. I think I found a solution. Here is some sample code I developed that is getting me to where I need to be (just need to add labels):
data dx;
input nmid $ pctmid $ dx $ nresponse pctresponse;
datalines;
totreq pctreq COPD 18 0.20
totrem pctrem COPD 8800 99.80
totreq pctreq Control 5 0.52
totrem pctrem Control 949 99.48
totreq pctreq ILD 0 0
totrem pctrem ILD 8124 100
totreq pctreq Other 200 12.93
totrem pctrem Other 1546 87.07
;
run; proc sort; by dx descending pctresponse; run;
ods graphics;
ods pdf file="X:\test1.pdf";
proc sgplot data=dx;
title 'Frozen specimens requested';
vbarparm category=dx response=pctresponse / group=pctmid dataskin=gloss;
xaxistable nresponse / class=nmid label labelpos=left location=inside;
xaxis display=(nolabel);
keylegend / location=inside position=topright;
yaxis offsetmax=0.1;
run;
ods pdf close;
Here's one way to do it with gchart and annotate:
%let name=bar_table; filename odsout '.'; goptions device=png; goptions border; ODS LISTING CLOSE; ODS HTML path=odsout body="&name..htm" style=htmlblue; goptions gunit=pct htitle=6 ftitle="albany amt/bold" htext=4.25 ftext="albany amt"; gopitons ctext=gray33; data dx; input nmid $ pctmid $ dx $ nresponse pctresponse; datalines; totreq pctreq COPD 18 0.20 totrem pctrem COPD 8800 99.80 totreq pctreq Control 5 0.52 totrem pctrem Control 949 99.48 totreq pctreq ILD 0 0 totrem pctrem ILD 8124 100 totreq pctreq Other 200 12.93 totrem pctrem Other 1546 87.07 ; run; data dx; set dx; format pctresponse percentn7.0; pctresponse=pctresponse/100; run; data anno_values; set dx; xsys='2'; ysys='3'; hsys='3'; when='a'; function='label'; position='5'; xc=dx; if nmid='totreq' then do; y=15; text=trim(left(nresponse)); output; end; if nmid='totrem' then do; y=7; text=trim(left(nresponse)); output; end; run; data anno_lines; length function $8 color $8 style $35; when='b'; color='cx989ea1'; /* vertical lines */ xsys='1'; x=0; ysys='1'; y=0; function='move'; output; xsys='1'; x=0; ysys='3'; y=2; function='draw'; output; xsys='1'; x=25; ysys='1'; y=0; function='move'; output; xsys='1'; x=25; ysys='3'; y=2; function='draw'; output; xsys='1'; x=50; ysys='1'; y=0; function='move'; output; xsys='1'; x=50; ysys='3'; y=2; function='draw'; output; xsys='1'; x=75; ysys='1'; y=0; function='move'; output; xsys='1'; x=75; ysys='3'; y=2; function='draw'; output; xsys='1'; x=100; ysys='1'; y=0; function='move'; output; xsys='1'; x=100; ysys='3'; y=2; function='draw'; output; xsys='3'; x=3; ysys='3'; y=18; function='move'; output; xsys='3'; x=3; ysys='3'; y=2; function='draw'; output; /* horizontal lines */ xsys='3'; x=3; ysys='3'; y=18; function='move'; output; xsys='1'; x=100; ysys='3'; y=18; function='draw'; output; xsys='3'; x=3; ysys='3'; y=10; function='move'; output; xsys='1'; x=100; ysys='3'; y=10; function='draw'; output; xsys='3'; x=3; ysys='3'; y=2; function='move'; output; xsys='1'; x=100; ysys='3'; y=2; function='draw'; output; /* white-out some of the lines behind the 'Frozen' label */ xsys='1'; x=10; ysys='3'; y=18.1; function='move'; output; xsys='1'; x=90; ysys='3'; y=27; function='box'; style='solid'; color='white'; output; /* labels to left of table */ function='label'; position='6'; color=''; style=''; xsys='3'; x=10; ysys='3'; y=15; text='Total requested'; output; xsys='3'; x=10; ysys='3'; y=7; text='Total remaining'; output; style='marker'; text='U'; xsys='3'; x=5; ysys='3'; y=15-.5; color="cxc6514a"; output; xsys='3'; x=5; ysys='3'; y=7-.5; color="cx4a82bd"; output; run; data anno_all; set anno_lines anno_values; run; pattern1 v=s c=cx4a82bd; pattern2 v=s c=cxc6514a; axis1 label=none order=(0 to 1 by 1) minor=none offset=(0,0); axis2 label=('Frozen') order=('ILD' 'COPD' 'Control' 'Other'); title1 a=90 h=20 ' '; /* blank space to the left of the bar chart */ footnote1 height=15pct ' '; /* blank space for the annotated table */ proc gchart data=dx anno=anno_all; vbar dx / type=sum sumvar=pctresponse subgroup=nmid nolegend raxis=axis1 maxis=axis2 coutline=gray77; run; quit; ODS HTML CLOSE; ODS LISTING;
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.