/* PROJECT MANAGEMENT USING THE SAS SYSTEM */ /* graphics options */ goptions cback=white ctext=black ctitle=black colors=(black red green blue) htext=2 htitle=3 gunit=pct ftext=swiss; /* PATTERN settings for color Gantt charts */ pattern1 c=black v=solid; pattern2 c=black v=empty; pattern3 c=red v=solid; pattern4 c=black v=l1; pattern5 c=black v=r1; pattern6 c=black v=l2; pattern7 c=blue v=l1; pattern8 c=green v=x2; pattern9 c=blue v=r2; /* PATTERN settings for black-and-white Gantt charts */ pattern1 c=black v=solid; pattern2 c=black v=empty; pattern3 c=black v=x2; pattern4 c=black v=l1; pattern5 c=black v=r1; pattern6 c=black v=l2; pattern7 c=black v=r2; pattern8 c=black v=l3; pattern9 c=black v=r3; /* PATTERN settings for color network diagrams */ pattern1 c=black v=empty; pattern2 c=red v=empty; /* PATTERN settings for black-and-white network diagrams */ pattern1 c=black v=empty; pattern2 c=black v=l1; /* pp. 10-11 */ data manuf; input task $ 1-26 success $ 27-52 days; cards; Unload Material Deliver to Production 2 Unload Material Record Shipment 2 Deliver to Production Prepare for Manufacturing 2 Prepare for Manufacturing Add Stock Material 4 Add Stock Material Update Records 5 Add Stock Material Start Production 5 Record Shipment Update Records 1 Update Records . 1 Start Production . 1 ; title 'Manufacturing Project'; proc netdraw data=manuf graphics; actnet / act=task successor=success pcompress separatearcs novcenter; run; /* pp. 11-12 */ proc cpm data=manuf date='01sep93'd interval=day out=mansched; activity task; successor success; duration days; run; proc print data=mansched; run; /* p. 13 */ proc gantt data=mansched graphics; chart / compress; id task; run; /* p. 14 */ proc netdraw data=mansched graphics; actnet / act=task successor=success pcompress separatearcs novcenter; run; /* pp. 24-26 */ title 'Book-Writing Project'; data books1; input jobnum task $ 4-14 succ1 $ 16-26 succ2 $ 28-35 succ3 $ 37-44; cards; 1 Plan Book Write P1 Write P2 Write P3 2 Write P1 Review1 P1 3 Write P2 Review1 P2 4 Write P3 Review1 P3 5 Review1 P1 Revise1 P1 6 Review1 P2 Revise1 P2 7 Review1 P3 Revise1 P3 8 Revise1 P1 Review2 P1 9 Revise1 P2 Review2 P2 10 Revise1 P3 Review2 P3 11 Review2 P1 Revise2 P1 12 Review2 P2 Revise2 P2 13 Review2 P3 Revise2 P3 14 Revise2 P1 Finalize P1 15 Revise2 P2 Finalize P2 16 Revise2 P3 Finalize P3 17 Finalize P1 Gloss/Index 18 Finalize P2 Gloss/Index 19 Finalize P3 Gloss/Index 20 Gloss/Index To Editing 21 To Editing ; data bookdesc; input jobnum descrpt $ 4-33 phase $ 35-44; cards; 1 Plan the Book Planning 2 Write Part 1 Writing 3 Write Part 2 Writing 4 Write Part 3 Writing 5 First Review of Part 1 Reviewing 6 First Review of Part 2 Reviewing 7 First Review of Part 3 Reviewing 8 First Revision of Part 1 Revising 9 First Revision of Part 2 Revising 10 First Revision of Part 3 Revising 11 Second Review of Part 1 Reviewing 12 Second Review of Part 2 Reviewing 13 Second Review of Part 3 Reviewing 14 Second Revision of Part 1 Revising 15 Second Revision of Part 2 Revising 16 Second Revision of Part 3 Revising 17 Final Revision of Part 1 Revising 18 Final Revision of Part 2 Revising 19 Final Revision of Part 3 Revising 20 Write Glossary and Index Writing 21 Send Finalized Book to Editing Production ; data books2; merge books1 bookdesc; by jobnum; run; proc print data=books2(obs=5); id jobnum; run; /* pp. 32-33 */ proc netdraw data=books2 graphics; actnet / activity=task successor=(succ1-succ3) pcompress separatearcs novcenter; run; /* pp. 33-34 */ proc netdraw data=books2 graphics; actnet / activity=task successor=(succ1-succ3) pcompress separatearcs novcenter zone=phase; run; /* pp. 36-37 */ data books1; input jobnum task $ 4-14 succ1 $ 16-26 succ2 $ 28-35 succ3 $ 37-44; cards; 1 Plan Book Write P1 Write P2 Write P3 2 Write P1 Review1 P1 3 Write P2 Review1 P2 4 Write P3 Review1 P3 5 Review1 P1 Revise1 P1 6 Review1 P2 Revise1 P2 7 Review1 P3 Revise1 P3 8 Revise1 P1 Review2 P1 9 Revise1 P2 Review2 P2 10 Revise1 P3 Review2 P3 11 Review2 P1 Revise2 P1 12 Review2 P2 Revise2 P2 13 Review2 P3 Revise2 P3 14 Revise2 P1 Finalize P1 15 Revise2 P2 Finalize P1 16 Revise2 P3 Finalize P3 17 Finalize P1 Gloss/Index 18 Finalize P2 Gloss/Index 19 Finalize P3 20 Glossary To Editing 21 To Editing ; run; proc netdraw data=books1 graphics; actnet / activity=task successor=(succ1-succ3) pcompress separatearcs novcenter; run; /* pp. 46-47 */ data bookinfo; input jobnum task $ 4-14 weeks writers revuwers; cards; 1 Plan Book 4 5 . 2 Write P1 8 2 . 3 Write P2 4 3 . 4 Write P3 9 5 . 5 Review1 P1 3 . 6 6 Review1 P2 3 . 6 7 Review1 P3 3 . 6 8 Revise1 P1 4 2 . 9 Revise1 P2 4 3 . 10 Revise1 P3 5 5 . 11 Review2 P1 2 . 6 12 Review2 P2 2 . 6 13 Review2 P3 2 . 6 14 Revise2 P1 2 2 . 15 Revise2 P2 2 3 . 16 Revise2 P3 3 5 . 17 Finalize P1 1 2 . 18 Finalize P2 1 3 . 19 Finalize P3 1 5 . 20 Gloss/Index 2 2 . 21 To Editing 0 . . ; run; data books3; merge books2 bookinfo; by jobnum; run; proc print data=books3(obs=5); id jobnum; run; /* pp. 48-53 */ data bookres; input obstype $ date : date7. writers revuwers; cards; restype . 1 1 reslevel 03feb92 5 6 ; proc cpm data=books3 date='03feb92'd interval=week out=bookcpm1 resourcein=bookres; activity task; successor succ1 succ2 succ3; duration weeks; id phase descrpt; resource writers revuwers / obstype=obstype period=date; baseline / set=resource; run; proc print data=bookcpm1; run; /* pp. 55-56 */ proc gantt data=bookcpm1 graphics; chart / compress mininterval=month hconnect duration=weeks; id descrpt; run; /* pp. 58-59 */ proc netdraw data=bookcpm1 graphics; actnet / act=task succ=(succ1-succ3) pcompress separatearcs novcenter zone=phase; run; /* pp. 63-64 */ proc cpm data=bookcpm1 date='03feb92'd interval=week out=bookcpm2 resourcein=bookres; activity task; successor succ1 succ2 succ3; duration weeks; id phase descrpt; resource writers revuwers / obstype=obstype period=date splitflag noe_start nol_start; baseline / compare=resource; run; proc print data=bookcpm2; var task segmt_no s_start s_finish b_start b_finish s_var f_var; run; /* pp. 65-66 */ proc gantt data=bookcpm2 graphics; chart / compress mininterval=month hconnect duration=weeks; id descrpt; run; /* pp. 67-68 */ proc netdraw data=bookcpm2 fullscreen; actnet / activity=task succ=(succ1-succ3); run; /* p. 70 */ proc netdraw data=bookcpm1 graphics; actnet / activity=task succ=(succ1-succ3) pcompress separatearcs novcenter zone=phase timescale align=s_start autoref nolabel; run; /* pp. 75-76 */ title 'Garment Industry Project'; data garments; input item $ task success cutter seamster presser inspectr mins desc $; cards; Shirts 11 12 1 . . . 45 Cut Pants 21 22 1 . . . 30 Cut T-shirts 31 32 1 . . . 20 Cut Shirts 12 13 . 1 . . 30 Stitch1 Pants 22 23 . 1 . . 20 Stitch1 T-shirts 32 34 . 1 . . 15 Stitch1 Shirts 13 15 1 1 . . 60 Detail Pants 23 25 1 1 . . 30 Detail T-shirts 34 36 . . 1 . 15 Apply Shirts 15 16 . 1 . . 25 Stitch2 Pants 25 26 . 1 . . 20 Stitch2 Shirts 16 17 . . 1 . 5 Press Pants 26 27 . . 1 . 5 Press T-shirts 36 37 . . 1 . 5 Press Shirts 17 18 . . . 1 5 Inspect Pants 27 28 . . . 1 5 Inspect T-shirts 37 38 . . . 1 3 Inspect Shirts 18 . . . . . 0 Ship Pants 28 . . . . . 0 Ship T-shirts 38 . . . . . 0 Ship ; proc sort data=garments; by item; run; proc print data=garments noobs; run; /* pp. 76-81 */ data garres; input type $ time time5. cutter seamster presser inspectr; cards; restype . 1 1 1 1 reslevel 08:00 1 1 1 1 ; proc cpm data=garments out=garcpm interval=minute resourcein=garres date='08:00't resourceout=gresout; activity task; successor success; duration mins; id item desc; resource cutter seamster presser inspectr / obstype=type period=time delayanalysis; run; proc print data=garcpm; run; proc sort data=garcpm out=garcpms; by item s_start; run; proc print data=garcpms; var desc s_start s_finish e_start e_finish l_start l_finish; by item; run; proc print data=gresout(obs=10); proc print data=gresout(firstobs=246 obs=256); run; /* pp. 82-83 */ symbol1 i=steplj w=3 l=1 c=black; symbol2 i=steplj w=3 l=33 c=black; symbol3 i=steplj w=3 l=20 c=black; legend1 label=('Schedule Followed') value=('Early' 'Late' 'Constrained') across=2; axis1 label=(angle=90 height=2 'Seamsters') minor=none; axis2 label=none order='08:00't to '12:30't by '00:30't; title2 'Usage of Seamsters'; proc gplot data=gresout; plot (eseamter lseamter rseamter) * _time_ / overlay vaxis=axis1 haxis=axis2 legend=legend1; run; /* pp. 85-86 */ proc gantt data=garcpm graphics; chart / compress dur=mins mininterval=hour nojobnum; id item desc; run; /* pp. 87-88 */ proc netdraw data=garcpm graphics; actnet / act=task succ=success zone=item pcompress novcenter timescale align=s_start mininterval=minute nodefid nolabel id=(desc); run; /* pp. 89-91 */ data garments; set garments; if item='Pants' then prty=1; else prty=2; run; proc cpm data=garments out=garcpm1 interval=minute resourcein=garres date='08:00't xfervars; activity task; successor success; duration mins; id item desc; resource cutter seamster presser inspectr / obstype=type period=time noe_start nol_start schedrule=actprty actprty=prty; baseline / set=resource; run; proc gantt data=garcpm1(drop=b_start b_finish) graphics; chart / compress dur=mins mininterval=hour nojobnum nolegend; id item desc; run; /* pp. 93-94 */ proc cpm data=garcpm1 out=garcpm2 interval=minute resourcein=garres date='08:00't; activity task; successor success; duration mins; id item desc; resource cutter seamster presser inspectr / obstype=type period=time noe_start nol_start schedrule=shortdur; baseline / compare=resource; run; proc gantt data=garcpm2 graphics; chart / compress dur=mins mininterval=hour nojobnum hconnect; id item desc; run; /* pp. 96-97 */ data garres1; input type $ time time5. cutter seamster presser inspectr; cards; restype . 1 1 1 1 reslevel 08:00 2 1 1 1 reslevel 09:00 . 3 . . ; run; proc cpm data=garments out=garcpm3 interval=minute resin=garres1 date='08:00't; activity task; successor success; duration mins; id item desc; resource cutter seamster presser inspectr / obstype=type period=time; run; proc gantt data=garcpm3 graphics; chart / compress dur=mins mininterval=hour nojobnum hconnect; id item desc; run; /* pp. 98-99 */ data garres2; input type $ time time5. cutter seamster presser inspectr; cards; restype . 1 1 1 1 reslevel 08:00 1 1 1 1 reslevel 11:00 0 0 . . reslevel 12:00 1 1 0 0 reslevel 13:00 . . 1 1 ; run; proc cpm data=garments out=garcpm4 interval=minute resin=garres2 date='08:00't; activity task; successor success; duration mins; id item desc; resource cutter seamster presser inspectr / obstype=type period=time noe_start nol_start; run; proc gantt data=garcpm4 graphics; chart / compress dur=mins mininterval=hour nojobnum; id item desc; run; /* pp. 103-108 */ title 'Research Project'; data grant1; input jobnum task $ 4-22 days succ1 $ 27-45 succ2 $ 47-59 aldate : date7. altype $ maxn; format aldate date7.; cards; 1 Design Exp 1 30 Recruit Exp 1 Subjs . . 1 2 Design Q1 25 Recruit Exp 1 Subjs . . 1 3 Recruit Exp 1 Subjs 20 Run Pilot 1 . . 2 4 Run Pilot 1 25 Analyze Pilot 1 . . 2 5 Analyze Pilot 1 5 Redesign Exp 1 . . 1 6 Redesign Exp 1 15 Run Exp 1 . . 2 7 Run Exp 1 50 Analyze Exp 1 . . 2 8 Analyze Exp 1 5 Discussion Mtg1 . . 1 9 Discussion Mtg1 0 Design Exp 2 Design Q2 . . 1 10 Design Exp 2 20 Recruit Exp 2 Subjs . . 1 11 Design Q2 13 Recruit Exp 2 Subjs . . 1 12 Recruit Exp 2 Subjs 20 Run Pilot 2 . . 2 13 Run Pilot 2 25 Analyze Pilot 2 . . 2 14 Analyze Pilot 2 5 Redesign Exp 2 . . 1 15 Redesign Exp 2 15 Run Exp 2 . . 2 16 Run Exp 2 60 Analyze Exp 2 . . 2 17 Analyze Exp 2 5 Discussion Mtg2 . . 1 18 Discussion Mtg2 0 Write Final Report . . 1 19 Write Final Report 20 . . 1 20 Annual Report 10 1sep93 mf 1 21 Site Visit 4 1jun93 ms 1 ; data gres; input jobnum cost; staff=1; cards; 1 80 2 . 3 . 4 50 5 . 6 . 7 100 8 . 9 . 10 80 11 . 12 . 13 60 14 . 15 . 16 120 17 . 18 . 19 . 20 . 21 . ; data grant2; merge grant1 gres; by jobnum; run; proc print data=grant2(obs=5); id jobnum; run; data grantin; input obstype $ date : date7. staff cost; format date date7.; cards; restype . 1 2 reslevel 01mar93 1 12000 reslevel 15sep93 2 . reslevel 01jan94 . 22000 ; data holidays; format holista date7. holifin date7.; input holista : date7. holifin : date7. name $ 17-32 @@; cards; 01jan93 01jan93 New Year's Day 09apr93 09apr93 Good Friday 31may93 31may93 Memorial Day 05jul93 05jul93 Independence Day 06sep93 06sep93 Labor Day 25nov93 26nov93 Thanksgiving 27dec93 31dec93 Christmas 01jan94 01jan94 New Year's Day 01apr94 01apr94 Good Friday 30may94 30may94 Memorial Day 04jul94 04jul94 Independence Day 05sep94 05sep94 Labor Day 24nov94 25nov94 Thanksgiving 26dec94 30dec94 Christmas ; proc cpm data=grant2 date='01mar93'd interval=weekday out=gcpm1 resourcein=grantin resourceout=gout1 holidata=holidays; activity task; successor succ1 succ2; duration days; id task; aligndate aldate; aligntype altype; holiday holista / holifin=holifin; resource staff cost / obstype=obstype period=date maxnsegmt=maxn cumusage; run; proc sort data=gcpm1 out=gcpmsort; by s_start; run; proc print data=gcpmsort; run; /* pp. 110-111 */ data gcpmtemp; set gcpm1; retain t_start; if segmt_no=. then t_start=s_start; run; proc sort data=gcpmtemp; by t_start; run; proc gantt data=gcpmtemp graphics holidata=holidays; chart / compress mininterval=month duration=days hconnect holidays=(holista) holifin=(holifin); id task; run; /* pp. 112-114 */ proc sort data=gcpm1 out=gcal1; by task; run; data gcal2; set gcal1; by task; if segmt_no = . and first.task ne last.task then delete; run; proc sort data=gcal2 out=gcal3(keep=task s_start s_finish cost); by s_start; run; proc calendar data=gcal3 holidata=holidays interval=workday; start s_start; fin s_finish; holistart holista; holifin holifin; holivar name; var task cost; format cost dollar8.2; run; /* pp. 115-117 */ data workdat; input s1 : time5. s2 : time5.; cards; 08:00 08:00 12:00 12:00 13:00 . 18:00 . ; data cal1; _cal_=1; _sun_='holiday'; _mon_='s1'; _tue_='s1'; _wed_='s1'; _thu_='s1'; _fri_='s1'; _sat_='s2'; d_length='08:00't; run; data grant3; set grant2; if task='Run Exp 1' or task='Run Exp 2' then _cal_=1; run; proc cpm data=grant3 date='01mar93'd interval=weekday out=gcpm2 resin=grantin holidata=holidays workdata=workdat caledata=cal1; activity task; successor succ1 succ2; duration days; id task; aligndate aldate; aligntype altype; holiday holista / holifin=holifin; resource staff cost / obstype=obstype period=date maxnsegmt=maxn; run; proc sort data=gcpm2 out=gcpm3; by s_finish; run; data gcpm3; set gcpm3 point=last nobs=last; output; stop; run; proc print data=gcpm3; var s_start s_finish; id task; run; /* pp. 118-121 */ data gact; input jobnum as : date7. af : date7. actcost pct; format as af date7.; cards; 1 04mar93 20apr93 80 . 2 21apr93 24may93 . . 3 25may93 24jun93 . . 4 25jun93 06aug93 61 . 5 09aug93 13aug93 . . 6 16aug93 20sep93 . . 7 21sep93 . 122 50 20 19aug93 01sep93 . . 21 01jun93 04jun93 . . ; data gmerge; merge grant2 gact; by jobnum; run; data grantin2; input obstype $ date : date7. staff cost actcost; format date date7.; cards; restype . 1 2 2 reslevel 01mar93 1 12000 12000 reslevel 15sep93 2 . . reslevel 01jan94 . 22000 22000 ; proc cpm data=gmerge date='01mar93'd interval=weekday out=gupdate resourcein=grantin2 holidata=holidays resourceout=guprout; activity task; successor succ1 succ2; duration days; id task; holiday holista / holifin=holifin; aligndate aldate; aligntype altype; resource staff cost actcost / obstype=obstype period=date maxnseg=maxn cumusage maxdate='01nov93'd; actual / a_start=as a_finish=af pctcomp=pct timenow='01nov93'd; run; proc print data=gupdate(drop=succ1 succ2); run; /* pp. 122-123 */ /* specify TIMENOW='01nov93'd in CHART statement to match Gantt chart */ proc sort data=gupdate; by s_start; run; proc gantt data=gupdate graphics holidata=holidays; chart / compress holidays=(holista) holifin=(holifin) mininterval=month duration=days hconnect combine ctnow=black ltnow=20; id task status; run; /* pp. 124-125 */ proc print data=gout1; run proc print data=guprout(firstobs=90 obs=100); run; /* pp. 126-128 */ /* Create C_BCWS */ data basecost(keep=_time_ c_bcws); set gout1; c_bcws=rcost; run; /* Merge the data sets, create C_BCWP and C_ACWP, */ /* create the DATE variable */ data gupdate2(keep=date c_bcws c_bcwp c_acwp); merge basecost guprout; by _time_; c_bcwp=rcost; c_acwp=ractcost; date=_time_; format date monyy.; run; legend1 value=(f=swiss c=black 'BCWS' 'BCWP' 'ACWP') label=(f=swiss c=black 'Legend:'); axis1 width=2 value=(f=swiss c=black) label=(f=swiss); axis2 width=2 value=(f=swiss c=black) label=(f=swiss); symbol1 i=join w=2 l=1 c=black; symbol2 i=join w=2 l=20 c=red; symbol3 i=join w=2 l=33 c=green; proc gplot data=gupdate2; title2 'Earned Value Chart'; label c_bcws='Dollars'; plot c_bcws*date=1 c_bcwp*date=2 c_acwp*date=3 / legend=legend1 overlay haxis=axis1 vaxis=axis2 hminor=0 vminor=4; run; proc gplot data=gupdate2; where date le '1nov93'd; title2 'Earned Value Chart'; label c_bcws='Dollars'; plot c_bcws*date=1 c_bcwp*date=2 c_acwp*date=3 / legend=legend1 overlay haxis=axis1 vaxis=axis2 hminor=0 vminor=4; run; /* pp. 129-130 */ /* create variances */ data gvars; set gupdate2; spendiff=c_acwp-c_bcwp; schediff=c_bcwp-c_bcws; totdiff=c_acwp-c_bcws; run; /* create plot of variances */ legend1 value=(f=swiss c=black 'Spending Variance' 'Schedule Variance' 'Total Variance') label=(f=swiss c=black 'Legend:'); axis1 width=2 order=('1mar93'd to '1nov93'd by month) value=(f=swiss c=black) label=(f=swiss); axis2 width=2 value=(f=swiss c=black) label=(f=swiss) order=(-1000 to 1000 by 500); symbol1 i=join w=2 l=1 c=black; symbol2 i=join w=2 l=20 c=red; symbol3 i=join w=2 l=33 c=green; proc gplot data=gvars; title2 'Plot of Variances'; label spendiff='Variance'; plot spendiff*date=1 schediff*date=2 totdiff*date=3 / legend=legend1 overlay haxis=axis1 vaxis=axis2 vminor=4; run; /* pp. 132-133 */ data grantfin; input year $ account $ budget actual; cards; 1993 Salaries 35000 18300 1994 Salaries 27600 0 1993 Contract 2400 2640 1994 Contract 1600 0 1993 Pilot1 1250 1830 1993 Exp1 5000 0 1994 Pilot2 1500 0 1994 Exp2 7200 0 1993 Overhead 2500 1135 1994 Overhead 2500 0 ; proc report data=grantfin; run; /* p. 134 */ data bardata; set grantfin; format account $12. budget dollar8.; run; pattern1 v=s c=black; proc gchart data=bardata; title2 'Cost Breakdown'; hbar account / sumvar=budget sum; run;