%let name=commute_time; filename odsout '.'; %let shadow_color=gray33; %let outline_color=gray55; %let red_color=Aef537577; /* v9.3 alpha-transparent version of red pie color */ %let grn_color=A00ff0077; /* green */ %let red_color=cxef5375; /* red */ %let grn_color=cx00dd00; /* green */ %let max_area=40; /* size of maximum annotated pie */ /* trying to make a better version of: http://awesome.good.is/transparency/web/1009/sprawl-crawl/flat.html using data from: http://www.ceosforcities.org/research/driven-apart (link along right-hand side, then go to p. 48) */ data my_data (drop=whole_line numbers); infile datalines pad truncover; input whole_line $ 1-100; length city_state $50; city_state=trim(left(scan(whole_line,1,':'))); length city $45; city=trim(left(scan(city_state,1,','))); length state $3; state=trim(left(scan(city_state,2,','))); length numbers $100; numbers=scan(whole_line,2,':'); format population peak_travelers comma10.0; population=input(scan(numbers,1,' '),comma10.0); peak_travelers=input(scan(numbers,2,' '),comma10.0); travel_time_index=.; travel_time_index=scan(numbers,3,' '); hours_of_delay=.; hours_of_delay=scan(numbers,4,' '); total_hours=.; total_hours=scan(numbers,5,' '); uncongested_travel=.; uncongested_travel=scan(numbers,6,' '); miles=.; miles=scan(numbers,7,' '); intrix_tti=.; intrix_tti=scan(numbers,8,' '); format percent_congested percent7.1; percent_congested=hours_of_delay/total_hours; datalines; Boston, MA : 4,200 2,113 1.26 43 208 165 19.8 1.18 Hartford, CT : 895 489 1.12 21 196 175 19.9 1.10 New York, NY : 18,225 8,602 1.37 44 163 119 18.9 1.45 Philadelphia, PA : 5,310 2,947 1.28 38 174 136 17.4 1.14 Washington, DC : 4,330 2,174 1.39 62 221 159 21.5 1.28 Virginia Beach, VA : 1,545 865 1.18 29 190 161 18.0 1.15 Richmond, VA : 935 514 1.09 20 242 222 22.5 1.03 Raleigh, NC : 1,025 574 1.17 34 234 200 22.2 1.06 Charlotte, NC : 1,070 599 1.25 40 200 160 19.1 1.13 Pittsburgh, PA : 1,815 1,016 1.09 15 182 167 15.8 1.10 Cleveland, OH : 1,790 995 1.08 12 162 150 16.3 1.06 Columbus, OH : 1,225 686 1.18 30 197 167 19.9 1.05 Cincinnati, OH: 1,670 949 1.18 25 164 139 17.7 1.07 Indianapolis, IN : 1,070 599 1.21 39 225 186 22.6 1.05 Louisville, KY : 915 503 1.20 38 228 190 21.7 1.05 Atlanta, GA : 4,400 2,371 1.35 57 220 163 21.6 1.18 Birmingham, AL: 715 393 1.15 32 245 213 23.3 1.04 Buffalo, NY : 1,125 540 1.07 11 168 157 16.6 1.04 Dallas, TX : 4,445 2,645 1.32 53 219 166 20.9 1.15 Denver, CO : 2,180 1,358 1.31 45 190 145 17.0 1.11 Detroit, MI : 4,050 2,268 1.29 52 231 179 20.9 1.15 Houston, TX : 3,185 2,232 1.33 56 226 170 22.1 1.18 Jacksonville, FL : 1,040 582 1.23 39 209 170 20.5 1.10 Kansas City, KS : 1,525 854 1.07 15 229 214 21.6 1.06 Las Vegas, NV : 1,405 787 1.30 44 191 147 17.6 1.07 Los Angeles, CA : 12,800 6,976 1.49 70 213 143 21.1 1.29 Memphis, TN : 1,035 580 1.12 25 233 208 20.7 1.06 Miami, FL : 5,420 3,095 1.37 47 174 127 16.5 1.21 Milwaukee, WI : 1,465 804 1.13 18 156 138 17.2 1.08 Chicago, IL : 8,440 4,566 1.43 41 136 95 13.5 1.23 Minneapolis, MN : 2,525 1,414 1.24 39 202 163 20.1 Nashville, TN : 995 547 1.15 37 284 247 25.2 1.17 New Orleans, LA : 1,100 579 1.17 20 138 118 12.6 1.10 Oklahoma City, OK: 875 481 1.12 27 252 225 24.1 1.05 Orlando, FL : 1,405 787 1.30 53 230 177 20.9 1.08 Phoenix, AZ : 3,425 1,829 1.30 44 191 147 19.4 1.12 Portland, OR : 1,800 931 1.29 37 165 128 16.0 1.20 Sacramento, CA : 1,860 1,001 1.32 39 161 122 16.2 1.10 Salt Lake City, UT : 975 536 1.19 27 169 142 16.0 1.05 San Antonio, TX : 1,450 812 1.23 38 203 165 20.2 1.09 San Diego, CA : 2,950 1,652 1.37 52 193 141 19.8 1.24 San Francisco, CA : 4,480 2,339 1.42 55 186 131 19.5 1.31 Seattle, WA : 3,100 1,696 1.29 43 191 148 18.8 1.29 Saint Louis, MO : 2,215 1,240 1.13 26 226 200 20.7 1.08 Tampa, FL : 2,320 1,299 1.31 47 199 152 17.8 1.12 ; run; /* Map was too crowded, so I took a few out: Rochester, NY : 745 410 1.06 10 177 167 14.9 1.04 Baltimore, MD : 2,320 1,299 1.31 44 186 142 18.8 1.14 Providence, RI : 1,245 682 1.17 29 200 171 18.2 1.10 New Haven, CT : 560 308 1.11 19 192 173 20.3 1.12 Austin, TX : 1,035 580 1.29 39 173 134 16.2 1.28 Riverside, CA : 2,030 1,102 1.36 44 166 122 18.2 1.20 San Jose, CA : 1,705 955 1.36 53 200 147 19.0 1.22 */ /* proc sort data=my_data out=my_data; by descending total_hours; run; */ /* Find the maximum value */ proc sql; select max(total_hours) format=comma8.0 into :max_hours from my_data; quit; run; proc geocode CITY lookup=sashelp.zipcode data=my_data out=my_data; run; data bad; set my_data (where=(x=. and y=.)); run; /* proc geocode needed a character state, but my gproject will need a numeric state */ proc datasets; modify my_data; rename state = char_state; run; data my_data; set my_data; x=atan(1)/45 * (-1*x); y=atan(1)/45 * y; if x^=. and y^=. then output; run; data anno_dots; set my_data; anno_flag=1; run; data states; set maps.states (where=((density<=2) and (fipstate(state) not in ('HI' 'AK' 'PR')))); run; /* project the map & annotate data */ data combined; set states anno_dots; run; proc gproject data=combined out=combined dupok; id state; run; data states anno_dots; set combined; if anno_flag=1 then output anno_dots; else output states; run; /* Create annotate 'dot' and chart-tip info for the city */ data anno_dots; length function style $8 color $12 position $ 1 text $ 20 html $1024; retain xsys ysys '2' hsys '3' when 'a'; set anno_dots; function='pie'; style='psolid'; /* var city_state hours_of_delay uncongested_travel total_hours; */ /* Scale data values to dot areas, and calculate the radius (size) for the areas */ area=(total_hours/&max_hours)*&max_area; size=.3 + sqrt(area/3.14); angle=0; /* start angle (3pm position) */ color="&red_color"; rotate=360*(hours_of_delay/(hours_of_delay+uncongested_travel)); output; angle=angle+rotate; /* start position for 2nd slice */ color="&grn_color"; rotate=360*(uncongested_travel/(hours_of_delay+uncongested_travel)); output; /* draw empty outline/border around the dot */ /* only put the url charttip on the outermost outline/border pie */ html= 'title='|| quote( trim(left(city))||', '||trim(left(char_state))||'0d'x|| trim(left(total_hours))||' annual hours commuting'||'0d'x|| '('||trim(left(put(percent_congested,percent7.1)))||' in traffic jams)' ); color='black'; style='pempty'; rotate=360; output; /* draw a point in the center */ color='black'; size=.1; output; run; data anno_stuff; set anno_dots; run; /* Create an annotate dataset, where each of the states is just a gray filled polygon -- when='b' draws this behind/before the real map */ /* First, get rid of the multiple segments per state */ data states; set states; orig_order+1; run; proc sort data=states out=states; by state segment orig_order; run; proc gremove data=states out=shadow_anno; by state; id state; run; data shadow_anno; length COLOR FUNCTION $ 8; retain FX FY FUNCTION; set shadow_anno; by state segment; xsys='2'; ysys='2'; color="&shadow_color"; size=1.75; when='B'; style='msolid'; if first.segment then do; FUNCTION = 'poly'; FX = X; FY = Y; end; else if FUNCTION ^= ' ' then do; if X = . then do; X = FX; Y = FY; output; FUNCTION = ' '; end; else FUNCTION = 'polycont'; end; if FUNCTION ^= ' ' then do; output; if last.segment then do; X = FX; Y = FY; output; end; end; run; /* Give a little x & y offset, so it will look like a shadow */ data shadow_anno; set shadow_anno; x=x-.0015; y=y-.0015; run; goptions device=png xpixels=1000 ypixels=730; goptions border; ODS LISTING CLOSE; /* ODS HTML path=odsout body="&name..htm" (title="Commute Time") style=htmlblue options(pagebreak='no'); */ ods html3 path=odsout body="&name..htm" (title="Commute Time") headtext="" style=htmlblue options(pagebreak='no'); goptions gunit=pct htitle=3.75 htext=2.9 ftitle="arial/bo" ftext="arial/bold"; pattern1 v=s c=white; title1 ls=1.5 "Total Annual Commuting Hours per person"; title2 ls=1.1 c=cx00dd00 "Uncongested Time" c=black " and " c=cxef5375 "Time in Traffic Jams"; footnote1 c=gray font="arial" height=2.25 j=l link="http://www.ceosforcities.org/research/driven-apart" " Data Source: 2010 ceosforcities.org " j=r link='commute_time_info.htm' " All values are yearly hours per traveler " ; proc gmap data=states map=states anno=anno_stuff; id state; choro state / levels=1 coutline=&outline_color anno=shadow_anno nolegend des="" name="&name"; run; title "Bad data - not able to geocode"; proc print data=bad; run; run; proc sort data=my_data out=my_data; by descending percent_congested; run; title; footnote; /* proc print data=my_data noobs label; label city_state='City'; label total_hours='Total Annual Hours Commuting'; label percent_congested='Percent Spent in Traffic Jams'; var city_state total_hours percent_congested; run; */ /* quit; ODS HTML CLOSE; ODS LISTING; */ data my_data; set my_data; format pct_congested comma5.1; pct_congested=percent_congested*100; run; title1 c=black h=11pt "Click column headers to sort table by that column"; proc report data=my_data nowd style(report)={htmlstyle="behavior:url(./tablesort.htc)"}; label city_state='City'; label total_hours='Total Annual Hours Commuting'; label pct_congested='Percent Spent in Traffic Jams'; column city_state total_hours pct_congested; define city_state / style(header)={tagattr='type="CaseInsensitiveString"'}; define total_hours / style(header)={tagattr='type="Number"'}; define pct_congested / style(header)={tagattr='type="Number"'}; run; quit; ods html3 close; ods listing;