BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Anita_n
Pyrite | Level 9

Dear all, 

I have the following code to draw a bar chart and label each bar with the sum total of each bar or each year using an annotate dataset. The seglabels should be in percentage as shown in the graph, since I can't use datalabel here, I creatde an annotate dataset but can't get it working, I might probably be missing something somewhere. any help? My code is as below

data mydat;
infile datalines;
input year	level $12.	number_of_cases;
datalines;
2001	1	        90	
2001	2	        1	 
2001	3	        5	 
2001	4	        22	
2001	no cases	35	
2002	1	        99	
2002	2	        4	 
2002	3	        2	 
2002	4	        55	
2002	no cases	39	
2003	1	        200
2003	2	        45	
2003	3	        77	
2003	4	        39	
2003	no cases	23	
2004	1	        205
2004	2	        19	
2004	3	        29	
2004	4	        15	
2004	no cases	18	
2005	1	        159
2005	2	        323
2005	3	        99	
2005	4	        10	
2005	no cases	28	
2006	1	        88	
2006	2	        10	
2006	3	        16	
2006	4	        55	
2006	no cases	8	 
;
run;
*calculate sum of cases per year;
proc means data=mydat noprint nway;
	class year;
	var number_of_cases;
	output out=sum_mydat (drop=_TYPE_ _FREQ_) sum= / autoname;
run;
*calculate rel. perecntages;
data merge_mydat;
	merge mydat sum_mydat;
	by year;
	format rel_freq percent8.0; 
	rel_freq = divide(number_of_cases,number_of_cases_sum);
    drop number_of_cases_sum;
run;

*create annodat;
data anno;
length function color $8 style $12;                                                                                                  
retain function 'label' when 'a' size 1.25 position '2'                                                                              
          color 'black' xsys '2' ysys '2' style 'Albany AMT' weight 'bold';    
set sum_mydat;

midpoint=year;                                                                                                                       
   y=number_of_cases_Sum;                                                                                                                            
   text=put(number_of_cases_Sum,3.);  

run;

*create attrmap;
data myattrmap;
	infile datalines;
	input id $6. value $10. fillcolor $8. linecolor $9.;
	datalines;
level no cases  CXA9A9A9 CXA9A9A9
level 1         CX00FFFF CX00FFFF
level 2         CXFF7F50 CXFF7F50
level 3         CXFFF8DC CXFFF8DC
level 4         CX006400 CX006400
;
run;

*create chart with labels, the totals of each bar should be written on top of the bar;

proc sgplot data =merge_mydat dattrmap=myattrmap sganno=anno pad=(bottom=5%) noautolegend noborder;
xaxis grid type=discrete discreteorder=data;
vbarparm category= year  response=rel_freq /group=level groupdisplay=stack attrid=level seglabel seglabelattrs=(size=0.25 color="CXFDF5E6") 
seglabelfitpolicy=none barwidth=0.6 missing;
xaxis  display= (nolabel) valueattrs=(family="verdana" size=8pt) fitpolicy=rotate ValuesRotate=Vertical;
yaxis  display= (nolabel) valueattrs=(family="verdana" size=8pt);
keylegend / location=outside position=bottomright across=0 title=" " valueattrs=(size=2 family="verdana") outerpad=(top=0.2cm) noborder;
run; 

 

1 ACCEPTED SOLUTION

Accepted Solutions
GraphGuy
Meteorite | Level 14

Since nobody jumped on this one, I'll go ahead and finish it...

Here's how to create an annotate dataset suitable for use with sgplot. Hopefully I've understood the values you're wanting on the bar segments, and the value you wanted annotated at the top of each bar (... if not, it should be easy for you to modify).

 

proc sql noprint;
create table myanno as
select unique year, sum(number_of_cases) as year_sum
from mydat
group by year;
quit; run;

data myanno; set myanno;
length label $100 anchor x1space y1space textweight $50;
layer="front";
function="text"; textcolor="gray44"; textsize=10; textweight='bold';
width=100; widthunit='percent'; 
label=trim(left(put(year_sum,comma8.0))); 
x1space='datavalue'; 
y1space='datapercent'; 
x1=year;
y1=100;
anchor='bottom'; 
run;

title "My Custom Bar Chart, with annotated sum at top of bar";
proc sgplot data=mydat dattrmap=myattrmap sganno=myanno pad=(bottom=5%) noborder;
vbarparm category=year  response=rel_freq /group=level groupdisplay=stack attrid=level 
 seglabel seglabelattrs=(size=8pt color=gray55) seglabelformat=percentn7.2
 seglabelfitpolicy=none barwidth=0.6 missing;
xaxis grid type=discrete discreteorder=data;
xaxis display=(nolabel) valueattrs=(family="verdana" size=8pt) fitpolicy=rotate ValuesRotate=Vertical;
yaxis display=(nolabel) valueattrs=(family="verdana" size=8pt) offsetmax=.10;
keylegend / location=outside position=bottomright across=0 title="" valueattrs=(size=8pt family="verdana") outerpad=(top=0.2cm) noborder;
run; 

bar_pct_anno.png

View solution in original post

8 REPLIES 8
ChrisNZ
Tourmaline | Level 20

1. Copy and paste the code you provided: It doesn't run.

 

2. You plot percentages (max value Y=1 ) and use YSYS=2 (data coordinates) but your annotate data has Y in the hundreds

Anita_n
Pyrite | Level 9
Is the max value allowed for Y=1?
ChrisNZ
Tourmaline | Level 20

>Is the max value allowed for Y=1?

Y displayed as 100% means Y=1 right?

So your chart displays Y values between 0 and 1. Now your annotate data specifies text to display at Y=300. How do you want this to happen?

@GraphGuy It seems out-of-plot annotate positions don't generate notes for SG like they do for SAS/Graph? 

 

[Edit:

Looking at @GraphGuy 's code, I see that the SG annotate variables are different from the SAS/Graph ones.

Seemingly like the OP, I am an old SAS/Graph hand and didn't catch that.

Again, notes should be printed in the log when the annotate data is not usable though. They really should.]

Anita_n
Pyrite | Level 9
okay, thanks for the explanation
GraphGuy
Meteorite | Level 14

Looks like you're trying to use the old SAS/Graph (gplot) style annotate dataset, with the new Base SAS (sgplot) graphics - that won't work. 🙂 

 

Here's a slightly cleaned-up version of your code, which might be a good starting place for you (or someone to help) add the sgplot-style annotate. (Does this graph look like you're wanting, so far?)

 

data mydat;
infile datalines;
input year	level $12.	number_of_cases;
datalines;
2001	1	        90	
2001	2	        1	 
2001	3	        5	 
2001	4	        22	
2001	no cases	35	
2002	1	        99	
2002	2	        4	 
2002	3	        2	 
2002	4	        55	
2002	no cases	39	
2003	1	        200
2003	2	        45	
2003	3	        77	
2003	4	        39	
2003	no cases	23	
2004	1	        205
2004	2	        19	
2004	3	        29	
2004	4	        15	
2004	no cases	18	
2005	1	        159
2005	2	        323
2005	3	        99	
2005	4	        10	
2005	no cases	28	
2006	1	        88	
2006	2	        10	
2006	3	        16	
2006	4	        55	
2006	no cases	8	 
;
run;

proc sql noprint;
create table mydat as
select mydat.*, 
sum(number_of_cases) as number_of_cases_sum
from mydat
group by year
order by year, level;
quit; run;

data mydat; set mydat;
format rel_freq percent7.0;
rel_freq=number_of_cases/number_of_cases_sum;
run;

data myattrmap;
	infile datalines;
	input id $6. value $10. fillcolor $8.;
	datalines;
level no cases  CXA9A9A9 
level 1         CX00FFFF 
level 2         CXFF7F50 
level 3         CXFFF8DC 
level 4         CX006400 
;
run;

proc sgplot data=mydat dattrmap=myattrmap pad=(bottom=5%) noborder;
vbarparm category=year  response=rel_freq /group=level groupdisplay=stack attrid=level 
 seglabel seglabelattrs=(size=8pt color=gray55) seglabelformat=percentn7.2
 seglabelfitpolicy=none barwidth=0.6 missing;
xaxis grid type=discrete discreteorder=data;
xaxis display=(nolabel) valueattrs=(family="verdana" size=8pt) fitpolicy=rotate ValuesRotate=Vertical;
yaxis display=(nolabel) valueattrs=(family="verdana" size=8pt);
keylegend / location=outside position=bottomright across=0 title="" valueattrs=(size=8pt family="verdana") outerpad=(top=0.2cm) noborder;
run; 

bar_pct.png

GraphGuy
Meteorite | Level 14

Since nobody jumped on this one, I'll go ahead and finish it...

Here's how to create an annotate dataset suitable for use with sgplot. Hopefully I've understood the values you're wanting on the bar segments, and the value you wanted annotated at the top of each bar (... if not, it should be easy for you to modify).

 

proc sql noprint;
create table myanno as
select unique year, sum(number_of_cases) as year_sum
from mydat
group by year;
quit; run;

data myanno; set myanno;
length label $100 anchor x1space y1space textweight $50;
layer="front";
function="text"; textcolor="gray44"; textsize=10; textweight='bold';
width=100; widthunit='percent'; 
label=trim(left(put(year_sum,comma8.0))); 
x1space='datavalue'; 
y1space='datapercent'; 
x1=year;
y1=100;
anchor='bottom'; 
run;

title "My Custom Bar Chart, with annotated sum at top of bar";
proc sgplot data=mydat dattrmap=myattrmap sganno=myanno pad=(bottom=5%) noborder;
vbarparm category=year  response=rel_freq /group=level groupdisplay=stack attrid=level 
 seglabel seglabelattrs=(size=8pt color=gray55) seglabelformat=percentn7.2
 seglabelfitpolicy=none barwidth=0.6 missing;
xaxis grid type=discrete discreteorder=data;
xaxis display=(nolabel) valueattrs=(family="verdana" size=8pt) fitpolicy=rotate ValuesRotate=Vertical;
yaxis display=(nolabel) valueattrs=(family="verdana" size=8pt) offsetmax=.10;
keylegend / location=outside position=bottomright across=0 title="" valueattrs=(size=8pt family="verdana") outerpad=(top=0.2cm) noborder;
run; 

bar_pct_anno.png

Anita_n
Pyrite | Level 9

@GraphGuy: Great job Robert, that is exactly what I wanted. You have really helped me 😊

ChrisNZ
Tourmaline | Level 20

@GraphGuy Can you pass to the SG team the request to add notes in the log when the annotate data is not suitable, like SAS/Graph does?

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

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.

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
  • 8 replies
  • 2578 views
  • 4 likes
  • 3 in conversation