/*************************************************************************************** *H* PROOGRAM: f_swimlane.sas *H* *H* USAGE: Create swimlnae Plot *H* *H* REQUIRES anadata: adtum adsl *H* *H* PRODUCES: f-*-swimlane.rf *H* REVISION HISTORY: *H* *H* 20230411 ssingh Created *H* $Id: ***************************************************************************************/ **** read in adsl ******; proc sort data=anaxl.adsl out=adsl0(keep=usubjid subjid cohort cohortn trtsdt dthdy dctreasa dctreasc eoadcdt eocdcdt cutdt); by usubjid; where saffl='Y'; run; ***** read in inv overall response *****; proc sort data=anaxl.adtum out=adtum0(keep=usubjid subjid avisit avisitn adt ady tstresc ttestcd confcrfl confprfl); by usubjid ady; where ttestcd='OVRLRESP' and ady ne . and tstresc ne 'NE' and teval='INVESTIGATOR' and recistyp='RECIST 1.1'; run; ***** exclude data after PD *****; proc sql noprint; create table pd0 as select usubjid, min(ady) as pddy from adtum0 where tstresc='PD' group by usubjid ; quit; data adtum1; merge adtum0(in=a) pd0(in=b); by usubjid; if a; if ady<=pddy or pddy=.; retain prfl crfl; if first.usubjid then do; prfl='N'; crfl='N'; end; if CONFPRFL='Y' and prfl='N' then do; prwk=ady/7; prfl='Y'; end; if CONFCRFL='Y' and crfl='N' then do; crwk=ady/7; crfl='Y'; end; run; **** merge with adsl *****; data adtum2; merge adsl0(in=a) adtum1(in=b); by usubjid; if a and b; if nmiss(eoadcdt, eocdcdt)=2 then durw=(cutdt-trtsdt+1)/7; else durw=(max(eoadcdt, eocdcdt)-trtsdt+1)/7; *** total duration gray line and symbols *****; if first.usubjid then do; trtst=0; trten=durw; if dctreasa='' or dctreasc='' then highcap='FilledArrow'; if pddy ne . then pdwk=pddy/7; if dthdy ne . then dthwk=dthdy/7; if nmiss(trtsdt, eoadcdt)=0 then eotawk=(eoadcdt-trtsdt+1)/7; if nmiss(trtsdt, eocdcdt)=0 then eotcwk=(eocdcdt-trtsdt+1)/7; end; run; *** each response duration ****; proc sort data=adtum2; by usubjid descending ady; run; data adtum3; set adtum2; by usubjid descending ady; awk=ady/7; retain lastawk lastavalc; length lastavalc avalc2 $40; if first.usubjid then do; lastawk=awk; lastavalc=''; if tstresc ne 'PD' then do; startline=awk; endline=lastawk; avalc2=strip(tstresc); end; if dctreasa='' or dctreasc='' then respcap='FilledArrow'; end; else if tstresc ne 'PD' then do; startline=awk; endline=lastawk; *lastamon=amon; avalc2=strip(tstresc); end; lastavalc=tstresc; lastawk=awk; if awk<=durw; if endline>durw then endline=durw; run; *********************************************; *********************************************; /* Create the attribute map data set */ data attrmap; length ID VALUE MARKERCOLOR MARKERSYMBOL FILLCOLOR LINEPATTERN $25; input ID$ VALUE$ MARKERCOLOR$ MARKERSYMBOL$ MARKERSIZE FILLCOLOR$ LINEPATTERN$; datalines; respgrp CR orange circlefilled 12 orange solid respgrp PR darkblue circlefilled 12 darkblue solid respgrp SD lightblue circlefilled 12 lightblue solid respgrp NA yellow circlefilled 12 yellow solid ; run; %macro crt_swimlane(whrstr=, tlfid=); proc sort data=adtum3 out=fin0; by cohortn durw subjid; &whrstr; run; ** get max X values for display ****; proc sql noprint; select floor(max(trten))+(6-int(mod(max(trten),6)) ) into :xmax from fin0 ; select distinct cohortn into :allcoh separated by " " from fin0 ; quit; %put cohorts: &allcoh; %put xmax is &xmax; * Output graphic template; proc template; define statgraph swimlane_resp; mvar cohlbl; dynamic ongfl; begingraph / border=false axislineextent=data; entrytitle cohlbl; discreteattrvar attrvar=avalc2 var=avalc2 attrmap="respgrp"; legendItem type=marker name="highcap_marker" / markerattrs=(color=gray symbol=trianglerightfilled size=11) label="Treatment Ongoing" ; legendItem type=marker name="cr_marker" / markerattrs=(color=darkgreen symbol=trianglefilled) label="First Confirmed CR" ; legendItem type=marker name="pd_marker" / markerattrs=(color=red symbol=trianglefilled) label="PD" ; legendItem type=marker name="eota_marker" / markerattrs=(color=magenta symbol=circle) label="End of Atezo" ; legendItem type=marker name="eotc_marker" / markerattrs=(color=black symbol=plus) label="End of Cabo" ; legendItem type=marker name="dth_marker" / markerattrs=(color=orange symbol=x) label="Death" ; layout overlay / xaxisopts=(label='Weeks' linearopts=(tickvaluesequence=(start=0 end=&xmax increment=6) viewmax=&xmax) ) yaxisopts=(display=(tickvalues) tickvalueattrs=(size=7) ); ***** total trt duration gray bar *****; highlowplot y=subjid low=trtst high=trten / highcap=highcap type=bar display=(fill) /*outlineattrs=(color=white thickness=1)*/ lineattrs=(thickness=10 color=darkgray) fillattrs=(color=darkgray) includemissinggroup=false; ***** each response duration *****; highlowplot y=subjid low=startline high=endline / highcap=respcap type=bar display=(fill) /* outlineattrs=(color=white thickness=0)*/ group=avalc2 name='status' includemissinggroup=false; *** symbol for CR ***; scatterplot y=subjid x=crwk / markerattrs=(symbol=trianglefilled size=8 weight=bold color=darkgreen); *** symbol for PR ***; scatterplot y=subjid x=prwk / name='pr_sym' legendlabel='First Confirmed PR' filledoutlinedmarkers=True markerfillattrs=(color=yellow) markeroutlineattrs=(color=black thickness=1) markerattrs=(symbol=trianglefilled size=9 weight=bold); *** symbol for PD ***; scatterplot y=subjid x=pdwk / name='pd_sym' legendlabel='PD' markerattrs=(symbol=trianglefilled size=9 weight=bold color=red); *** end of atezo ***; scatterplot y=subjid x=eotawk / markerattrs=(symbol=circle size=7 weight=bold color=magenta); *** end of atezo ***; scatterplot y=subjid x=eotcwk / markerattrs=(symbol=plus size=7 weight=bold color=black); *** symbol for death ***; scatterplot y=subjid x=dthwk / markerattrs=(symbol=x size=7 weight=bold color=orange); if (ongfl = 'Yes') discretelegend 'highcap_marker' 'status' 'pr_sym' /*'cr_marker'*/ 'pd_sym' 'eota_marker' 'eotc_marker' 'dth_marker' / valueattrs=(size=6) halign=right valign=bottom border=false location=inside across=1 itemsize=(linelength=20); else discretelegend 'status' /*'cr_marker'*/ 'pr_sym' 'pd_sym' 'eota_marker' 'eotc_marker' 'dth_marker' / valueattrs=(size=6) halign=right valign=bottom border=false location=inside across=1 itemsize=(linelength=20); endif; endlayout; endgraph; end; run; options orientation=landscape; ods rtf file="./RTF/monthly/20220104/C14_15/&tlfid..rtf"; ods escapechar='^'; title1 h=9pt bold j=l f=Courier c=black "Left Title" j=r f=Courier c=black "Page ^{thispage} of ^{lastpage}"; title2 h=9pt bold j=l f=Courier "protocol" j=r "task"; title3 h=9pt bold j=c f=Courier "Swimlane Plot"; %do f=1 %to 3; footnote&f h=9pt j=l f="Courier" "Footnote 1"; %end; **********************************************************; **** uno cohort per page ****; **********************************************************; %let i=1; %let coh=%scan("&allcoh", &i," "); %do %while(&coh ne ); %let highcap=; proc sql noprint; select distinct cohort into :cohlbl from fin0 where cohortn=&coh ; select distinct highcap into :highcap from fin0 where cohortn=&coh and highcap ne '' ; quit; %if &highcap ne %then %let ongfl=Yes; %else %let ongfl=; ods graphics / reset imagename="&tlfid._C&coh." imagefmt=eps width=9.5in height=6in; * width=900 height=550; proc sgrender data=fin0 dattrmap=attrmap template=swimlane_resp; where cohortn=&coh; dynamic ongfl="&ongfl"; run; %let i=%eval(&i+1); %let coh=%scan("&allcoh", &i," "); %end; ods rtf close; %mend crt_swimlane; %crt_swimlane(whrstr=%str(where cohortn in (16 17)), tlfid=f-14-2-1-5-swimlane);