BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Jima
Calcite | Level 5

Jima_0-1660833393117.png

I would like the portion of the bars for home campus to be in the same position for all bars. It is hard to read when one is on the bottom and next is on the top. I want the bars to be in descending order. Thanks...

Here is the code:

proc sgplot data=zfive_year2x;
by cawardx;
where count1fifth not = .;
styleattrs datacolors=(blue red);
vbar acadplan / response=count1fifth group=home_campus
categoryorder=respdesc
outlineattrs=(color=black);
label acadplan='Academic Plan'
cawardx='Award Level'
count1fifth='Number of Students';
format cawardx $awardc.;
title1 'Chart 3: Annual Five-Year Mean Headcount Enrollment';
run;

1 ACCEPTED SOLUTION

Accepted Solutions
Rick_SAS
SAS Super FREQ

Let's simplify the problem by getting rid of the BY statement.

The problem is that the CATEGORYORDER= option is going to order ALL the bars in a stacked bar , even those that are stacked. You say you do not want this, so we need to get rid of the CATEGORYORDER= option and instead order the categories by using VALUES= option on the XAXIS statement. There are several substeps:

  1. Use PROC FREQ to obtain the TOTAL  counts for each stacked bar. For your data, this means finding the height of each (stacked) bar for each acadplan.
  2. Order the bar heights and read them into a macro variable.
  3. Call PROC SGPLOT and use the macro variable on the XAXIS VALUES= option to order the bars by height.

I have created some fake data that seems to be similar to the first few categories in your example:

data Have;
length home_campu $6;
input acadplan $ count1fifth home_campus $;
datalines;
155 128 CHSTR
155   9 MIDLO
156 150 MIDLO
156  90 CHSTR
480  99 MIDLO
480  87 CHSTR
212  97 CHSTR
212  64 MIDLO
299 120 CHSTR
299  92 MIDLO
464 135 CHSTR
464  25 MIDLO
;

/* order the categories by frequency. Write to data set. */
proc freq data=Have order=freq;
   tables acadplan / out=FreqOut;
   weight count1fifth;
run;

/* read the ordered list of categories into a macro variable */
proc sql noprint;                              
 select acadplan into :TickList separated by ' '
 from FreqOut;
quit;
%put &=TickList;

/* create a stacked bar chart. Use the VALUES= option on the XAXIS statement 
   to order the bars by height */
title1 'Chart 3: Annual Five-Year Mean Headcount Enrollment';
proc sgplot data=Have;
   vbar acadplan / response=count1fifth group=home_campus 
                   attrid=TestAttr
                   outlineattrs=(color=black);
   xaxis values=(&TickList);
   label acadplan='Academic Plan'
         count1fifth='Number of Students';
run;

SGPlot22.png

My solution doesn't work with a BY statement because it relies on calling PROC FREQ and reordering the XAXIS. However, you can take my solution and wrap it in a %DO macro or use the DATA step and CALL EXECUTE to add in the BY-group processing.

View solution in original post

6 REPLIES 6
ballardw
Super User

Your option categoryorder=respdesc is forcing the group with the largest value as the first (bottom) value so you need to remove that to have a chance of getting the appearance you want.

 

Generally the first thing I try when I want a specific order is to sort the data set by the categories.

Typically the "first" element that gets set for a plot is the first value found.

 

 

Jima
Calcite | Level 5

I tried that thinking like you did, but the procedure ignores the order in the dataset and orders the bars by the y-axis data. I want the bars to be ordered in ascending by the response value.

Jima
Calcite | Level 5
That should have been "descending by the response value".
Rick_SAS
SAS Super FREQ

Let's simplify the problem by getting rid of the BY statement.

The problem is that the CATEGORYORDER= option is going to order ALL the bars in a stacked bar , even those that are stacked. You say you do not want this, so we need to get rid of the CATEGORYORDER= option and instead order the categories by using VALUES= option on the XAXIS statement. There are several substeps:

  1. Use PROC FREQ to obtain the TOTAL  counts for each stacked bar. For your data, this means finding the height of each (stacked) bar for each acadplan.
  2. Order the bar heights and read them into a macro variable.
  3. Call PROC SGPLOT and use the macro variable on the XAXIS VALUES= option to order the bars by height.

I have created some fake data that seems to be similar to the first few categories in your example:

data Have;
length home_campu $6;
input acadplan $ count1fifth home_campus $;
datalines;
155 128 CHSTR
155   9 MIDLO
156 150 MIDLO
156  90 CHSTR
480  99 MIDLO
480  87 CHSTR
212  97 CHSTR
212  64 MIDLO
299 120 CHSTR
299  92 MIDLO
464 135 CHSTR
464  25 MIDLO
;

/* order the categories by frequency. Write to data set. */
proc freq data=Have order=freq;
   tables acadplan / out=FreqOut;
   weight count1fifth;
run;

/* read the ordered list of categories into a macro variable */
proc sql noprint;                              
 select acadplan into :TickList separated by ' '
 from FreqOut;
quit;
%put &=TickList;

/* create a stacked bar chart. Use the VALUES= option on the XAXIS statement 
   to order the bars by height */
title1 'Chart 3: Annual Five-Year Mean Headcount Enrollment';
proc sgplot data=Have;
   vbar acadplan / response=count1fifth group=home_campus 
                   attrid=TestAttr
                   outlineattrs=(color=black);
   xaxis values=(&TickList);
   label acadplan='Academic Plan'
         count1fifth='Number of Students';
run;

SGPlot22.png

My solution doesn't work with a BY statement because it relies on calling PROC FREQ and reordering the XAXIS. However, you can take my solution and wrap it in a %DO macro or use the DATA step and CALL EXECUTE to add in the BY-group processing.

GraphGuy
Meteorite | Level 14

I believe SAS/Graph Proc Gchart is built to do exactly what you want (including the 'by' groups), without needing any extra processing, etc...

 

data Have;
length home_campu $6;
input acadplan $ count1fifth home_campus $;
datalines;
155 128 CHSTR
155   9 MIDLO
156 150 MIDLO
156  90 CHSTR
480  99 MIDLO
480  87 CHSTR
212  97 CHSTR
212  64 MIDLO
299 120 CHSTR
299  92 MIDLO
464 135 CHSTR
464  25 MIDLO
;

data Have; set Have;
label cawardx='Award Level';
cawardx='AAS';
run;

axis1 label=(a=90 "Number of Students") order=(0 to 250 by 50) minor=none;
axis2 label=('Academic Plan');

pattern1 v=s c=red;
pattern2 v=s c=blue;

title1 "Chart 3: Annual Five-Year Mean Headroll Enrollment";
proc gchart data=Have;
by cawardx;
vbar acadplan / sumvar=count1fifth descending subgroup=home_campus 
 raxis=axis1 maxis=axis2 width=5;

bar.png

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 6 replies
  • 1072 views
  • 2 likes
  • 4 in conversation