Thank you.
Hi @Ksharp
Thank you for the contribution. I see you already given multiple different ( Permutation and Combination) of questions asked on this topic.
I was running the code using PROC SGPLOT Inspired from the @Jay54 (https://blogs.sas.com/content/graphicallyspeaking/2017/10/30/fill-patterns/)
This request looks similar to what you explained with proc template but using PROCSGPLOT. like in your output you have three box for each region. but the colors are different for each car type but patttern is same for the Region. Can we do the other way around, each Region will have one different color, and each cartype will have the same pattern across the three different regions.
In my Example, I am expecting below, but its not comming as expected.
Treatment A = Blue color, Age group: Young = L1 Pattern, datasymbol = Circlefilled ; Old = X1 Pattern Datasymbol = square filled;
Treatment B = salmon color, Age group: Young = L1 Pattern, datasymbol = Circlefilled ; Old = X1 Pattern Datasymbol = square filled;
Treatment C = Green color, Age group: Young = L1 Pattern, datasymbol = Circlefilled ; Old = X1 Pattern, Datasymbol = square filled;
Legends will be as per the above assignment/ counts displayed inner axis. Can you please help. thank you very much
/* Create sample dataset */
data treatment_data;
input Treatment $ AgeGroup $ Value @@;
/* Create a combined group variable for styling */
length GroupVar $20;
if Treatment='A' and AgeGroup='Young' then GroupVar='A_Young';
else if Treatment='A' and AgeGroup='Old' then GroupVar='A_Old';
else if Treatment='B' and AgeGroup='Young' then GroupVar='B_Young';
else if Treatment='B' and AgeGroup='Old' then GroupVar='B_Old';
else if Treatment='C' and AgeGroup='Young' then GroupVar='C_Young';
else if Treatment='C' and AgeGroup='Old' then GroupVar='C_Old';
datalines;
A Young 25 A Young 28 A Young 30 A Young 22 A Young 26
A Old 32 A Old 35 A Old 38 A Old 30 A Old 33
B Young 18 B Young 20 B Young 22 B Young 19 B Young 21
B Old 28 B Old 30 B Old 32 B Old 27 B Old 29
C Young 30 C Young 32 C Young 34 C Young 31 C Young 33
C Old 40 C Old 42 C Old 45 C Old 38 C Old 41
;
run;
/* Create box plot with custom styling */
ods graphics on / attrpriority=color;
ods rtf file="xx\text_color_patrn.rtf" style=mypatterns;
proc sgplot data=treatment_data;
title "Box Plot with Custom Treatment Colors and Age Patterns";
styleattrs datacolors=(lightblue salmon lightblue salmon lightgreen lightgreen )
datafillpatterns=(L1 X1)
DATASYMBOLS=( circlefilled squarefilled )
datacontrastcolors=(blue red green); /* Young=L1, Old=X1 for all treatments */
vbox Value / category=Treatment
group=AgeGroup
groupdisplay=cluster
nooutliers
fillpattern
/* fillattrs=(transparency=0.3)*/
grouporder=data;
/* Assign specific colors and patterns */
xaxis label="Treatment";
yaxis label="Measurement Value" grid;
/* Custom legend */
keylegend / title="Age Group"
position=topright
across=1;
run;
ods rtf close;
You want this ?
/* Create sample dataset */
data treatment_data;
input Treatment $ AgeGroup $ Value @@;
/* Create a combined group variable for styling */
length AgeGroup GroupVar $20;
if Treatment='A' and AgeGroup='Young' then GroupVar='A_Young';
else if Treatment='A' and AgeGroup='Old' then GroupVar='A_Old';
else if Treatment='B' and AgeGroup='Young' then GroupVar='B_Young';
else if Treatment='B' and AgeGroup='Old' then GroupVar='B_Old';
else if Treatment='C' and AgeGroup='Young' then GroupVar='C_Young';
else if Treatment='C' and AgeGroup='Old' then GroupVar='C_Old';
datalines;
A Young 25 A Young 28 A Young 30 A Young 22 A Young 26
A Old 32 A Old 35 A Old 38 A Old 30 A Old 33
B Young 18 B Young 20 B Young 22 B Young 19 B Young 21
B Old 28 B Old 30 B Old 32 B Old 27 B Old 29
C Young 30 C Young 32 C Young 34 C Young 31 C Young 33
C Old 40 C Old 42 C Old 45 C Old 38 C Old 41
;
run;
/* Create box plot with custom styling */
ods graphics on / attrpriority=none;
proc sgplot data=treatment_data;
title "Box Plot with Custom Treatment Colors and Age Patterns";
styleattrs datacolors=(blue blue red red green green )
datafillpatterns=(L1 X1)
DATASYMBOLS=( circlefilled squarefilled )
datacontrastcolors=(black); /* Young=L1, Old=X1 for all treatments */
vbox Value / category=Treatment
group=AgeGroup
groupdisplay=cluster
nooutliers fillpattern fillattrs=(color=white)
grouporder=data name='x';
vbox Value / category=Treatment
group=GroupVar
groupdisplay=cluster
nooutliers
fillpattern
/* fillattrs=(transparency=0.3)*/
grouporder=data;
xaxis label="Treatment";
yaxis label="Measurement Value" grid;
/* Custom legend */
keylegend 'x'/ title="Age Group"
position=topright
across=1;
run;
Yes. You applied 2 'Vbox ' statements, one for color and one for pattern? If you don't mind 2 more questions.
1. can we display the counts on x axis ( inner axis table) for those boxes like you did in another graph, I tried merging with counts but it messing the graphs, So I must be doing wrong.
2. For legends, can we apply the color that reflects in the data? Do we need to create another variable to display 6 legends ( 3 treat X 2 pattern = 6 legends)? I see your response in this topic, We still have to depend on "Style.Patterns"? If Yes, Please ignore this request. As it looks complicated for me to understand.
Thank you so much for Your time. I really appreciate your time.
For your first question, yes, you can include COUNT with XAXISTABLE.
/* Create sample dataset */ data treatment_data; input Treatment $ AgeGroup $ Value @@; /* Create a combined group variable for styling */ length AgeGroup GroupVar $20; if Treatment='A' and AgeGroup='Young' then GroupVar='A_Young'; else if Treatment='A' and AgeGroup='Old' then GroupVar='A_Old'; else if Treatment='B' and AgeGroup='Young' then GroupVar='B_Young'; else if Treatment='B' and AgeGroup='Old' then GroupVar='B_Old'; else if Treatment='C' and AgeGroup='Young' then GroupVar='C_Young'; else if Treatment='C' and AgeGroup='Old' then GroupVar='C_Old'; datalines; A Young 25 A Young 28 A Young 30 A Young 22 A Young 26 A Old 32 A Old 35 A Old 38 A Old 30 A Old 33 B Young 18 B Young 20 B Young 22 B Young 19 B Young 21 B Old 28 B Old 30 B Old 32 B Old 27 B Old 29 C Young 30 C Young 32 C Young 34 C Young 31 C Young 33 C Old 40 C Old 42 C Old 45 C Old 38 C Old 41 ; run; proc sql; create table treatment_data2 as select *,count(*) as n from treatment_data group by Treatment,GroupVar; quit; data treatment_data2; set treatment_data2; by Treatment GroupVar; if not first.GroupVar then call missing(n); run; /* Create box plot with custom styling */ ods graphics on / attrpriority=none; proc sgplot data=treatment_data2; title "Box Plot with Custom Treatment Colors and Age Patterns"; styleattrs datacolors=(blue blue red red green green ) datafillpatterns=(L1 X1) DATASYMBOLS=( circlefilled squarefilled ) datacontrastcolors=(black); /* Young=L1, Old=X1 for all treatments */ vbox Value / category=Treatment group=AgeGroup groupdisplay=cluster nooutliers fillpattern fillattrs=(color=white) grouporder=data name='x'; vbox Value / category=Treatment group=GroupVar groupdisplay=cluster nooutliers fillpattern /* fillattrs=(transparency=0.3)*/ grouporder=data; xaxistable n/x=Treatment class=GroupVar classdisplay=cluster location=inside ; xaxis label="Treatment"; yaxis label="Measurement Value" grid; /* Custom legend */ keylegend 'x'/ title="Age Group" position=topright across=1; run;
For your second question. Can you post the desired output ? I don't understand " For legends, can we apply the color that reflects in the data?".
Or you maybe display all the "6 legends ( 3 treat X 2 pattern = 6 legends)".
/* Create box plot with custom styling */ ods graphics on / attrpriority=none; proc sgplot data=treatment_data2; title "Box Plot with Custom Treatment Colors and Age Patterns"; styleattrs datacolors=(blue blue red red green green ) datafillpatterns=(L1 X1) DATASYMBOLS=( circlefilled squarefilled ) datacontrastcolors=(black); /* Young=L1, Old=X1 for all treatments */ vbox Value / category=Treatment group=GroupVar groupdisplay=cluster nooutliers fillpattern /* fillattrs=(transparency=0.3)*/ grouporder=data name='x'; xaxistable n/x=Treatment class=GroupVar classdisplay=cluster location=inside ; xaxis label="Treatment"; yaxis label="Measurement Value" grid; /* Custom legend */ keylegend 'x'/ title="Age Group" position=topright across=1; run;
Or you could plot it as :
/* Create box plot with custom styling */ ods graphics on / attrpriority=none; proc sgplot data=treatment_data2; title "Box Plot with Custom Treatment Colors and Age Patterns"; styleattrs datafillpatterns=(L1 X1) DATASYMBOLS=( circlefilled squarefilled ) datacontrastcolors=(black); /* Young=L1, Old=X1 for all treatments */ vbox Value / category=Treatment group=AgeGroup groupdisplay=cluster nooutliers fillpattern fillattrs=(color=white) grouporder=data name='x'; xaxistable n/x=Treatment class=GroupVar classdisplay=cluster location=inside ; xaxis label="Treatment" colorbands=even; yaxis label="Measurement Value" grid; /* Custom legend */ keylegend 'x'/ title="Age Group" position=topright across=1; run;
Hi @Ksharp. I don't think I need to post the data, as your second output answered my expectations. Thank you so much. Really appreciate it. And you are awesome. I have one more question. How to control the groups on the x-axis so that they always come in the order I want. Since here A, B, C is alphabetical order. I want to display them in B, A, C order, so giving numeric numbering will help me?
You could change the order of X axis value by padding some blanks before it. Here is an example:
/* Create sample dataset */ data treatment_data; input Treatment $ AgeGroup $ Value @@; /* Create a combined group variable for styling */ length AgeGroup GroupVar $ 20; if Treatment='A' and AgeGroup='Young' then GroupVar='A_Young'; else if Treatment='A' and AgeGroup='Old' then GroupVar='A_Old'; else if Treatment='B' and AgeGroup='Young' then GroupVar='B_Young'; else if Treatment='B' and AgeGroup='Old' then GroupVar='B_Old'; else if Treatment='C' and AgeGroup='Young' then GroupVar='C_Young'; else if Treatment='C' and AgeGroup='Old' then GroupVar='C_Old'; datalines; A Young 25 A Young 28 A Young 30 A Young 22 A Young 26 A Old 32 A Old 35 A Old 38 A Old 30 A Old 33 B Young 18 B Young 20 B Young 22 B Young 19 B Young 21 B Old 28 B Old 30 B Old 32 B Old 27 B Old 29 C Young 30 C Young 32 C Young 34 C Young 31 C Young 33 C Old 40 C Old 42 C Old 45 C Old 38 C Old 41 ; run; proc sql; create table treatment_data2 as select *,count(*) as n from treatment_data group by Treatment,GroupVar; quit; data treatment_data2; length Treatment $ 20; set treatment_data2; by Treatment GroupVar; if not first.GroupVar then call missing(n); if Treatment='B' then Treatment=' B'; else if Treatment='C' then Treatment=' C'; run; /* Create box plot with custom styling */ ods graphics on / attrpriority=none; proc sgplot data=treatment_data2; title "Box Plot with Custom Treatment Colors and Age Patterns"; styleattrs datafillpatterns=(L1 X1) DATASYMBOLS=( circlefilled squarefilled ) datacontrastcolors=(black); /* Young=L1, Old=X1 for all treatments */ vbox Value / category=Treatment group=AgeGroup groupdisplay=cluster nooutliers fillpattern fillattrs=(color=white) name='x'; xaxistable n/x=Treatment class=GroupVar classdisplay=cluster location=inside ; xaxis label="Treatment" colorbands=even; yaxis label="Measurement Value" grid; /* Custom legend */ keylegend 'x'/ title="Age Group" position=topright across=1; run;
Hi @Ksharp again. Sorry for bothering. What are the options I can play with if the x-axis table count numbers do not align with the boxes, like in the image with 'Red' color numbers. I tried with 'offsetmin' and clusterwidth in the 'xaxis' and ' vbox' statements. Is any other options available? if you can direct me, I can play with the graph. Thank you.
Unfortunately, there is not such option for XAXISTABLE statment.
But you can mimic it by SCATTER statement, if you really need it.
/* Create sample dataset */ data treatment_data; input Treatment $ AgeGroup $ Value @@; /* Create a combined group variable for styling */ length AgeGroup GroupVar $ 20; if Treatment='A' and AgeGroup='Young' then GroupVar='A_Young'; else if Treatment='A' and AgeGroup='Old' then GroupVar='A_Old'; else if Treatment='B' and AgeGroup='Young' then GroupVar='B_Young'; else if Treatment='B' and AgeGroup='Old' then GroupVar='B_Old'; else if Treatment='C' and AgeGroup='Young' then GroupVar='C_Young'; else if Treatment='C' and AgeGroup='Old' then GroupVar='C_Old'; datalines; A Young 25 A Young 28 A Young 30 A Young 22 A Young 26 A Old 32 A Old 35 A Old 38 A Old 30 A Old 33 B Young 18 B Young 20 B Young 22 B Young 19 B Young 21 B Old 28 B Old 30 B Old 32 B Old 27 B Old 29 C Young 30 C Young 32 C Young 34 C Young 31 C Young 33 C Old 40 C Old 42 C Old 45 C Old 38 C Old 41 ; run; proc sql noprint; create table treatment_data2 as select *,count(*) as n from treatment_data group by Treatment,GroupVar; select min(value)-1 into :min from treatment_data; quit; data treatment_data2; length Treatment $ 20; set treatment_data2; by Treatment GroupVar; min=&min.; if not first.GroupVar then call missing(n); if Treatment='B' then Treatment=' B'; else if Treatment='C' then Treatment=' C'; run; %sganno data sganno; /*display COUNT or N at south-west corner */ %SGTEXT( LABEL="N", DRAWSPACE="WALLPERCENT" ,X1=-2,Y1=2.5, JUSTIFY= "RIGHT" , TEXTCOLOR="black" , /* TEXTSIZE= n units,*/ RESET="ALL" ) run; /* Create box plot with custom styling */ ods graphics on / attrpriority=none; proc sgplot data=treatment_data2 sganno=sganno; title "Box Plot with Custom Treatment Colors and Age Patterns"; styleattrs datafillpatterns=(L1 X1) DATASYMBOLS=( circlefilled squarefilled ) datacontrastcolors=(black); /* Young=L1, Old=X1 for all treatments */ vbox Value / category=Treatment group=AgeGroup groupdisplay=cluster nooutliers fillpattern fillattrs=(color=white) name='x'; scatter x=Treatment y=min/group=AgeGroup groupdisplay=cluster datalabel=n datalabelpos=left clusterwidth=0.7 discreteoffset=-0.1 markerattrs=(size=0); /*xaxistable n/x=Treatment class=AgeGroup classdisplay=cluster location=inside ;*/ xaxis label="Treatment" colorbands=even; yaxis label="Measurement Value" grid; /* Custom legend */ keylegend 'x'/ title="Age Group" position=topright across=1; run;
Thank you.
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.
Ready to level-up your skills? Choose your own adventure.