%let name=bdash1; filename odsout '.'; /* SAS Imitation of Stephen Few's "bullet graph" dashboard ... */ /* First, define a macro that will do the individual bullet graphs. The parameters are a dataset name (the dataset must contain certain variables, a name (pltname) to store the grseg in, and the format for the charttip. */ %macro bullet(mydata,pltname,fmt); %local mydata pltname fmt; goptions xpixels=500 ypixels=170 noborder; /* Grab some values out of the data, so you can use them as macro variables... */ proc sql noprint; select range3 into :range3 from mydata; select byval into :byval from mydata; quit; run; /* Define the html mouse-over charttip */ data mydata; set mydata; length myhtml $200; myhtml= 'title='||quote( 'Value: '||trim(left(put(myvalue,&fmt)))||'0d'x|| 'Goal: '||trim(left(put(mygoal,&fmt))))|| ' href="bdash1_info.htm"'; run; data myanno; set mydata; length function $8 color $12 style $35 text $20; hsys='3'; /* Annotate 3 colored areas (bars), representing the 3 ranges of values. Use when='b' so these will show up 'behind' the real bar chart bar. */ xsys='2'; ysys='1'; style='solid'; when='b'; x=0; y=0; function='move'; output; x=range1; y=100; function='bar'; color='gray88'; output; x=range1; y=0; function='move'; output; x=range2; y=100; function='bar'; color='graybb'; output; x=range2; y=0; function='move'; output; x=range3; y=100; function='bar'; color='graydd'; output; /* Annotate a thick line, representing the 'goal' value */ x=mygoal; y=15; function='move'; output; x=mygoal; y=85; function='draw'; line=1; size=1.7; color='black'; output; /* Annotate the midpoint value label, so you'll have the flexibility to easily place multiple lines of text. */ xsys='1'; ysys='1'; x=-2; y=85; function='label'; when='a'; position='4'; style='albany amt/bold'; size=15; text=trim(left(mylabel1)); output; x=-2; y=30; function='label'; when='a'; position='4'; style=''; size=11; text=trim(left(mylabel2)); output; run; goptions gunit=pct htitle=16 htext=10 ftitle="albany amt/bold" ftext="albany amt"; /* The offset to the right is important in guaranteeing the bars will line up. Style=0 makes the axis lines invisible. */ axis1 order=(0 to &range3 by &byval) major=(height=3) minor=none label=none offset=(0,9) style=0; /* The offset here makes more room for the shaded area to be visible above and below the bar */ axis2 label=none value=(font="albany amt/bold" height=9 color=white) offset=(7,7) style=0; /* Bar color */ pattern1 v=s color=black; title; footnote; proc gchart data=mydata anno=myanno; hbar blank / discrete type=sum sumvar=myvalue raxis=axis1 maxis=axis2 width=3.7 /* width of bar */ coutline=same nolegend nostats noframe html=myhtml name="&pltname"; run; %mend bullet; goptions nodisplay; goptions device=png; goptions border; ODS LISTING CLOSE; ODS HTML path=odsout body="&name..htm" (title="Stephen Few's Bullet Graph Dashboard - A SAS/Graph Chart") style=htmlblue; goptions nodisplay; goptions xpixels=600 ypixels=600; /* Title Slide */ goptions gunit=pct htitle=4 ftitle="albany amt/bold" htext=3 ftext="albany amt/bold"; title1 ls=2.5 "Bullet Graph Dashboard"; title2 ls=2 "2005 YTD"; proc gslide name="titles" /* anno=titlanno */; run; /* Call the bullet macro for each bullet graph. Note that the data set must have these variable names, because the macro is hard-coded to use them. blank blank space where I annotate bar labels mylabel1 label which I annotate beside bar mylabel2 secondary label I annotate beside bar mygoal goal is annotated as thick mark myvalue value is length of black bar byval by-value for axis tickmarks range1 max value of dark gray area range2 max value of middle gray area range3 max value of light gray area (also end of raxis) */ /* Call the bullet macro 5 times, using 5 different data sets. The resulting graph will be saves in a grseg, and then you will later greplay them into a custom greplay template to get all 5 on the same page. */ data mydata; format myvalue comma7.0; blank='BBBBBBBBBBBB'; mylabel1='Revenue'; mylabel2='U.S. $(1,000s)'; mygoal=250; myvalue=270; byval=50; range1=150; range2=225; range3=300; ; run; %bullet(mydata,plot1,comma7.0); data mydata; format myvalue percent5.0; blank='BBBBBBBBBBBB'; mylabel1='Profit'; mylabel2='%'; mygoal=.27; myvalue=.225; byval=.05; range1=.20; range2=.25; range3=.30; ; run; %bullet(mydata,plot2,percent5.0); data mydata; format myvalue comma7.0; blank='BBBBBBBBBBBB'; mylabel1='Avg Order Size'; mylabel2='U.S. $'; mygoal=550; myvalue=330; byval=100; range1=350; range2=500; range3=600; ; run; %bullet(mydata,plot3,comma7.0); data mydata; format myvalue comma7.0; blank='BBBBBBBBBBBB'; mylabel1='New Customers'; mylabel2='Count'; mygoal=2050; myvalue=1750; byval=500; range1=1400; range2=2000; range3=2500; ; run; %bullet(mydata,plot4,comma7.0); data mydata; format myvalue comma7.0; blank='BBBBBBBBBBBB'; mylabel1='Cust Satisfaction'; mylabel2='Top Rating of 5'; mygoal=4.5; myvalue=4.6; byval=1; range1=3.5; range2=4.3; range3=5; ; run; %bullet(mydata,plot5,comma7.0); goptions display; goptions border; goptions xpixels=600 ypixels=600; /* Create a custom greplay template. 0 = whole screen (for the title slide) 1-5 = spaces for the 5 bullet graphs) */ proc greplay tc=tempcat nofs igout=work.gseg; tdef rdpgrid des='Bullet Dashboard' 0/llx = 0 lly = 0 ulx = 0 uly =100 urx =100 ury =100 lrx =100 lry = 0 1/llx = 0 lly = 68 ulx = 0 uly = 85 urx =100 ury = 85 lrx =100 lry = 68 2/llx = 0 lly = 51 ulx = 0 uly = 68 urx =100 ury = 68 lrx =100 lry = 51 3/llx = 0 lly = 34 ulx = 0 uly = 51 urx =100 ury = 51 lrx =100 lry = 34 4/llx = 0 lly = 17 ulx = 0 uly = 34 urx =100 ury = 34 lrx =100 lry = 17 5/llx = 0 lly = 0 ulx = 0 uly = 17 urx =100 ury = 17 lrx =100 lry = 0 ; run; /* Replay the 5 bullet graphs, and the title slide, into the custom greplay template. */ template = rdpgrid; treplay 0:titles 1:plot1 2:plot2 3:plot3 4:plot4 5:plot5 des='' name="&name"; run; quit; ODS HTML CLOSE; ODS LISTING;