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

 

I want a Stacked Bar chart with both count and percent in the data label like image attached,
 
 I try to use the method posted in   https://communities.sas.com/t5/SAS-Programming/Making-a-grouped-bar-chart-with-both-count-and-percent-in/td-p/521667
count and percent are not displayed in the output chart, can anyone help me?
Thank you!

data bar; 
infile datalines dlm=',';
input letter $ group1 group2 group3; 
datalines; 
A,3,2,2
B,2,3,1
C,0,1,0
; 
run;

proc transpose data=bar out=barlong(rename=(_NAME_=Group COL1=value));
   by letter;
run;

proc sql;
   create table GraphData as
   select *,
          cats(value, "(", put(value/(sum(value)), percent.), ")") as datalabel
   from barlong
   group by Group;
quit;
proc sgplot data=GraphData noautolegend noborder;
   vbar Group / response=value group=letter seglabel datalabel=datalabel;
   keylegend / position=e title="" noborder;
   yaxis grid display=(nolabel);
   xaxis display=(nolabel);
run;






1 ACCEPTED SOLUTION

Accepted Solutions
ballardw
Super User

If you meant to reference this post: https://communities.sas.com/t5/SAS-Programming/Making-a-grouped-bar-chart-with-both-count-and-percen...

 

your left out the last two elements of the URL so no one can find it directly.

 

The SEGLABEL option only shows the statistic associated with the bar values. It does not display the value of another variable.

 

So  you have to do a bit more work. One way is to create an annotate data set with the coordinates the text gets placed.

proc transpose data=bar out=barlong(rename=(_NAME_=Group COL1=value));
   by letter;
run;

proc sql;
   create table GraphData as
   select *,
          cats(value, "(", put(value/(sum(value)), percent.), ")") as datalabel
   from barlong
   group by Group
   order by group , letter
   ;
quit;

data annotate;
   set graphdata;
   by group letter ;
   retain yval cum;
   if first.group then do;
      yval=value/2;
      cum=value;
   end;
   else do;
      yval= cum + value/2;
      cum+value;
   end;
   length label $ 10 x1space y1space  $50;
   layer="front";
   function="text"; textcolor="gray44"; textsize=10; textweight='bold';
   width=100; widthunit='percent'; 
   label=datalabel; 
   x1space='datavalue'; 
   y1space='datavalue'; 
   xc1=group;
   y1=yval;
   anchor='bottom'; 
run;


proc sgplot data=GraphData sganno=annotate noautolegend noborder;
   vbar group/ response=value group=letter;
   keylegend / position=e title="" noborder;
   yaxis grid display=(nolabel);
   xaxis display=(nolabel);
run;

Some details not to skip over, the ORDER BY in the SQL code is so the data step has variable values in order to create cumulative values to find the borders of the tops of the segments so an estimated midpoint on the segment can be used to display the values.

SGANNO data sets have some pretty strict requirements for certain variable names, types and values. Read up on them before modifying the code.

Note the SGANNO= option on the Sgplot statement telling the procedure to use the annotate data set.

 

CAUTION: This approach for calculating the Yval to plot will fail miserably if multiple adjacent segments have no value (those 0 counts). Small segments relative to different group values may mean not enough space to display text. The code does show how to set text size (and color and weight) so could be adjusted a bit in that case.

 

Suggestion: do not use variable names with the same names as procedure options, especially if they are not used for that option. It gets pretty hard to tell when an option/variable was actually meant.

 

View solution in original post

2 REPLIES 2
ballardw
Super User

If you meant to reference this post: https://communities.sas.com/t5/SAS-Programming/Making-a-grouped-bar-chart-with-both-count-and-percen...

 

your left out the last two elements of the URL so no one can find it directly.

 

The SEGLABEL option only shows the statistic associated with the bar values. It does not display the value of another variable.

 

So  you have to do a bit more work. One way is to create an annotate data set with the coordinates the text gets placed.

proc transpose data=bar out=barlong(rename=(_NAME_=Group COL1=value));
   by letter;
run;

proc sql;
   create table GraphData as
   select *,
          cats(value, "(", put(value/(sum(value)), percent.), ")") as datalabel
   from barlong
   group by Group
   order by group , letter
   ;
quit;

data annotate;
   set graphdata;
   by group letter ;
   retain yval cum;
   if first.group then do;
      yval=value/2;
      cum=value;
   end;
   else do;
      yval= cum + value/2;
      cum+value;
   end;
   length label $ 10 x1space y1space  $50;
   layer="front";
   function="text"; textcolor="gray44"; textsize=10; textweight='bold';
   width=100; widthunit='percent'; 
   label=datalabel; 
   x1space='datavalue'; 
   y1space='datavalue'; 
   xc1=group;
   y1=yval;
   anchor='bottom'; 
run;


proc sgplot data=GraphData sganno=annotate noautolegend noborder;
   vbar group/ response=value group=letter;
   keylegend / position=e title="" noborder;
   yaxis grid display=(nolabel);
   xaxis display=(nolabel);
run;

Some details not to skip over, the ORDER BY in the SQL code is so the data step has variable values in order to create cumulative values to find the borders of the tops of the segments so an estimated midpoint on the segment can be used to display the values.

SGANNO data sets have some pretty strict requirements for certain variable names, types and values. Read up on them before modifying the code.

Note the SGANNO= option on the Sgplot statement telling the procedure to use the annotate data set.

 

CAUTION: This approach for calculating the Yval to plot will fail miserably if multiple adjacent segments have no value (those 0 counts). Small segments relative to different group values may mean not enough space to display text. The code does show how to set text size (and color and weight) so could be adjusted a bit in that case.

 

Suggestion: do not use variable names with the same names as procedure options, especially if they are not used for that option. It gets pretty hard to tell when an option/variable was actually meant.

 

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

SAS Enterprise Guide vs. SAS Studio

What’s the difference between SAS Enterprise Guide and SAS Studio? How are they similar? Just ask SAS’ Danny Modlin.

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
  • 2 replies
  • 530 views
  • 0 likes
  • 2 in conversation