%let name=wafer1; filename odsout '.'; goptions reset=global; /* Create the 'map' dataset. */ data work.wafermap; length id $ 20; do grid_y=1 to 33; do grid_x=1 to 33; id=trim(left(grid_x))||'_'||trim(left(grid_y)); x=grid_x*10-10; y=grid_y*10-10; output; x=x+10; output; y=y+10; output; x=x-10; output; end; end; run; /* Annotate a gray circular polygon behind the grid */ data work.outlines; length function color $ 8 text $ 30; xsys='2'; ysys='2'; hsys='3'; when='b'; size=1; /* line thickness */ style='msolid'; color='graybb'; /* make sure this color matches the coutline */ radius=(33*10)/2; x_circle_origin=0+(33*10)/2; y_circle_origin=0+(33*10)/2; do degrees=0 to 360 by 5; if degrees eq 0 then function='poly'; else function='polycont'; radians=degrees/57.3; x=(radius * cos(radians)) + x_circle_origin; y=(radius * sin(radians)) + y_circle_origin; output; end; run; /* Here is my data, imitating the data from IDS's webpage */ data work.rawdata; input value @@; cards; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 50 50 50 50 50 50 10 30 . . . . . . . . . . . . . . . . . . . . . . 50 50 50 50 50 70 70 70 90 50 70 50 50 50 . . . . . . . . . . . . . . . . . 30 30 70 30 50 50 70 50 70 70 50 50 70 50 50 50 50 . . . . . . . . . . . . . . . 70 70 70 70 30 50 30 50 50 30 30 50 70 70 50 50 70 50 50 . . . . . . . . . . . . . 30 50 50 50 70 70 70 30 50 30 30 30 50 50 70 50 70 70 70 70 50 30 . . . . . . . . . . 70 50 70 70 70 50 70 70 70 50 30 50 30 50 30 70 70 70 70 50 50 50 50 . . . . . . . . . 50 50 70 90 90 70 70 90 90 70 50 50 30 50 50 50 30 50 50 70 70 70 70 70 50 . . . . . . . . 50 70 70 70 70 70 70 70 50 50 50 50 30 50 50 50 30 50 70 50 50 50 70 50 30 70 . . . . . . 50 50 70 50 70 70 70 50 70 70 70 50 50 50 30 50 30 30 50 50 70 70 70 70 70 50 50 . . . . . . 30 70 70 70 70 70 90 70 70 70 50 50 50 30 30 50 50 70 50 70 70 50 70 70 70 50 50 50 . . . . 30 70 50 70 70 70 70 70 50 90 70 70 50 70 50 50 50 50 70 50 50 70 70 70 70 70 70 70 70 . . . . 70 70 70 70 70 90 70 70 70 70 70 70 70 50 50 70 50 50 30 50 50 50 50 50 70 70 70 50 50 . . . . 70 70 70 70 90 70 70 70 90 90 70 70 70 70 50 50 50 50 50 50 50 50 30 50 50 50 70 70 50 30 . . . 50 50 70 90 70 70 70 90 90 90 90 90 70 50 70 70 70 50 70 50 70 50 90 70 50 70 50 70 50 50 . . . 30 70 90 70 70 90 70 90 90 90 90 70 90 70 70 70 50 50 50 70 50 50 50 70 50 50 70 50 50 50 . . . 50 50 70 90 70 70 90 70 70 90 70 70 70 70 70 70 70 50 70 50 70 70 70 70 50 70 50 50 30 10 . . . 50 70 70 90 90 90 90 70 90 90 70 90 70 90 90 70 70 90 90 70 50 70 70 70 50 50 50 50 30 10 . . . 30 50 90 90 70 90 90 70 90 90 90 90 90 70 70 70 70 70 70 70 50 70 70 50 70 50 30 50 30 30 . . . 30 70 50 90 70 70 70 90 70 90 90 70 50 70 70 70 70 70 70 50 50 50 70 70 50 50 50 50 30 . . . . . 30 70 70 90 70 90 70 70 90 70 70 70 90 70 70 50 70 50 50 50 50 30 50 50 50 50 30 50 . . . . . 50 50 50 70 70 70 90 70 70 70 70 70 50 50 70 70 30 50 50 50 50 30 50 30 30 30 30 30 . . . . . 50 50 70 70 70 70 70 70 70 70 70 30 50 50 30 50 30 30 50 50 50 50 50 30 30 50 50 . . . . . . . 70 70 70 70 70 70 70 70 70 50 50 50 50 50 70 50 50 50 50 30 70 30 70 30 30 10 . . . . . . . . 50 70 70 70 90 70 70 50 50 50 50 50 50 50 50 50 50 30 50 50 50 30 50 30 . . . . . . . . . . 70 70 70 70 70 30 50 50 70 50 50 70 50 50 70 50 30 30 50 70 70 50 . . . . . . . . . . . 50 70 70 70 50 70 70 70 50 70 50 50 30 30 30 30 30 50 50 50 50 . . . . . . . . . . . . . . 50 50 70 50 50 70 50 50 30 30 30 30 50 30 30 70 50 50 . . . . . . . . . . . . . . . . 30 30 50 50 50 30 10 30 30 50 30 30 50 50 70 50 . . . . . . . . . . . . . . . . . . . 30 30 30 30 30 30 30 30 50 30 70 50 . . . . . . . . . . . . . . . . . . . . . . . . 30 50 50 30 30 30 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; run; proc format; value myfmt 0 - < 20 = '0%-20%' 20 - < 40 = '20%-40%' 40 - < 60 = '40%-60%' 60 - < 80 = '60%-80%' 80 - 100 = '80%-100%' ; run; data work.rawdata; set work.rawdata; format value myfmt.; n=_n_; x=mod(_n_,33); y= 33 - int((_n_-1)/33); run; data work.griddata; set work.rawdata; length id $ 20 myhtml $ 254; id=trim(left(x))||'_'||trim(left(y)); myhtml= 'title='|| quote( 'id: '||trim(left(id))||'0D'x|| 'x: '||x||'0D'x|| 'y: '||y||'0D'x|| 'value: '||value||' ' ) ||' '|| 'href="./wafer.htm"'; /* 'href="http://www.sas.com/sub_wafer/'||trim(left(id))||'.com "'; */ if value^=. then output; run; GOPTIONS DEVICE=png; ODS LISTING CLOSE; ODS HTML path=odsout body="&name..htm" (title="SAS/GRAPH Silicon Wafer Map Example") style=d3d; goptions gunit=pct htitle=5 htext=2.5 ftitle="arial/bo" ftext="arial"; title "Silicon Wafer Map Analysis"; title2 h=3 " "; /* This just puts more space between title1 and the plot/map */ footnote1 h=1 " "; footnote2 h=3 link="http://www.idsusa.com/site/images/products/wafermap/bmtitle.gif" "Similar to this IDS WaferMap (click here to see)"; pattern1 v=s c=red; pattern2 v=s c=blue; pattern3 v=s c=cx00ff00; pattern4 v=s c=yellow; pattern5 v=s c=white; legend1 across=1 position=(bottom left) shape=bar(2,2) label=none origin=(2,5) value=(h=2.2) mode=share; goptions cback=white; goptions hsize=7in vsize=7in; goptions border; proc gmap data=work.griddata map=work.wafermap anno=work.outlines /* all */; id id; choro value / html=myhtml legend=legend1 discrete coutline=graybb woutline=2 des="" name="&name"; run; /* proc print data=griddata; var value value n x y id; run; */ quit; ODS HTML CLOSE; ODS LISTING;