![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
Note: Bullet graphs were invented by dashboard expert Stephen Few and are described in detail in Chapter 6 of Information Dashboard Design (Sebastopol, CA: O'Reilly Media, Inc., 2006).
For a sample of an individual indicator, see Create a single bullet graph indicator for a dashboard.
For additional information about creating dashboard applications with SAS/GRAPH software, see SAS/GRAPH Dashboard Samples.
These sample files and code examples are provided by SAS Institute Inc. "as is" without warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability and fitness for a particular purpose. Recipients acknowledge and agree that SAS Institute shall not be liable for any damages whatsoever arising out of their use of this material. In addition, SAS Institute will provide no support for the materials contained herein.
/* This example uses SAS/GRAPH software to generate a bullet graph
dashboard, as described by in "Information Dashboard Design"
(Stephen Few. 2006. Sebastopol, CA. O'Reilly Media, Inc.). */
/* Specify the name for the output file. */
%let name=bulletGraphDashSTP;
/* Set output options. */
goptions reset=all;
goptions device=gif;
/* Define range colors for the bullet graphs. */
%let color1=gray88;
%let color2=graybb;
%let color3=graydd;
/* Define bar and background colors for the indicator. */
%let barcolor=black;
%let backcolor=white;
/* If you need more space for the labels on the left side of bullets,
add more B's to this string. */
%let blank=BBBBBBBBBBBBBBBBBBB;
/* Define fonts for indicator title and text. */
%let ftitle='swissb';
%let ftext='swissl';
/* Define the location of the HTML page that supplies drill-down details
for the indicator. If you don't have Internet access, you must put
the target HTML file where your browser can access it, then change the
following URL to point to your location. */
%let hardcoded_drilldown=http://support.sas.com/rnd/datavisualization/dashboards/generic_drilldown.htm;
/**************************************************************************/
/* The do_bullet macro creates an individual bullet graph indicator.
The do_bullet macro accepts the following list of parameters:
data_name = name of the data set that contains indicator values
pltname = name of GRSEG to store the graph
*/
%macro do_bullet(data_name,pltname);
%local data_name pltname;
goptions xpixels=500 ypixels=125 noborder;
data temp_data; set &data_name;
run;
/* Read values from the indicator data set into macro variables. */
proc sql noprint;
select range3 into :range3 from temp_data;
select by_value into :by_value from temp_data;
select unique value_format into :value_format from temp_data;
quit;
%let range3=%trim(&range3);
%let by_value=%trim(&by_value);
%let value_format=%trim(&value_format);
/* Set the 'tool tip' for the chart to provide a link to an
HTML page with drill-down details. */
data temp_data; set temp_data;
length myhtml $200;
myhtml='title='||quote(
'Value: '||trim(left(put(actual,&value_format)))||'0d'x||
'Target: '||trim(left(put(target,&value_format)))||
' ')||' '||
'href="'||"&hardcoded_drilldown"||'"';
run;
data myanno;
set temp_data;
length function $8 color $12 style $20 text $20;
hsys='3';
/* Annotate three colored areas (bars), representing the three 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="&color1";
output;
x=range1; y=0; function='move';
output;
x=range2; y=100; function='bar'; color="&color2";
output;
x=range2; y=0; function='move';
output;
x=range3; y=100; function='bar'; color="&color3";
output;
/* Annotate a thick line representing the target value. */
x=target; y=15; function='move';
output;
x=target; y=85; function='draw'; line=1; size=1.7; color="&barcolor";
output;
/* Annotate the midpoint value label to provide 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="&ftitle"; size=14; text=trim(left(mylabel));
output;
x=-2; y=30; function='label'; when='a'; position='4'; style="&ftext"; size=11; text=trim(left(mylabel2));
output;
run;
/* Draw the custom bullet graph (consisting of a bar chart with
annotated color ranges behind it and an annotated target marker
across the bar). */
goptions gunit=pct htitle=10 htext=9.5 ftitle=&ftitle ftext=&ftext;
goptions cback=&backcolor;
/* The offset to the right is important to guarantee that the bars will line up.
Style=0 makes the axis lines invisible. */
axis1 order=(0 to &range3 by &by_value) 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=&ftext height=9 color=&backcolor) offset=(7,7) style=0;
/* Set the bar color. */
pattern1 v=s color=&barcolor;
title;
footnote;
proc gchart data=temp_data anno=myanno;
format actual &value_format;
hbar blank / discrete
type=sum sumvar=actual
raxis=axis1 maxis=axis2
width=2.4 /* width of bar */
coutline=same
nolegend
nostats
noframe
html=myhtml
des=""
name="&pltname";
run;
quit;
%mend do_bullet;
/**************************************************************************/
/* Delete all GRSEGs in the current session to ensure that indicators use
the expected names. If a name is already in use, then an attempt to create
a new GRSEG using that name it will add a number to the name. In that case,
the subsequent GREPLAY will be placing the wrong GRSEGs into the dashboard.
Note: The macro code just checks whether there are any gsegs to delete. If
it tried to delete specific entries and none existed, then you would get an
error message: "ERROR: Member-name GSEG is unknown." */
%macro delcat(catname);
%if %sysfunc(cexist(&catname)) %then %do;
proc greplay nofs igout=&catname;
delete _all_;
run;
%end;
quit;
%mend delcat;
%delcat(work.gseg);
/**************************************************************************/
goptions border;
%let _GOPT_DEVICE=gif;
%let _ODSOPTIONS=gtitle gfootnote style=minimal;
%stpbegin;
goptions nodisplay;
goptions xpixels=600 ypixels=600;
/* Title Slide */
goptions gunit=pct htitle=4 ftitle=&ftitle htext=3 ftext=&ftitle;
title ls=2.5 "Bullet Graph Dashboard";
title2 ls=2 "2005 YTD";
proc gslide des="" name="titles" /* anno=titlanno */;
run;
/* The indicator data set must have the folllowing variables
because the macro is hard-coded to use them:
blank blank space to annotate bar labels
mylabel label beside bar
mylabel2 secondary label beside bar
target target is annotated as thick mark
actual value is length of black bar
by_value 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 do_bullet macro five times using five different data sets.
The resulting graphs will be saved into individual GRSEGs that can
later be replayed them into a custom template to get all five on
the same page. */
options mprint;
data mydata;
blank="&blank";
mylabel='Revenue';
mylabel2='U.S. $(1,000s)';
target=250;
actual=270;
by_value=50;
range1=150;
range2=225;
range3=300;
value_format='comma7.0';
run;
%do_bullet(mydata,plot1);
data mydata;
blank="&blank";
mylabel='Profit';
mylabel2='%';
target=.27;
actual=.225;
by_value=.05;
range1=.20;
range2=.25;
range3=.30;
value_format='percent5.0';
run;
%do_bullet(mydata,plot2);
data mydata;
blank="&blank";
mylabel='Avg Order Size';
mylabel2='U.S. $';
target=550;
actual=330;
by_value=100;
range1=350;
range2=500;
range3=600;
value_format='comma7.0';
run;
%do_bullet(mydata,plot3);
data mydata;
blank="&blank";
mylabel='New Customers';
mylabel2='Count';
target=2050;
actual=1750;
by_value=500;
range1=1400;
range2=2000;
range3=2500;
value_format='comma7.0';
run;
%do_bullet(mydata,plot4);
data mydata;
blank="&blank";
mylabel='Cust Satisfaction';
mylabel2='Top Rating of 5';
target=4.5;
actual=4.6;
by_value=1;
range1=3.5;
range2=4.3;
range3=5;
value_format='comma7.0';
run;
%do_bullet(mydata,plot5);
goptions display;
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 bullets 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 title slide and the individual bullet graphs into the
custom dashboard template. */
template = bullets;
treplay
0:titles
1:plot1
2:plot2
3:plot3
4:plot4
5:plot5
des=""
name="&name";
run;
quit;
%stpend;
These sample files and code examples are provided by SAS Institute Inc. "as is" without warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability and fitness for a particular purpose. Recipients acknowledge and agree that SAS Institute shall not be liable for any damages whatsoever arising out of their use of this material. In addition, SAS Institute will provide no support for the materials contained herein.
Source: Stephen Few, Information Dashboard Design (Sebastopol, CA: O'Reilly Media, Inc., 2006), 127.
| Type: | Sample |
| Topic: | SAS Reference ==> Procedures ==> GSLIDE SAS Reference ==> Procedures ==> GREPLAY SAS Reference ==> Procedures ==> GCHART Query and Reporting ==> Creating Reports ==> Graphical ==> Graph Types ==> Dashboards |
| Date Modified: | 2007-10-17 13:53:14 |
| Date Created: | 2006-12-23 03:03:01 |
| Product Family | Product | Host | Starting Release | Ending Release |
| SAS System | SAS/GRAPH | All | 9.1 TS1M3 | 9.1 TS1M3 |






