BookmarkSubscribeRSS Feed
jsbyxws
Obsidian | Level 7

I have a dummy dataset with 3 cohorts: 1, 2 and 3. In each cohort there are subjects (Cohort 1: 011, 012. Cohort2: 021. Cohort 3: 031). I want the keylegend to show 3 rows with row 1 "Cohort 1: 011 012", row 2 "Cohort 2: 021", and row 3 "Cohort 3: 031". I don't know how. Below is the data and plot.

data test;
	cohort = 1;subjid = '011';aval = 10; ady = 1; output;
	cohort = 1;subjid = '012';aval = 15; ady = 1; output;
	cohort = 2;subjid = '021';aval = 20; ady = 2; output;
	cohort = 3;subjid = '031';aval = 30; ady = 3; output;
run;

proc sort data=test; by cohort subjid; run;

proc sgpanel data=test;
	panelby cohort / columns=1 spacing=5 novarname HEADERATTRS=(Family=Arial Size=11 Weight=Bold);
	series x=ady y=aval / markers group=subjid markerattrs=(symbol=circle) ;
	keylegend /title='Subject' titleattrs=(size=8 family='Arial' weight=bold);

	colaxis offsetmin=0.05 offsetmax=0.01 values=(-1 1 2 3 ) valueattrs=(weight=bold size=8 family='Arial')
	      valuesdisplay=('Baseline' 'Day 1' 'Day 2' 'Day 3') 
	      label='Study Day' labelattrs=(weight=bold size=11 family='Arial') fitpolicy=rotate;
	rowaxis label="Param" labelattrs=(weight=bold family='Arial' size=11);

	refline 1 / axis=x lineattrs=(thickness=1 color=lightgray pattern=solid);
run;
6 REPLIES 6
ballardw
Super User

I think this comes close to what you are asking for.

Separate legends sort of imply separate plots. So the data is changed to plot a different y variable in each plot panel. Then use the EXCLUDE= option for each separate keylegend to only show the subjid for the cohort.

data test;
	cohort = 1;subjid = '011';aval = 10; ady = 1; output;
	cohort = 1;subjid = '012';aval = 15; ady = 1; output;
	cohort = 2;subjid = '021';aval2 = 20; ady = 2; output;
	cohort = 3;subjid = '031';aval3 = 30; ady = 3; output;
run;

proc sort data=test; by cohort subjid; run;

proc sgpanel data=test;
	panelby cohort / columns=1 spacing=5 novarname HEADERATTRS=(Family=Arial Size=11 Weight=Bold);
	series x=ady y=aval / markers group=subjid markerattrs=(symbol=circle) name='p1' ;
	series x=ady y=aval2 / markers group=subjid markerattrs=(symbol=circle) name='p2' ;
	series x=ady y=aval3 / markers group=subjid markerattrs=(symbol=circle) name='p3' ;
	keylegend 'p1' /title='Corhort 1' exclude=('021' '031') titleattrs=(size=8 family='Arial' weight=bold);
	keylegend 'p2' /title='Corhort 2' exclude=('011' '012' '031') titleattrs=(size=8 family='Arial' weight=bold);
	keylegend 'p3' /title='Corhort 3' exclude=('011' '012' '021') titleattrs=(size=8 family='Arial' weight=bold);

	colaxis offsetmin=0.05 offsetmax=0.01 values=(-1 1 2 3 ) valueattrs=(weight=bold size=8 family='Arial')
	      valuesdisplay=('Baseline' 'Day 1' 'Day 2' 'Day 3') 
	      label='Study Day' labelattrs=(weight=bold size=11 family='Arial') fitpolicy=rotate;
	rowaxis label="Param" labelattrs=(weight=bold family='Arial' size=11);

	refline 1 / axis=x lineattrs=(thickness=1 color=lightgray pattern=solid);
run;

There might be a cleaner way with Annotate data.

jsbyxws
Obsidian | Level 7

Hi Ballardw,

 

Thanks a lot for help! It works!

 

The actual data has about many cohorts. Each cohort has 3 subjects. It would be tedious to exclude so many subjects in reality.

 

 

Ksharp
Super User
data test;
	cohort = 1;subjid = '011';aval = 10; ady = 1; output;
	cohort = 1;subjid = '012';aval = 15; ady = 1; output;
	cohort = 2;subjid = '021';aval = 20; ady = 2; output;
	cohort = 3;subjid = '031';aval = 30; ady = 3; output;
run;

proc sort data=test; by cohort subjid; run;

proc sgpanel data=test;
	panelby cohort / columns=1 spacing=5 novarname HEADERATTRS=(Family=Arial Size=11 Weight=Bold);
	series x=ady y=aval / markers group=subjid markerattrs=(symbol=circle) ;

legenditem name='a' type=MARKERLINE / label='011' MARKERATTRS=graphdata1 LINEATTRS=graphdata1;
legenditem name='b' type=MARKERLINE / label='012' MARKERATTRS=graphdata2 LINEATTRS=graphdata2;
legenditem name='c' type=MARKERLINE / label='021' MARKERATTRS=graphdata3 LINEATTRS=graphdata3;
legenditem name='d' type=MARKERLINE / label='031' MARKERATTRS=graphdata4 LINEATTRS=graphdata4;



keylegend 'a' 'b' /title='Corhort 1' titleattrs=(size=8 family='Arial' weight=bold) noborder;
keylegend 'c' /title='Corhort 2' titleattrs=(size=8 family='Arial' weight=bold) noborder;
keylegend 'd' /title='Corhort 3' titleattrs=(size=8 family='Arial' weight=bold) noborder;

	colaxis offsetmin=0.05 offsetmax=0.01 values=(-1 1 2 3 ) valueattrs=(weight=bold size=8 family='Arial')
	      valuesdisplay=('Baseline' 'Day 1' 'Day 2' 'Day 3') 
	      label='Study Day' labelattrs=(weight=bold size=11 family='Arial') fitpolicy=rotate;
	rowaxis label="Param" labelattrs=(weight=bold family='Arial' size=11);

	refline 1 / axis=x lineattrs=(thickness=1 color=lightgray pattern=solid);
run;

Ksharp_0-1678453427153.png

 

jsbyxws
Obsidian | Level 7

Thanks a lot, KSharp! 

 

Yes, it solves this problem.

 

But in reality, the study has about 50 subjects with 15 cohort. How to make legend item list easier to code?

 

Another information: if each cohort is 3 subjects, crossover = 3 will make it multiple rows in 3 columns. But how to add cohort label "Cohort 1", "Cohort 2" etc?

ballardw
Super User

@jsbyxws wrote:

Thanks a lot, KSharp! 

 

Yes, it solves this problem.

 

But in reality, the study has about 50 subjects with 15 cohort. How to make legend item list easier to code?

 

Another information: if each cohort is 3 subjects, crossover = 3 will make it multiple rows in 3 columns. But how to add cohort label "Cohort 1", "Cohort 2" etc?


That would likely be ugly in SGPANEL.

Did you try SGPLOT:

Consider that with a BY statement then each legend is built separately and by default each plot will have the By information:

data test;
	cohort = 1;subjid = '011';aval = 10; ady = 1; output;
	cohort = 1;subjid = '012';aval = 15; ady = 1; output;
	cohort = 2;subjid = '021';aval = 20; ady = 2; output;
	cohort = 3;subjid = '031';aval = 30; ady = 3; output;
run;

proc sort data=test; by cohort subjid; run;

proc sgplot data=test;
   by cohort;
/*	panelby cohort / columns=1 spacing=5 novarname HEADERATTRS=(Family=Arial Size=11 Weight=Bold);*/
	series x=ady y=aval / markers group=subjid markerattrs=(symbol=circle) ;
	keylegend /title='Subject' titleattrs=(size=8 family='Arial' weight=bold);

	xaxis offsetmin=0.05 offsetmax=0.01 values=(-1 1 2 3 ) valueattrs=(weight=bold size=8 family='Arial')
	      valuesdisplay=('Baseline' 'Day 1' 'Day 2' 'Day 3') 
	      label='Study Day' labelattrs=(weight=bold size=11 family='Arial') fitpolicy=rotate;
	yaxis label="Param" labelattrs=(weight=bold family='Arial' size=11);

	refline 1 / axis=x lineattrs=(thickness=1 color=lightgray pattern=solid);
run;

SAS Innovate 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 6 replies
  • 906 views
  • 2 likes
  • 3 in conversation