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;
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.
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 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.
Ready to level-up your skills? Choose your own adventure.