Dear all,
I created a graph using sgpanel but since my legend is too large, it compresses the graph which doesn't make it look nice. On searching through the internet I came accross this article which says Microsoft Word - More to it than Meets the Eye.doc (lexjansen.com)
a Legend can be created seperate from the graph using an annotate facility. I have being tring to follow up the description but am not really getting it.
Could someone maybe help?
I used sashelp.cars here as test data. Here is my code:
I tried to transform sashelp.cars data to look like my data:
data have;
length make_combi $50;
set sashelp.cars;
if _n_ <= 20 then do; make_combi="Accura"; end;
if _n_ >= 21 and _n_<=40 then do; make_combi= "Dodge+Buick+Ford" ; end;
if _n_ >= 41 and _n_<=60 then do; make_combi= "Dodge+Buick+GMC"; end;
if _n_ >= 61 and _n_<=75 then do; make_combi="Accura+Audi+BMW"; end;
if _n_ >= 76 and _n_<=90 then do; make_combi="Accura+Buick"; end;
if _n_ >= 91 and _n_<=100 then do; make_combi= "Chevrolet"; end;
if _n_ >= 101 and _n_<=120 then do; make_combi= "Honda"; end;
if _n_ >= 121 and _n_<=160 then do; make_combi="Accura+Buick+BMW"; end;
if _n_ >= 161 and _n_<=170 then do; make_combi= "Hummer"; end;
if _n_ >=171 and _n_<=180 then do; make_combi= "Hummer+Buick" ; end;
if _n_ >= 181 and _n_<=190 then do; make_combi= "Hummer+Buick+BMW"; end;
if _n_ >= 191 and _n_<=200 then do; make_combi= "Hummer+Buick+Hyundai"; end;
if _n_ >= 201 and _n_<=210 then do; make_combi="Accura+Buick+Chevrolet"; end;
if _n_ >= 211 and _n_<=220 then do; make_combi="Cadillac"; end;
if _n_ >= 221 and _n_<=230 then do; make_combi="Chrysler"; end;
if _n_ >= 231 and _n_<=240 then do; make_combi="Chrysler+Audi"; end;
if _n_ >= 281 and _n_<=290 then do; make_combi= "Chrysler+Buick" ; end;
if _n_ >= 291 and _n_<=300 then do; make_combi= "Jaguar"; end;
if _n_ >= 301 and _n_<=310 then do; make_combi="Chrysler+Buick+BMW"; end;
if _n_ >= 311 and _n_<=320 then do; make_combi= "Jaguar+BMW"; end;
if _n_ >= 321 and _n_<=330 then do; make_combi="BMW"; end;
if _n_ >= 231 and _n_<=340 then do; make_combi= "Jaguar+Hyundai"; end;
if _n_ >= 341 and _n_<=360 then do; make_combi="Dodge" ; end;
if _n_ >= 361 and _n_<=380 then do; make_combi= "Dodge+Buick+BMW" ; end;
if _n_ >= 381 and _n_<=390 then do; make_combi="Dodge+Chevrolet" ; end;
if _n_ >= 391 and _n_<=400 then do; make_combi= "Jaguar+Audi"; end;
if _n_ >=401 and _n_<=420 then do; make_combi= "Dodge+Audi"; end;
if _n_ >= 421 and _n_<=440 then do; make_combi= "Dodge+Buick" ; end;
keep make type make_combi;
run;
I then created the format using proc format as described in the paper
proc format;
value BarLabel 1="Accura"
2= "Accura+Audi+BMW"
3= "Accura+Buick"
4= "Accura+Buick+BMW"
5= "Accura+Buick+Chevrolet"
6= "Cadillac"
7= "Chrysler"
8= "Chrysler+Audi"
9= "Chrysler+Buick"
10= "Chrysler+Buick+BMW"
11= "BMW"
12= "Dodge"
13= "Dodge+Chevrolet"
14= "Dodge+Audi"
15= "Dodge+Buick"
16= "Dodge+Buick+BMW"
17= "Dodge+Buick+Ford"
18= "Dodge+Buick+GMC"
19= "Chevrolet"
20= "Honda"
21= "Hummer"
22= "Hummer+Buick"
23= "Hummer+Buick+BMW"
24= "Hummer+Buick+Hyundai"
25= "Ford"
26= "Infiniti"
27= "Hyundai"
28= "Audi"
29= "Audi+Hyundai"
30= "Jaguar"
31= "Jaguar+BMW"
32= "Jaguar+Hyundai"
33= "Jaguar+Audi"
34= "Jaguar+Audi+Hyundai"
35= "Jaguar+Buick"
36= "Jaguar+Buick+BMW"
37= "Jaguar+Buick+Chevrolet"
38= "MINI"
39= "Buick"
40= "Buick+BMW"
41= "Buick+Chevrolet"
42= "Buick+Ford"
43= "Buick+Hyundai"
44= "Buick+GMC"
45= "GMC"
;
value BarColor 1= "CX00FA9A"
2= "CX0000FF"
3= "CXFFE4C4"
4= "CX696969"
5= "CX8B0000"
6= "CX5F9EA0"
7= "CXB8860B"
8= "CX8FBC8F"
9= "CX1E90FF"
10= "CXADFF2F"
11= "CXFFEBCD"
12= "CXF08080"
13= "CX00CED1"
14= "CXFFDAB9"
15= "CXB22222"
16= "CX00FFFF"
17= "CXFF8C00"
18= "CXE0FFFF"
19= "CX4682B4"
20= "CXE0FFFF"
21= "CX40E0D0"
22= "CX008080"
23= "CX8B4513"
24= "CX4169E1"
25= "CXBC8F8F"
26= "CX696969"
27= "CXD2691E"
28= "CX7FFF00"
29= "CXBDB76B"
30= "CXE9967A"
31= "CX483D8B"
32= "CXDCDCDC"
33= "CX2F2F2F"
34= "CXFFF0F5"
35= "CXFF0000"
36= "CX808000"
37= "CXFFDEAD"
38= "CX7B68EE"
39= "CX0000CD"
40= "CX20B2AA"
41= "CXADFF2F"
42= "CXFFD700"
43= "CXFF1493"
44= "CX8B008B"
45= "CX8FBC8F"
;
run;
Here is the code for the annotate data, the %cbar is not working (so the colors are also not showing) that is why I commented it out, Or maybe am doing something wrong. Or there is a better way to do that
data want;
set have;
do i=1 to max(_n_);
BarLabel= put(i, BarLabel.);
BarColor= put(i, BarColor.);
%annomac;
%bar(4,44-(i*3),8,42-(i*3),black, 0, e);
*%cbar(4,44-(i*3), 8,42-(i*3), BarColor,3,s);
%label(10,43.3-(i*3), BarLabel, black, 0,0,0.5,'Arial',6);
end;
run;
to create the legend using
filename legend "mypath\test2.gif";
goptions device=gif gsfname=legend hsize=5in vsize=12in;
proc gslide anno=want;
run;
quit;
Thanks for any help
You may need to explain what you think
do i=1 to max(_n_)
does in that data step.
Your first data step code shows that you are aware that _n_ could be as large as 440 and your have set would have that many records. So for any _n_ > then 45 you have more calls to the formats than you have defined. Unless you did some thing to the HAVE data set before that want.
First thing when using helper macros like %annomac, they should be called before any data step or procedure that want to use the result. There are timing issues related.
Second, for a legend, which typically has a fixed number of elements, you likely do not need the use the HAVE data set at all as you only want the 45 elements you have defined.
An obnoxious result from your internet search is is that you are using the older SAS/Graph annotate macros, %annomac which do not align with the newer SGPLOT/SGPanel and related graphics programs. There significant differences in what the macros do and how they address space. That paper appears to be about 14 years old.
You might look into %sganno and use the sg annotate macros instead.
Suggestion: since your example uses the SAS supplied Sashelp.cars, thank you for providing a set, provide your current SGPANEL code using that same set. Likely the option NOAUTOLEGEND will figure into a solution to create the graph without the legend and then add one.
@ballardw thanks for the comments . Here is the code for my sgpanel plot. I wish to seperate the legend from the plot and probably use ods gridded layout to place these side by side
data have;
infile datalines;
input make_combi $20. period $14. status amount;
datalines;
Accura before 2005 1 1
Accura+Buick 2005 to 2015 1 7
Accura+Buick before 2005 1 10
Accura+Buick since 2015 1 11
Accura+Buick+Audi 2005 to 2015 1 1
Chrysler+BMW since 2015 1 1
Dodge+Buick 2005 to 2015 1 13
Dodge+Buick before 2005 1 28
Dodge+Buick since 2015 1 21
Honda before 2005 1 3
Honda since 2015 1 1
Honda+Buick 2005 to 2015 1 49
Honda+Buick before 2005 1 29
Honda+Buick since 2015 1 50
Honda+Buick+Audi 2005 to 2015 1 14
Honda+Buick+Audi before 2005 1 1
Honda+Buick+Audi since 2015 1 9
Hyundai 2005 to 2015 1 1
Hyundai before 2005 1 4
Hyundai+BMW+Ford 2005 to 2015 1 1
Hyundai+Buick 2005 to 2015 1 8
Hyundai+Buick before 2005 1 15
Hyundai+Buick since 2015 1 13
Hyundai+Buick+Audi 2005 to 2015 1 2
Hyundai+Buick+Audi before 2005 1 1
Hyundai+Buick+Audi since 2015 1 2
Hyundai+Buick+MINI before 2005 1 1
Hyundai+Buick+MINI since 2015 1 6
Buick 2005 to 2015 1 3
Buick before 2005 1 2
Buick since 2015 1 2
Buick+MINI since 2015 1 1
Accura+Buick before 2005 2 13
Accura+Buick since 2015 2 1
Accura+Buick+MINI before 2005 2 1
Chrysler+Buick 2005 to 2015 2 3
Chrysler+Buick since 2015 2 1
Chrysler+Buick+Audi since 2015 2 1
Audi 2005 to 2015 2 10
Audi before 2005 2 5
Audi since 2015 2 21
Dodge+MINI before 2005 2 1
Dodge+BMW 2005 to 2015 2 1
Dodge+Buick 2005 to 2015 2 7
Dodge+Buick before 2005 2 26
Dodge+Buick since 2015 2 1
Dodge+Buick+Audi 2005 to 2015 2 1
Dodge+Buick+Infiniti 2005 to 2015 2 2
Dodge+Buick+Infiniti before 2005 2 7
Honda before 2005 2 1
Honda+Buick 2005 to 2015 2 3
Honda+Buick before 2005 2 11
Honda+Buick since 2015 2 2
Honda+Buick+Audi 2005 to 2015 2 1
BMW before 2005 2 1
Hyundai before 2005 2 2
Hyundai since 2015 2 1
Hyundai+Audi since 2015 2 3
Hyundai+Buick 2005 to 2015 2 3
Hyundai+Buick before 2005 2 9
Hyundai+Buick since 2015 2 2
Hyundai+Buick+Audi 2005 to 2015 2 1
Hyundai+Buick+MINI 2005 to 2015 2 1
Hyundai+Buick+MINI since 2015 2 1
Ford 2005 to 2015 2 2
Buick before 2005 2 3
Buick since 2015 2 1
Buick+Audi since 2015 2 5
Buick+GMC 2005 to 2015 2 1
Buick+Ford since 2015 2 1
Infiniti 2005 to 2015 2 1
Infiniti before 2005 2 5
Accura before 2005 3 1
Accura+BMW+Audi since 2015 3 1
Accura+Buick before 2005 3 2
Accura+Buick since 2015 3 1
Chrysler+BMW before 2005 3 1
Chrysler+Buick 2005 to 2015 3 3
Chrysler+Buick since 2015 3 2
Audi 2005 to 2015 3 7
Audi before 2005 3 7
Audi since 2015 3 6
Dodge+BMW before 2005 3 1
Dodge+Buick 2005 to 2015 3 2
Dodge+Buick before 2005 3 9
Dodge+Buick since 2015 3 5
Dodge+Buick+Infiniti 2005 to 2015 3 1
Dodge+Buick+Infiniti before 2005 3 2
Dodge+Buick+Infiniti since 2015 3 1
MINI before 2005 3 1
MINI since 2015 3 1
Honda+Buick 2005 to 2015 3 1
Honda+Buick before 2005 3 2
Honda+Buick since 2015 3 1
GMC since 2015 3 2
BMW since 2015 3 1
BMW+Ford 2005 to 2015 3 1
Hyundai before 2005 3 2
Hyundai since 2015 3 1
Hyundai+Ford since 2015 3 1
Hyundai+Buick 2005 to 2015 3 2
Hyundai+Buick before 2005 3 3
Hyundai+Buick since 2015 3 5
Hyundai+Buick+MINI before 2005 3 1
Ford 2005 to 2015 3 1
Ford before 2005 3 1
Buick before 2005 3 3
Buick+GMC 2005 to 2015 3 1
Buick+GMC since 2015 3 1
Infiniti before 2005 3 6
Accura+Buick before 2005 4 5
Accura+Buick+MINI before 2005 4 1
Audi 2005 to 2015 4 7
Audi before 2005 4 5
Audi since 2015 4 3
Dodge+Buick before 2005 4 7
Dodge+Buick since 2015 4 1
Dodge+Buick+GMC before 2005 4 1
Dodge+Buick+Infiniti before 2005 4 2
GMC 2005 to 2015 4 1
GMC since 2015 4 1
Hyundai before 2005 4 1
Hyundai since 2015 4 2
Hyundai+Audi before 2005 4 1
Hyundai+BMW 2005 to 2015 4 1
Hyundai+Buick 2005 to 2015 4 2
Hyundai+Buick before 2005 4 1
Hyundai+Buick since 2015 4 1
Hyundai+Buick+MINI before 2005 4 1
Hyundai+Buick+MINI since 2015 4 1
Ford before 2005 4 1
Ford since 2015 4 2
Buick before 2005 4 2
Buick+Audi 2005 to 2015 4 1
Buick+Audi since 2015 4 1
Buick+GMC 2005 to 2015 4 1
Accura+Buick since 2015 5 2
Chrysler+Buick before 2005 5 1
Chrysler+Buick since 2015 5 1
Audi before 2005 5 1
Dodge+Buick+Infiniti before 2005 5 2
Honda +Buick+Ford 2005 to 2015 5 1
Hyundai+Audi 2005 to 2015 5 2
Hyundai+Buick before 2005 5 3
Hyundai+Buick since 2015 5 1
Hyundai+Buick+MINI since 2015 5 1
Ford 2005 to 2015 5 1
Ford since 2015 5 2
Buick 2005 to 2015 5 1
Buick+GMC 2005 to 2015 5 1
Buick+GMC since 2015 5 2
Buick+Infiniti 2005 to 2015 5 1
Audi before 2005 6 1
GMC before 2005 6 1
Hyundai since 2015 6 1
Hyundai+Buick before 2005 6 1
Ford before 2005 6 1
Buick 2005 to 2015 6 1
Buick before 2005 6 1
Buick+Audi before 2005 6 1
Buick+MINI 2005 to 2015 6 1
Buick+MINI before 2005 6 1
Buick+GMC before 2005 6 1
Buick+GMC since 2015 6 1
Buick+Ford since 2015 6 1
Audi before 2005 7 1
Dodge before 2005 7 1
Hyundai+Buick before 2005 7 1
Ford 2005 to 2015 7 1
Infiniti since 2015 7 1
Hyundai+Buick+MINI 2005 to 2015 8 1
Ford 2005 to 2015 9 1
;
run;
ods graphics / maxlegendarea=100 width=4in height=3in;
proc sgpanel data=have pad=(bottom=5%) noautolegend;
panelby period/ columns=3 novarname noborder headerattrs=(color=black family="arial" weight=bold size=7pt)
nowall sort=data;
vbar status /response=amount group=make_combi groupdisplay=stack attrid=make_combi missing;
rowaxis grid display=(nolabel) valueattrs=(size=5pt family="arial" color=black)
grid minor ;
colaxis display=(nolabel) discreteorder=unformatted valueattrs=(size=5pt family=arial color=dimgray) valuesrotate=diagonal2
;
keylegend / position=bottom title="" valueattrs=(size=4pt family=arial) outerpad=(top=0.2cm) sortorder=ascending noborder;
run;
Or if there is a better alternative, I will be grateful
Before going on I am going to make a style suggestion that may help down the road. Instead of creating text values like "before 2005" "2005 to 2015" and "since 2015" that you use a NUMERIC variable and custom format to display the desired text.
The groups created by a custom format will allow things to sort properly in general. So if you had something like
Proc Format; value yeargroup 2000- 2004 = 'before 2005' 2005-2015 = '2005 to 2015' 2016-2025 = 'since 2015' ; run;
then with a variable holding the actual year you have some flexibility. For instance a different format with the same data set could great groups/graphs of different periods.
Second relates to Input statements using fixed column syntax and data that contains tabs. You may not realize that what you created below has tab characters between the columns. Which means that when others copy the code and paste into an editor that their tab settings may mean that the code won't run properly, especially when you use a FIXED format, i.e Period $14. to read it. My version of your data set has 16 values for Period as the fixed columns cut off many values at the front and then include some of the values of status, leaving amount missing.
A second advantage of reading your Period as a single year would be not having to do anything to read in the spaces between words, which is why I assume you used a fixed column input.
@ballardw okay, thanks for that suggestion
Is there really a solution to this problem?
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
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.