%let name=hurricane; filename odsout '.'; /* This is very useful to set up in sas/intrnet, so these 2 macro vbls can be passed in dynamically. Here's a link to my intrnet version (on the sas internal web)... http://sww.sas.com/~realliso/tests/v9/cgi/hurricane.html */ %let hurname=betsy; %let huryear=1965; /* Guarantee that the hurricane name is in upper-case */ %let uhurname=%upcase(&hurname); libname here '.'; /* Run this once, and after that use the copy you saved the 1st time. This reduces the resolution (and therefore the number of obsns) in the map, and makes the program run a lot faster. */ /* data here.allmap; set maps.namerica maps.samerica (where=(lat gt 0)) ; run; proc greduce data=here.allmap out=here.allmap; id id; run; data here.allmap; set here.allmap (where = (density <= 2)); run; */ proc sql; create table allmap as select long as x, lat as y, segment, id from here.allmap; /* Add html title= chart tips with the county name */ proc sql; create table my_mapdata as select unique id from allmap; quit; run; options fmtsearch=(sashelp.mapfmts); data my_mapdata; set my_mapdata; length htmlvar $1024; htmlvar= 'title='||quote( trim(left(put(id,glcnsm.))) ); run; /* Read in the hurricane data, dynamically from the website */ filename caneurl url "http://weather.unisys.com/hurricane/atlantic/&huryear/&uhurname/track.dat" proxy='http://inetgw.fyi.sas.com:80'; data canedata; /* skip the 1st 3 lines of header info, data starts on line 4 */ infile caneurl dlm=',' firstobs=4 lrecl=80 pad; input foo $ 1-80; name=trim(left("&hurname")); year=trim(left("&huryear")); adv=scan(foo,1,' '); lat=0; lat=scan(foo,2,' '); long=0; long=scan(foo,3,' '); datetime=scan(foo,4,' '); date=substr(datetime,1,5); time=scan(datetime,3,'/'); wind=0; wind=scan(foo,5,' '); /* Don't really need pressure, and it's often '-', which is invalid numeric */ /* pr=0; pr=scan(foo,6,' '); */ stat=substr(foo,39,30); if index(adv,'+') ne 0 then stat='*PREDICTED* '||trim(left(stat)); run; data canedata; set canedata; x=atan(1)/45 * -1*long; y=atan(1)/45 * lat; run; data circle_anno; length function style color $ 8 position $ 1 text $ 20 html $1024; retain xsys ysys '2' hsys '3' when 'a'; set canedata; anno_flag=1; position='5'; size=(wind/100)*6; /* An annotated circle/pie is more accurate than a weather font character, but the weather hurricane symbol looks nicer, so I'm using that. */ /* function='pie'; rotate=360; style='pempty'; */ function='label'; style='weather'; text='L'; /* It it has 'HURRICANE' in the status, then make the graphic red */ if index(upcase(stat),'HURRICANE') ne 0 then color='red'; else color='cx0000ff'; /* This is the html title= charttip and href= drilldown for the hurricane markers */ html= 'title='||quote( 'Status: '||trim(left(stat))||'0d'x|| 'Latitude: '||trim(left(lat))||'0d'x|| 'Longitude: '||trim(left(long))||'0d'x|| 'Date (mm/dd): '||trim(left(date))||'0d'x|| 'Time (gmt/zulu): '||trim(left(time))||'0d'x|| 'Wind: '||trim(left(wind))|| ' ')|| ' '|| 'href="http://www.google.com/search?hl=en&ie=UTF-8&q=hurricane+'||trim(left(name))||'+'||trim(left(year))||'"'; output; run; /* Blue rectangle behind map area */ /* Along certain edges, I had to use these .01 offsets, because gproject clipping was trimming off the edge otherwise */ data blue_anno; length function style color $ 8; retain xsys ysys '2' hsys '3' when 'b'; anno_flag=1; color='cxccffff'; style='msolid'; function='poly'; long=45; lat=5+.01; output; function='polycont'; lat=5+.01; do long=45 to 100 by 5; output; end; long=99.99; do lat=5+5 to 45 by 5; output; end; lat=45; do long=100 to 45 by -5; output; end; long=45; do lat=45 to 5+5 by -5; output; end; long=45; lat=5+.01; output; run; data blue_anno; set blue_anno; x=atan(1)/45 * long; y=atan(1)/45 * lat; run; /* Annotate the longitude/latitude grid lines */ %let min_long=50; %let max_long=95; %let min_lat=10; %let max_lat=40; data grid_anno; length function style color $ 8; retain xsys ysys '2' hsys '3' when 'a'; anno_flag=1; do long = &min_long to &max_long by 5; function='label'; color='black'; longitude=long; latitude=&min_lat; degrees=abs(int(long)); minutes=abs((long-int(long))*60); text=trim(left(degrees))||'B0'x; position='a'; size=2.5; angle=90; output; color='gray'; size=.1; line=33; function='move'; longitude=long; latitude=&min_lat; output; do lat = &min_lat to &max_lat by 5; function='draw'; longitude=long; latitude=lat; output; end; end; do lat = &min_lat to &max_lat by 5; function='label'; color='black'; longitude=&min_long; latitude=lat; degrees=abs(int(lat)); minutes=abs((lat-int(lat))*60); text=trim(left(degrees))||'B0'x; position='c'; size=2.5; angle=0; output; color='gray'; size=.1; line=33; function='move'; latitude=lat; longitude=&min_long; output; do long = &min_long to &max_long by 5; function='draw'; latitude=lat; longitude=long; output; end; end; run; data grid_anno; set grid_anno; x=atan(1)/45 * longitude; y=atan(1)/45 * latitude; run; data all_anno; set circle_anno grid_anno blue_anno; run; /* project the map */ /* See examples of projections here ... http://www.progonos.com/furuti/MapProj/Normal/ProjTbl/projTbl.html */ data combined; set allmap all_anno; run; proc gproject data=combined out=combined dupok project=robinson /* project=lambert project=mercator project=gnomon project=albers */ longmax=100 longmin=45 latmax=45 latmin=5 ; id id; run; data my_map all_anno; set combined; if anno_flag=1 then output all_anno; else output my_map; run; GOPTIONS DEVICE=gif; ODS LISTING CLOSE; ODS HTML path=odsout body="&name..htm" (title="Tracking Hurricane &uhurname") style=minimal gtitle gfootnote ; goptions gunit=pct htitle=6 htext=4 ftitle="arial" ftext="arial" ctitle='white' ctext='white' /* ctitle='cx8bbbed' ctext='cx8bbbed' */ ; goptions border cback=cx3366cc; title link="http://teacher.scholastic.com/activities/wwatch/hurricanes/extreme/track.htm" "Tracking Hurricane &uhurname in &huryear"; /* Getting a little tricky with this title ;) */ title2 a=-90 r=180 "edutitaL"; footnote "Longitude"; pattern v=s c=cxffcc33 r=100; proc gmap map=my_map data=my_mapdata anno=all_anno; id id; choro id / coutline=gray nolegend discrete html=htmlvar des="" name="&name"; run; quit; ODS HTML CLOSE; ODS LISTING;