10月 292008
 
I love being able to share good news, and this is good news. You brought it to our attention that you could not locate a hot fix on the support.sas.com site using search. Thanks to your comments and a little work from our administrators, you can now search for hot fixes on support.sas.com using the search box at the top of any page. (Now would be a great time for me to stress the importance of your feedback. Without your comments, this omission could have gone undetected. So keep your comments coming!)

Finding a hot fix download


If you know the hot fix name or topic and simply want to locate the download package, try the following:
  1. Find a search box on the top of any support.sas.com page.
  2. Type the name or description into the search field .
    For example: E9BA02 or hot fix for Compaq Tru64 9.2
  3. Select Downloads and Hot Fixes from the search drop list.


  4. Select Search or hit your Enter key.


Continue reading "Searching for Hot Fixes"
10月 242008
 
原文載點:http://www.nesug.info/Proceedings/nesug07/cc/cc21.pdf

有時候要針對一組資料裡面不同類別的觀測值進行分析,在所有的 PROC 程序裡面都可以利用 BY 這個語法來完成。但是 BY 並沒有辦法在某些特殊情況下使用,因此利用 macro 進行遞迴式的處理就變成一另一種可行的方式。Katie Joseph 和 Taylor Lewis 在 NESUG 2007 發表了一篇利用 macro + do loop + %scan 來完成 BY 所無法完成的工作,可供有需要的人參考。

 假設有一組資料如下所示:
你拍攝的 2008-10-24_1333。
每個 agency 有數筆重複觀測資料,Q1-Q73 為 73 個類別變數,weight 是連續變數表「權重」,而 strata 則是一個獨立的分層變數,同一個 agency 可能有兩種以上不同的分層變數。

假設我們要計算抽樣母體的平均值,則可使用下列程式:

proc surveymeans data=survey total=frametotals;
strata STRATA;
var Q1-Q73;
weight weight;
domain agency;
ods output domain=outstats;
run;

這個程式特殊的地方在於他有使用 domain statement 來執行 domain analysis。關於 domain analysis 可以參考下面這個網址:

http://support.sas.com/rnd/app/da/new/801ce/stat/chap13/sect9.htm#smeansdomainanalysis

Domain analysis 在變數分層多的時候會消耗大量電腦記憶體,而此例的 agency 總共有 87 層,一般電腦可能會出現「out of memory」的訊息而中斷程序。因此得轉個彎讓每個 agency 跑一次 proc surveymeans,然後一個一個去跑 domain analysis 就不會有記憶體不足的問題。假設只跑 agy1 這一層,則程式如下:

data split;
set survey;
length split $1;
if agency='agy1' then split='Y';
else split='N';
run;
proc surveymeans data=split total=frametotals;
strata STRATA;
var Q1-Q73;
weight weight;
domain split;
ods output domain=outstats_agy1 (where=(split='Y'));
run;

第一個 data step 設定一個新的變數 split,當 agency=agy1 時則 split = 'Y',反之則 split = 'N'。然後執行 proc surveymeans 時,把 split 放進 domain statement 裡面。由於 split 只是個二項變數,因此 domain 只要處理兩層就好。然後用一個 ods output 把 domain analysis 的表格輸出並存成 outstats_agy1。由於我們只關心 agy1 的結果,所以只要留下 split='Y' 的部分,至於 split='N' 的部分就不是我們所關心的了,這就是 ods output 後面要用一個 where 來抑制 split='N' 部分的輸出。

根據這個程式,我們可用一個 macro + do loop 讓他對每個 agency 都執行一次 proc surveymeans 程序。程式如下:

%macro agydoloop();
%do agynum=1 %to 87;
data split;
set survey;
length split $1;
if agency="agy&agynum" then split='Y';
else split='N';
run;
proc surveymeans data=split total=frametotals;
strata STRATA;
var Q1-Q73;
weight weight;
domain split;
ods output domain=outstats_agy&agynum (where=(split='Y'));
run;
%end;
%mend agydoloop;

這個程式首先先用 %macro agydoloop(); 和 %mend agydoloop; 把整個程式包起來。由於沒有額外的巨集參數需要使用,所以 %macro agydoloop(); 裡面就流空白即可。然後裡面再用一個 %do agynum=1 %to 87; 和 %end; 把那個 data step 以及 proc surveymeans 程序給包起來。特別注意是 do, to 和 end 若使用在 macro 裡面時,前面需加上百分比符號「%」。之後再把 1 改成 &agynum 即可,這樣讓 do loop 在跑時能把 1 到 87 遞迴地代入 agynum 裡面。如此一來 87 次 proc surveymeans 就可以輕鬆完成了。

如果不想一次把 Q1 到 Q73 跑完,而也想用 do loop 分批跑的話,只要再加上一層 do loop 即可。程式如下:

%macro agyandQdoloop();
%do agynum=1 %to 87;
data split;
set survey;
length split $1;
if agency="agy&agynum" then split='Y';
else split='N';
run;
%do qnum=1 %to 73;
proc surveymeans data=split total=frametotals;
strata STRATA;
var Q&qnum;
weight weight;
domain split;
ods output domain=outstats_agy&agynum._Q&qnum (where=(split='Y'));
run;
%end; /* qnum do loop */
%end; /* agynum do loop */
%mend agyandQdoloop;

由於 Qn 變數只出現在 proc surveymeans,所以新的 do loop 只需要放在 proc surveymeans 的頭尾即可。然後用 &qnum 來替換數字 1 到 73。特別一提的是,此處的 ods output 在設定輸出資料名稱時,原先的 &agynum 由於後面接了一個特殊符號「_」,因此 &agynum 後面要先打上一個句點「.」再接「_」。如果沒有打上句點,則這個 macro 會無法分辨出 &agynum 是個參數而非定值。這個規則通用於各種情況,只要巨集變數後面接上符號如「_」,「.」或「\」,都需要打上一個句點先。

可是,當類別變數全都是字串時,do loop 就無法處理了。因此需要利用 %scan 來輔助完成。%scan 函式是用來切割一長串的字串。其語法為:

%scan(參數, n [,分隔符號]);

其中,n 代表要抽出切割後的第幾個字串,而[,分隔符號]是一個選擇性的參數。在沒有額外設定的情況下,預設值為「空白」,「.」,「<」,「(」,「+」,「|」,「&」,「$」,「*」,「)」,「;」,「﹁」,「-」,「/」,「,」,「%」,「¢」。 假設 agency 變數不再是 agy1-agy87,而是 ED, BO, CM 這三個字串,則程式如下:
%macro agyscanloop(agylist=);

%let num=1;

%let agy=%scan(&agylist,&num);

%do %while (&agy ne );

data split;

set survey;

length split $1;

if agency="&agy" then split='Y';

else split='N';

run;

proc surveymeans data=split total=frametotals;

strata STRATA;

var Q1-Q73;

weight weight;

domain split;

ods output domain=outstats_&agy(where=(split='Y'));

run;

%let num=%eval(&num+1); *** increase by one the position pointer;

%let agy=%scan(&agylist,&num);

%end;

%mend agyscanloop;

其中,agy=%scan(&agylist,&num)是要把巨集參數 agylist 裡面所打的字串切割並取第 &num 個部分。由於一開始 &num 設定為 1,所以每跑完一次之後要把 &num 加一,這樣跑第二次時就會去取切割後的第二個字串。而遞迴的過程是由 %do %while (&agy ne); 來驅動。這個道理很簡單,只要當 &agy=%scan(&agylist, &num) 的結果不是空白(即 missing data),則這個 do while 就會一直跑,直到 &agy 是 missing data 為止。要怎樣讓這個 do while 結束,就是靠之後得 %let num=%eval(&num+1); 和 %let agy=%scan(&agylist, &num); 來控制。當跑完第一次時,num=%eval(&num+1) 會讓 &num = 2。之所以要用 %eval 的原因是因為任何四則運算在 macro 裡面都會被視為字串。只有包在 %eval 函式裡面的四則運算過程才會真正被計算出來並輸出結果。所以如果沒有用 %eval 函式的話,num 會變成字串型的「1+1」,而非數值型的「2」。當 num=2 後代入下面那個 %let agy=%scan(&agylist, &num); 時,這行就會把 &agylist 所代表的字串再次切割,然後取出第二個部分。所以這個 do while 就會繼續去執行,直到 num=3 時才會跳出。

因此當執行下面這行時:

%agyscanloop(agylist=ED BO CM);

此巨集會把「ED BO CM」從中間的空白處切成「ED」,「BO」以及「CM」,然後再一個一個去執行 proc surveymeans。

雖然 %scan 可以幫忙切割字串,但是如果 agency 這個變數有數十個字串型的類別,而非上例的只有三個類別,則在輸入巨集參數 &agylist 時便會顯得相當相當耗時。作者提出了一個 proc sql 程序來解決這項煩人的工作。程式改寫如下:

proc sql;
select distinct agy into :agylist separated by ' '
from survey;
%put &agylist;
quit;
%macro agySQLscanloop();
%let num=1;
%let agy=%scan(&agylist,&num);
%do %while (&agy ne );
*** PROC SURVEYMEANS Code - uses &agy as the agency code;
%let num=%eval(&num+1);
%let agy=%scan((&agylist,&num);
%end;
%mend agySQLscanloop;

這個 proc sql 會把 agy 所有的類別黏成一串,並用空白符號分隔開來,然後把黏成一串的結果用 %put 函式放進一個巨集變數 &agylist 裡面。由於這個 &agylist 變數已經在外部設定好了,所以之後寫 macro 時就不用在 %macro agySQLscanloop(); 裡面放 agylist 了。至於 macro 裡面的內容和設定則完全跟前例一樣。

CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the authors at:
Katie Joseph
US Office of Personnel Management
1900 E St, NW, Room 7439
Washington, DC 20415
Work Phone: (202) 606-1817
Fax: (202) 606-1719
E-mail: Katie.Joseph@opm.gov
Taylor Lewis
U.S. Office of Personnel Management (OPM)
1900 E St., NW, Room 7439
Washington, DC 20415
Work Phone: (202) 606-1309
Fax: (202) 606-1719
E-mail: Taylor.Lewis@opm.gov
 Posted by at 3:18 上午
10月 212008
 
原文載點:http://www.mediafire.com/?sharekey=00ab0205b2465593dd8b33b5aa27078d

長期以來 SAS 內部只能使用 PROC MI 來執行多重插補法的資料插補動作,而當然世界上不可能只有這麼一種方法。由於多重插補法的使用時機需要配合他強大的假定,所以一旦資料不適用 PROC MI 時,SAS 使用者往往沒有別的替代方案。另外,有時缺失值的情況不嚴重,但使用 Complete Case Analysis 直接刪除有缺失值的觀測值,往往對其他沒有缺失值的變數造成一些資料上的浪費。使用 PROC MI 又需要驗證許多假定,還得在事後進行 PROC MIANALYSIS,實在相當浪費時間。如果有個簡單但又不失可靠的替代方案,將可大大增加處理缺失值的效率。Nearest neighbor imputation(以下簡稱 NNI)是個形之多年的資料插補法,但 SAS 現存的程序並不支援。這篇於 SESUG 2008 由 Lung-Chang Chien (我本人)和 Mark Weaver (我的committee member)所發表的技術文件,提供了一個簡易的 macro 來執行 NNI 的插補動作。


首先,要瞭解 Nearest neighbor imputation 的理論,可以參考這一篇文章:

Nearest。Neighbor。Imputation

我所設計的 %NNI 一共只有五個語法便可完成插補的動作。原始碼如下:

%MACRO NNI(INDATA=,                  /*INPUT DATA SET(INCLUDING LIBRARY NAME) */
MISSVAR=, /*INPUT SINGLE VARIABLE WITH MISSING DATA*/
RESPVAR=, /*RESPONSE VARIABLE*/
IDVAR=, /*SUBJECT VARIABLE*/
OUTDATA= /*OUTPUT DATA SET WITH COMPLETE DATA*/
);

DATA OBSY_MISSX;
SET &INDATA;
IF &MISSVAR=.;
KEEP &IDVAR &RESPVAR;
RUN;

PROC MEANS DATA=&INDATA N NMISS NOPRINT;
VAR &MISSVAR;
OUTPUT OUT=OBSN N=OBSX NMISS=MISSX;
RUN;

DATA _NULL_;
SET OBSN;
CALL SYMPUT('OBSN',OBSX);
CALL SYMPUT('MISSN',MISSX);
RUN;

DATA SIMDATA_NOMISS;
SET &INDATA;
IF &MISSVAR NE .;
RUN;

PROC IML;
USE SIMDATA_NOMISS;
READ ALL VAR {&MISSVAR} INTO XMAT;
READ ALL VAR {&RESPVAR} INTO YMAT;
USE OBSY_MISSX;
READ ALL VAR {&IDVAR &RESPVAR} INTO MISSMAT;
TXMAT=T(XMAT);
TYMAT=T(YMAT);
DISTANCE=J(&MISSN,&OBSN,.);
MIND=J(&MISSN,1,.);
MISSVAR=J(&MISSN,&OBSN,.);
IMP=J(&MISSN,1,.);
DO I = 1 TO &MISSN;
DO J = 1 TO &OBSN;
DISTANCE[I,J]=ABS(MISSMAT[I,2]-TYMAT[,J]);
END;
MIND[I,]=MIN(DISTANCE[I,]);
END;
DO I = 1 TO &MISSN;
DO J = 1 TO &OBSN;
IF DISTANCE[I,J]=MIND[I,] THEN MISSVAR[I,J]=TXMAT[,J];
END;
IMP[I,]=MISSVAR[I,:];
END;
CNAME={"&IDVAR" "&RESPVAR" "&MISSVAR"};
IMPX=MISSMAT||IMP;
CREATE NNI FROM IMPX[C=CNAME];
APPEND FROM IMPX;
QUIT;

DATA &OUTDATA;
MERGE &INDATA NNI;
BY &IDVAR;
RUN;
%MEND;

語法使用方式如下:

  • INDATA:原始資料的名稱,包含其所用的 library
  • MISSVAR:含有 missing data 的變數(只能放一個)
  • RESPVAR:沒有 missing data 的變數(也只能放一個)
  • IDVAR:放 id number 或 case number,如果沒有的話必須要自己造一個
  • OUTDATA:插補過後輸出的完整資料
這邊使用一個實際範例來說明如何使用 %NNI。我使用一個位於北卡 Raleigh 的空氣品質監測站的資料,使用裡面的 PM2.5 和二十四小時日均溫這兩個變數,時間點取在西元兩千年,所以總共有 366 個觀測值。其中氣溫變數是完整的,但是 PM2.5 有十七個 missing data。我用這個資料來配適下面這個模式:

你拍攝的 2008-10-22_1608。

程式如下:

%NNI(INDATA=CASE.RALFORNNI,
MISSVAR=PM25TMEAN,
RESPVAR=TMPD,
IDVAR=DATE,
OUTDATA=CASE.RAL_NNI);

這張散佈圖說明了插補資料所在的位置:

你拍攝的 2008-10-22_1610。

由於 Nearest neighbor imputation 是一個比較保守的插補法,所以插補值很依賴既有資料的變異程度。如果既有資料的變異程度比較小,那能夠拿來當作插補值的變化也會跟著變小。不過至少不可能插補到離群值,這一點是絕對可以保證的。

再來看看 PM2.5 在插補前後的差異:
你拍攝的 2008-10-22_1613。
可以發現數值都很逼近。

經過 PROC GAM 程序的配適後,比較一下最重要的兩個參數估計值的結果:
你拍攝的 2008-10-22_1614。

從上表可知彼此的差異不大。顯著情況也沒有改變。

再來看看平滑曲線圖:
你拍攝的 2008-10-22_1615。

兩張圖的情況也非常近似。不過這邊要特別強調一點,那就是如果 missing data 是出現在要配適平滑曲線的變數時,Nearest neighbor imputation 的成效並不好。這一點已經經過我用另外一個模擬結果證實了,只是沒放在這篇技術文件裡面。這個實例之所以會有相似的平滑曲線是因為 missing data 只出現在線性的應變數 PM2.5 裡面,而非使用在平滑曲線的時間變數裡面。

Nearest neighbor imputation 還是有一些限制,整理如下:
1. 不太適用於插補離散變數,但如果資料夠大,能來搭配的完整變數內的數值變化也夠多的話,還是可以勉強使用。
2. 資料一定要多,太小的樣本數會大幅降低插補功效。
3. 資料裡面一定至少要有一個完整的變數,如果所有變數都有 missing data,則此方法和程式都會失效。
4. 目前這個 macro 的版本只能在 MISSVAR 和 RESPVAR 裡面各放一個變數。如果有數個變數含有 missing data,則需要重複使用這個 %NNI 來插補。如果情況是完整的變數有很多個,那到底要放哪一個變數在 RESPVAR 裡面。目前為止並沒有什麼準則來決定最好的完整變數。根據我個人的經驗,最好先用 PROC CORR 把所有變數的相關矩陣弄出來,然後挑出那個和有 missing data 變數有最高相關程度的完整變數即可。

此外,這次在 St. Pete Beach 舉辦的 SESUG 2008 會議,我也有去會場發表。整個過程可以看下面這篇文章:


St。Pete。Beach


比較令人印象深刻的是我在 Tampa International Airport 等交通車時遇到了 Wendi Wright 女士。本部落格曾經發表過兩篇她寫的 SAS 技術文件:

A Legend is Not Just a Legend
Checking for Duplicates

她今年也在 SESUG 發表了兩篇技術文件,有空我再來分享她的著作。

CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author at:
Lung-Chang Chien
University of North Carolina at Chapel Hill
Chapel Hill, NC 27599
E-mail: cchien@email.unc.edu
 Posted by at 12:37 下午
10月 152008
 
原文載點:http://www.nesug.org/Proceedings/nesug07/po/po21.pdf

這是一篇關於介紹 SAS/GRAPH 裡面圖例(legend)的基本寫法和一些變化,由 Wendi Wright 在 NESUG 2007 所發表。

假設有個程式如下所示:
TITLE font=’Times New Roman’ height=1.5 ‘Number of Hits on Websites 1, 2, and 3’;
TITLE2 font=’Times New Roman’ height=1.5 ‘For the Month of ‘ COLOT=red ‘March 2007’;
FOOTNOTE JUSTIFY=left ‘Educational Testing Service’ JUSTIFY=right ‘April 1, 2007’;
AXIS1 LABEL=(ANGLE=270 ROTATE=90 HEIGHT=1.5 ‘Number of Hits’)
ORDER=(0 to 1800 by 200) MINOR=(NUMBER=3);
AXIS2 REFLABEL=(POSITION=top JUSTIFY=center ‘Email Ad‘)
VALUE=(‘1’ ‘2’ ‘3’ ‘4’ ‘5’ ‘6’ ‘7’ ‘8’ ‘9’);
SYMBOL1 COLOR=blue INTERPOL=join LINE=1 VALUE=dot;
SYMBOL2 COLOR=red INTERPOL=join LINE=2 VALUE=star;
SYMBOL3 COLOR=green INTERPOL=join LNEe=3 VALUE=circle;
PROC GPLOT DATA=perm.hits;
PLOT Web1*day Web2*day Web3*day
/ OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2;
RUN;

能夠畫出這樣的圖:

以此圖為基準,我們來看看如果加上圖例,並且做一些變化。

最基本的圖例就是依照 SAS 內部的設定將三條折線的點和線的型態標註在整張圖的最下方。這個動作只需要在 plot statement 後面加上 legend 即可,如下所示:
PROC GPLOT DATA=perm.hits;
PLOT Web1*day Web2*day Web3*day
/ OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND;
Run;

SAS 會輸出下面這種圖:

如果想要換掉 legend 裡面三條折線的標籤,則可以在 PROC GPLOT 程序前面加上一條 legendn 的指令來修改。其中 n=1,2,3... 表示可以寫 n 條 legend 的指令。之後再把寫好的 legend statement 掛在 legend option 的後面,如下所示:
LEGEND1 VALUE=(COLOR=blue HEIGHT=1 ‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’);
PROC GPLOT DATA=perm.hits;
PLOT Web1*day Web2*day Web3*day
/ OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;
Run;

在 legend1 指令中,value 可以設定標籤的顏色(color option)、大小(height option)還有標籤字樣(此例用 'Web Site 1' 'Web Site 2' 'Web Site 3',記得要加引號,不要加逗號)。改好後得圖例會變成這樣:

如果也想一併把 legend 的名字(此例為「PLOT」)改掉,則可使在 legendn 指令裡面再加上一個 label 的選項,如下所示:
LEGEND1 LABEL=(COLOR=blue HEIGHT=2 ‘Our Web Pages’)
VALUE=(COLOR=blue HEIGHT=1 ‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’);
PROC GPLOT data=perm.hits;
PLOT Web1*day Web2*day Web3*day
/ OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;
Run;

同樣地,label 裡面也可以設定顏色大小和想要用的字,語法和 value 一模一樣。改出來的效果如下所示:


如果不想讓 legend 橫的排列,而想改成直的,則需使用 across 和 down 兩個選項控制。across 可以表示行數,down 可以表示列數。因此此例要讓 legend 直的排,就等於是要宣告 legend 裡面只要一行三列,程式改寫如下:
LEGEND1 LABEL=(HEIGHT=1 ‘Our Web Pages’)
VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)
ACROSS=1 DOWN=3;
PROC GPLOT DATA=perm.hits;
PLOT Web1*day Web2*day Web3*day
/ OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS axis2 LEGEND=legend1;
Run;

此時 legend 就會站起來了!


若覺得這樣還不夠,想要讓 legend 名稱「Our Web Pages」也放在圖例的上頭,則需要在 legend 裡面的 label option 多加兩個指令。一個是 position,用來指定 legend 名稱的位置,有上下左右(top, bottom, left, right)可選,然後再用 justify 指令來對齊,有置左(left)、置中(center)、和置右(right)可選。程式如下:
LEGEND1 LABEL=(HEIGHT=1 POSITION=top JUSTIFY=center ‘Web Sites’)
VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)
ACROSS=1 DOWN=3;
PROC GPLOT DATA=perm.hits;
PLOT Web1*day Web2*day Web3*day
/ OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;
Run;

此程式是將他放在上頭並置中,所以用 position=top 和 justify=center 來調整。結果如下:


若覺得這樣的圖例太大很佔空間,想要把他移到圖內,只要在 position 裡面加上一個 inside 選項即可。如果要把圖例移到左上角,則可以再同時宣告 top 和 left 於 position 裡面。換句話說,position 可以一次宣告三種位置。另外,如果擔心圖例會遮到既有的點或線,則可以使用 mode 來決定要不要覆蓋。要的話設定為 protect,不要的話則設定為 share。此例設定為要覆蓋,所以使用 mode=protect。程式改寫如下:
LEGEND1 LABEL=(HEIGHT=1 POSITION=top JUSTIFY=center ‘Web Sites’)
VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)
ACROSS=1 DOWN=3
POSITION = (top left inside)
MODE=protect;
PROC GPLOT DATA=perm.hits;
PLOT Web1*day Web2*day Web3*day
/ OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;
Run;

圖形如下:


如果覺得這個 legend 太單調,想要多加一個有顏色的框,則需使用 cframe 來設定顏色,如下所示:
LEGEND1 LABEL=(HEIGHT=1 POSITION=top JUSTIFY=center ‘Web Sites’)
VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)
ACROSS=1 DOWN=3
POSITION = (top left inside)
MODE=protect
CFRAME = yellow;
PROC GPLOT DATA=perm.hits;
PLOT Web1*day Web2*day Web3*day
/ OVERLYA HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;
Run;

然後你就會得到一個黃色的框架:


當然框架也是可以做一些微調的,比方說若覺得他太靠近 Y 軸的話,可利用 offset 來進行調整。以此圖為例,如果想要將 legend 框架和 Y 軸拉開差不多整張圖的 3% 的距離,則可以下列程式:
LEGEND1 LABEL=(HEIGHT=1 POSITION=top JUSTIFY=center ‘Web Sites’)
VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)
ACROSS=1 DOWN=3
POSITION = (top left inside)
MODE=protect
CFRAME= yellow
OFFSET = (3 pct);
PROC GPLOT DATA=perm.hits;
PLOT Web1*day Web2*day Web3*day
/ OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;
Run;

成效如下:

特別一提的是,這種調整通常很難一次到位,所以使用者需要輸入不同的數值以求達到自己最滿意的結果。

這框架也可以更改長寬大小,只要在 legend 裡面使用 shape=(w,h) 語法就可設定,其中 w 代表寬度,h 代表高度。預設值是 (w,h)=(5,1)。此例若要加長寬度,則需用 shape=(10,1),如下所示:
LEGEND1 LABEL=(HEIGHT=1 POSITION=top JUSTIFY=center ‘Web Sites’)
VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)
ACROSS=1 DOWN=3
POSITION = (top left inside)
MODE=protect
CFRAME = yellow
OFFSET = (3 pct)
SHAPE=(10,1);
PROC GPLOT DATA=perm.hits;
PLOT Web1*day Web2*day Web3*day
/ OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;
RUN;



當然 legend 指令還有很多,不過這些基本的設定可以應付大部分的情況,如果想要再深入研究其他指令,可以依照下面的路徑去找網路上的手冊:

AUTHOR CONTACT
Your comments and questions are valued and welcome. Contact the author at:
Wendi L. Wright
1351 Fishing Creek Valley Rd.
Harrisburg, PA 17112
Phone: (717) 513-0027
E-mail: wendi_wright@ctb.com
 Posted by at 5:30 上午
10月 142008
 
Well, recently October has meant play-off baseball to me, since I'm a Red Sox fan, and that's true this year, too. But this year it also means the first edition of our new SAS Statistics and Operations Research News, a newsletter focused on information for our analytical audience and users of products such as SAS/STAT, SAS/ETS, SAS/QC, and SAS/OR.

I was elected the first editor (okay, not exactly elected) and since I'm a statistician, the first issue is pretty STAT-heavy. But it comes out each quarter, and we'll be bringing you news from numerous analytical product areas, as well as insight into how we operate in this arena at SAS. One of our best-kept secrets is our talented statistics group in SAS Technical Support, and this issue includes an interview with Phil Gibbs, group manager.

Thanks to Waynette Tubbs and Diana Witt for their help in getting the first newsletter ready. If interested, you can subscribe at www.sas.com/news/newsletter . If you hurry, you won't miss a single issue.

Okay. Time to get back to work so I leave early enough to catch some of today's game……
10月 092008
 
SAS Global Forum dates and deadlines are about to kick into high gear. I don't want you to miss a thing, so here are a few tidbits and reminders that I just received about the conference.

  • SAS Global Forum 2009 offers unequaled educational and networking opportunities: more than 300 papers and presentations; hands-on demonstrations; powerful workshops and much more.

  • Learn industry-specific perspectives in the Industry Solution Tracks.

  • The keynote speaker is confirmed to be author and Pulitzer Prize winner Dave Barry. Don't miss his humorous view of work, kids, technology and life.

  • DON’T FORGET…Call for Papers ends Oct. 13, so get your submissions in.

  • Registration & housing opens November 10th.

Get all of the details on www.sasglobalforum.com.

10月 082008
 
Sometimes, you just need a little help adjusting to change. We introduced a lot of change when we updated support.sas.com in October of 2007. Then, the Publications Division brought out the SAS 9.2 documentation in the spring of 2008. More change.

We hope that the changes in the SAS 9.2 documentation offer you features that you've been waiting for. The biggest change is that the documentation is now integrated with the rest of the support.sas.com content. You can use the site search to locate content across all SAS Support content; or you can limit your search to just documentation, just documentation for SAS 9.2, or even to just one book. My favorite enhancement is the Product Documentation A-Z list. If you know your product, it is easy to find the books, by title, that are associated with that product. We've never had a list like this before!

The SAS 9.2 documentation also takes advantage of the topic browse feature that was introduced with Samples & SAS Notes in October. With topic browse, you don't have to know a product name or a book title. You can find content based on the subject. For example, if you are interested in CALL routines, simply go to the SAS 9.2 Documentation page and select the CALL routines link from the SAS Reference category. You will get a list of 10 books that address CALL routines. You can select the book most likely to help you based on the book title and description. If that doesn't work, you can search the text of the 10 books by submitting a search query in the Search box in the body of the page. (See the image below.) The search you submit from this search field searches only the current results set.



Get more tips
Helen Weeks, a member of the SAS Publications Division, wrote an article to help you get the most out of the new documentation features. She created a hints table that compares how you used to use the SAS OnlineDoc with how you might use the new SAS 9.2 documentation. If you are still learning your way around, take a look at Helen's Product Documentation for SAS 9.2 article on support.sas.com.

We'll be watching this post, so share your usage tips, questions and suggestions with us and other SAS documentation users.

10月 062008
 

管理SAS DashBoard 仪表盘的安全
 
你可以管理访问仪表盘的对象,如数据模型、仪表盘、指示器等只需要通过添加适当的用户或者组到适当的位于仪表盘组就可以。
下面具体介绍
1。允许仪表盘安全
  修改 BIDashboard.config 配置文件
  去掉下面元素的注释:
  jaasConfig
  metadataRootFolder
  adminGroup
  userGroup
  例如:
  jaasConfig=C:\SAS\EntBIServer\Lev1\web\Deployments\Portal\login.config
  metadataRootFolder=BIP Tree/BIDashboard
  adminGroup=Dashb

 Posted by at 10:21 下午
9月 162008
 
Do you still have the newspaper delivered to your house? I do. It is part of our morning routine. It dominates our weekend mornings. We sit together at the kitchen table with our coffee and our favorite section of the paper. I get the home and garden section first. He gets the sports section. After that, it is first come, first read. Except. Soon the quiet breaks and we start spoiling each other's discovery process. The conversation goes like this:

Me: Hey. Did you see this about the horse farm?
Him: No. I haven't read that section yet.
Me: It's amazing. You should read it.
Him: OK. I will when I get to that section.
Me: It says....

I know; it's annoying to spoil someone's newspaper adventure. But the reason we read is to share the interesting, the absurd, and the necessary. Right? I often find tidbits of information that are worth sharing with you. I've created a new category called Just Sharing. The posts in this category will be less about SAS Online Support and more about SAS — the company and the people. I hope you enjoy it.

Here's a tidbit that I've been carrying around for a month. [excerpted from the News & Observer]

Bradley Jones and Maura Stokes, research and development directors at SAS in Cary, have become fellows of the American Statistical Association. Recipients are honored for their professional contributions and leadership in the field of statistical science.

Visit the Statistics and Operations Research focus area on support.sas.com to see what Maura and her coworkers are contributing to data analysis, econometrics, and operations research at SAS.

See if you know anyone else on the list of fellows for 2008.