|
제가 올리는것이 유용한지요? 실지로 조금씩 바꿔보면서 돌려보지않으면 눈으로만 봐서는 확실히 자기것이 되기가 힘듭니다. 저도 SGPlot을 쓸때마다 아에 SAS SGPlot Help Documentation site를 열어놓고 계속 option들을 체크하면서 씁니다.
https://documentation.sas.com/?docsetId=grstatproc&docsetTarget=n0yjdd910dh59zn1toodgupaj4v9.htm&docsetVersion=9.4&locale=en 솔직히 제가 올리는 설명들을 잘 이해하고 누구한테던지 설명할수있을 정도면 초보던 아니던 임상시험 프로젝트에 참여하기가 아주 유리할겁니다. 특히 resume나 인터뷰때 자랑을 하면 좋죠, 아직 잘 아는사람들이 없으니까요.
오늘은 so-called swimmer's plot에 대해서 설명을 하겠습니다. 임상시험프로젝트에서 일하다보면 이런 nick name들은 보통 programmer들이 만든다기보다는 review를 하는 사람들이 느낀데로 만드는경우가 많은데 수영장에서 수영경기를 하는것 같다고 swimmer's plot이라고 했지만 사실 간단한 bar chart인데 SGPlot 에서는 highlow statement를 쓰는것이 좋습니다.
8개의 그래프를 만들어 봤지만 그동안 제가 올린것을 돌려보시고 이해를 하신분들은 금방 이해하실수 있을겁니다. 우선 시작하기전에 이번에는 다른 방법으로 color를 콘크롤하는것을 보여드리겠습니다. "아, 거 한가지로 하지 왜 여러가지로 혼동을 합니까?" 하고 하실분이 있을지 몰라도 원래 SAS의 매력이라고 볼수도 있는 "여러가지 방법" 이 있다는거죠. 어떤것을 쓰건 User가 알아서 해야죠. Attribute Map이라고 하는데 ID는 어떤 변수를 말하는가이고 Value는 변수값, 그리고 fillcolor는 그야말로 변수값과 상관되는 색깔이죠.
그리고 물론 SQL들을 잘하실테니 메크로 변수는 SQL로 만들어도 되겠지만 ongoing 하는 환자들의 수를 저절로 세어서 그래프에 올렸습니다. 코드는 이렇습니다.
data attrmap;
length ID $ 9 linecolor markercolor fillcolor $ 10;
input id $ value $10-20 fillcolor $;
show = 'ATTRMAP';
linecolor = 'black';
markercolor = 'black';
datalines;
kit E-00A green
kit G-11B gold
kit K-23C purple
kit P-56X blue
kit Q-78Z lightgreen
;
run;
proc freq data=swimmer;
table ongoing/out=dscat noprint;
run;
%let dsg0 = 0;
%let dsg1 = 0;
data _null_;
retain tot 0;
set dscat end=last;
tot = tot + count;
call symput('dsg'||strip(put(ongoing,2.)), put(count,2.));
if last then call symput('dsgt', strip(put(tot,2.)));
run;
그리 어려운 코드는 전혀 아닙니다.
그럼 본론을 시작하겠습니다.
누가 Swimmer's plot을 만들어 달라면 간단히 몇줄로 해결할수는 있지만 Figure A-1을 보고서 와! 할사람은 없을겁니다. 그냥 default만 쓴것이고 잘못된것은 아니지만 쓸모는 거의 없겠죠. 여기서 한가지 설명을 드리면 pre-sorting을 하는것이 그래프의 결과에 차이를 줍니다. 많은경우에는 아닌데 이경우에는 그렇습니다. 그리고 option "reverse" 를 쓰면 sorting한것을 반대로 할수있습니다. 이경우에는 weeks 변수데로 sorting을 했기에 제일 적은 값이 아래에 와야 하지만 reverse때문에 y-axis의 제일 위로 갑니다.
proc sort data=swimmer;
by weeks;
run;
proc sgplot data= swimmer dattrmap=attrmap nocycleattrs noborder;
highlow y=subjid low=low high=weeks / highcap=highcap labelattrs=(size=6);
xaxis display=(noticks) values=(0 to 12 by 4) valueattrs=(size=8) labelattrs=(size=10);
refline 4 8 12 / axis=x transparency=0.92;
yaxis reverse display=(noticks ) valueattrs=(size=6) label='Participants' fitpolicy=none ;
run;
한가지 간단하게 바꿀수있는것이 type=line (default) 에서 type=bar를 바꾸고 barwidth를 써서 두께를 조절할수있습니다. 그것이 A-2입니다.
proc sgplot data= swimmer dattrmap=attrmap nocycleattrs noborder;
highlow y=subjid low=low high=weeks /highcap=highcap labelattrs=(size=6) type=bar barwidth=0.8;
xaxis display=(noticks) values=(0 to 12 by 4) valueattrs=(size=8) labelattrs=(size=10);
refline 4 8 12 / axis=x transparency=0.92;
yaxis reverse display=(noticks ) valueattrs=(size=6) label='Participants' fitpolicy=none ;
run;
아직까지 환자ID정도는 알수있지만 더 자세한 사항이 없죠? 그래서 Lowlabel과 inset statement를 써서 과연 몇명이 계속 임상시험에 있는지도 알수있고 treatment 가 뭔지를 알수있게 만든것이 Figure A-3 입니다. 제가 지금 이글을 쓰면서 보니까 On 하고 off의 숫자가 바뀌었네요. 메크로 변수값을 반대로 썼군요. 참 여기서 fitpolicy를 none이라고 했는데 이건 SAS가 잘못생각한것이 아닌가 하네요. Default가 None이 아니고 환자ID를 쓸자리가 모자랄것 같으면 SAS가 저절로 skip해서 쓰게 만들었는데 저도 한참후에야 알아냈습니다. 글씨가 아주 작아져도 될수있으면 fitpolicy=none을 쓰는것이 좋습니다.
proc sgplot data= swimmer dattrmap=attrmap nocycleattrs noborder;
highlow y=subjid low=low high=weeks / highcap=highcap labelattrs=(size=6) type=bar barwidth=0.8
lowlabel=group;
inset "N = &dsgt"
" On treatment = &dsg0"
" Off treatment = &dsg1" / noborder position=right valuealign=left textattrs=(size=14)
opaque;
xaxis display=(noticks) values=(0 to 12 by 4) valueattrs=(size=8) labelattrs=(size=10);
refline 4 8 12 / axis=x transparency=0.92;
yaxis reverse display=(noticks ) valueattrs=(size=6) label='Participants' fitpolicy=none ;
run;
그런데 아직까지도 어런 그래프를 만들려고 시간을 쓰지는 않을겁니다. 그래서 만든것이 Figure B-1인데 사실 이 그래프에서 환자 ID나 treatment도 중요하지만 kit을 어떤것을 썼느냐가 중요한데 다섯가지의 kit을 색깔을 줬습니다. 이번부터 Attribute Map data가 유용해지는것죠. 중요한것이 환자들의 group을 kit을 쓰고 attrmap data에서 ID가 뭔가를 써줘야 하는데 그것이 attrid option입니다. 제가 제일 위에 ID값을 kit이라고 했죠. 그래서 attrid=kit 이라고 한것이고 keylegend를 쓰기위해서 이름을 지어준것이 name='kittype' 입니다. 아무 이름이나 괜찮지만 keylegend 에서 같은 이름을 사용해야 합니다. 그래서 만든것이 Figure B-1입니다. 여기서 한가지 tip이 있는데 fillheight입니다. 이것으로 legend의 symbol size를 콘트롤합니다.
proc sgplot data= swimmer dattrmap=attrmap nocycleattrs noborder;
highlow y=subjid low=low high=weeks / highcap=highcap labelattrs=(size=6) type=bar barwidth=0.8
lowlabel=group group=kit attrid=kit name='kittype';
inset "N = &dsgt"
" On treatment = &dsg0"
" Off treatment = &dsg1" / noborder position=right valuealign=left textattrs=(size=14)
opaque;
xaxis display=(noticks) values=(0 to 12 by 4) valueattrs=(size=8) labelattrs=(size=10);
refline 4 8 12 / axis=x transparency=0.92;
yaxis reverse display=(noticks ) valueattrs=(size=6) label='Participants' fitpolicy=none ;
keylegend 'kittype' / noborder location=inside position=bottomright across=1 linelength=10
valueattrs=(size=14) fillheight=12;
run;
이쯤되면 not bad이죠? 그런데 여기서 많은경우에 같은 group끼리 묶어놓는것을 좋아하는데 같은 SGPlot code를 쓰면서 sorting order만 바꿔주면 Figure B-2가 됩니다.
proc sort data=swimmer;
by kit weeks;
run;
어떤 사람들은 긴것을 먼저 위에 프린트하는것을 좋아하는데 이것또한 간단히 sorting으로 해결할수있고 그래서 만든것이 Figure B-3입니다. 직접 아무것이 만드신후에 sorting으로 순서를 바뀌보세요.
proc sort data=swimmer;
by kit descending weeks;
run;
이정도만 되어도 꽤 쓸만하다고 할겁니다. 근데 제 생각에는 색깔이 좀 촌스러워 보여서 dataskin을 써서 조금 고급스러워 보이게 만들었습니다. 그것이 C-1입니다. 한가지 제가 inset를 설명을 안했는데 keylegend하고 비슷하지만 그야말로 free text입니다. 아무거나 쓸수있고 제가 지난번에 소개를 했었죠. 한가지 option을 설명드리자면 opague입니다. Opague를 쓰면 조심해야 할것이 불투명하게 되어서 그 밑으로 그래프 자료가 있어도 모를수있습니다. 이경우에야 확실히 아니지만 scatter plot을 쓸때는 조심해야 합니다.
proc sgplot data= swimmer dattrmap=attrmap nocycleattrs noborder;
highlow y=subjid low=low high=weeks /highcap=highcap labelattrs=(size=6) type=bar lowlabel=group
group=kit attrid=kit name='kittype' dataskin=crisp;
inset "N = &dsgt"
" On treatment = &dsg0"
" Off treatment = &dsg1" / noborder position=right valuealign=left textattrs=(size=14)
opaque;
xaxis display=(noticks) values=(0 to 12 by 4) valueattrs=(size=8) labelattrs=(size=10);
refline 4 8 12 / axis=x transparency=0.92;
yaxis reverse display=(noticks ) valueattrs=(size=6) label='Participants' fitpolicy=none ;
keylegend 'kittype' / noborder location=inside position=bottomright across=1 linelength=10
valueattrs=(size=14) fillheight=12;
run;
이쯤되면 Figure A-1에 비해서 하늘과 땅차이죠. 하지만 저는 아직도 presentation level이 아닌것 같아서 좀더 option을 찾아보고 써봤더니 이경우에는 dataskin=sheen이 마음에 들더군요. 근데 색깔이 너무 진해서 transparency=0.2 정도로 해서 부드럽게 만들어 본것이 마지막 Figure C-2입니다. 이외에도 얼마던지 option들은 많으니 관심있고 자주 쓰실분들은 직접 모든 option들을 이용해보시는것을 추천합니다.
어떤 질문이던 있으시면 답글을 다시던가 아니면 저한테 따로 이메일주시기 바랍니다. 마지막 code는 이렇습니다.
proc sgplot data= swimmer dattrmap=attrmap nocycleattrs noborder;
highlow y=subjid low=low high=weeks /highcap=highcap labelattrs=(size=6) type=bar lowlabel=group
group=kit attrid=kit name='kittype'
dataskin=sheen transparency=0.2;
inset "N = &dsgt"
" On treatment = &dsg0"
" Off treatment = &dsg1" / noborder position=right valuealign=left textattrs=(size=14)
opaque;
xaxis display=(noticks) values=(0 to 12 by 4) valueattrs=(size=8) labelattrs=(size=10);
refline 4 8 12 / axis=x transparency=0.92;
yaxis reverse display=(noticks ) valueattrs=(size=6) label='Participants' fitpolicy=none ;
keylegend 'kittype' / noborder location=inside position=bottomright across=1 linelength=10
valueattrs=(size=14) fillheight=12;
run;
|
첫댓글 감사합니다. 예전에 흡연자의 금연/재흡연 행태 관련해서 비슷한 그림을 그려야 할 때가 있었는데 SAS로도 그릴 수 있군요.
솔직히 이제는 SAS로 presentation level graph를 못 그릴것이 없다고 봐도 됩니다. 이것조차 마음에 안들면 proc template까지 쓰면 아주 더 잘 만들수있습니다. 제 client는 이정도도 아주 만족해 하죠.
유용한 글 올려주셔서 감사합니다. ^^