Graphically Speaking

Diagonal tick values

Fitting of long category values on a x-axis is usually a challenge. With SAS 9.4, the SGPLOT procedure tries to fit the values by first splitting the values at white space to see if the values will fit in the space available. This normally works well for a small number of categories with long labels as shown below.

proc sgplot data=sashelp.heart;
vbar deathcause;
run;

SAS Certifications Tutorials and Materials, SAS Certifications Guide, SAS Certifications, SAS Certifications Syllabus

Personally, I prefer this layout for the values when space is available as it is easier to read. If the split values will not fit in the space per value, then the values are rotated. Prior to SAS 9.4, the splitting of tick values was not supported, and the only option for long category values was to rotate the values at a 45 degree angle as shown below. In the program, “Carssubset” is a reduced data set for Asian Sports cars as you can see in the linked SAS program.

proc sgplot data=carssubset;
vbar model / response=mpg_city dataskin=matte fillattrs=graphdata2;
run;

SAS Certifications Tutorials and Materials, SAS Certifications Guide, SAS Certifications, SAS Certifications Syllabus

The SGPLOT procedure now supports a VALUESROTATE option that supports Diagonal, for the above result and Vertical that rotates the values 90 degrees, in the same orientation as the y-axis label. However, there is no option to rotate the values in the other diagonal direction, bottom-left to top-right (Diagonal2).

As user requests started coming in for the ability to rotate the tick values in the Diagonal2 direction, we added this value to the VALUESROTATE option and this will be available with SAS 9.40M5 release later this year. Also, a FITPOLICY=STACKED was added that will result in the values displayed in the “Hotel Text” orientation. This is useful in some cases, especially with many Asian languages.

Recently, a user chimed in about the Diagonal2 placement, wanting to know what we could do for him today. Also, a colleague from Europe chimed in with the information that in addition to Excel (which orients the labels like this), this is also the preferred orientation in many parts of Europe. Given that, it would be useful if we could come up (in the interim, prior to SAS 9.40M5) with a way to achieve this without too much pain, as shown below.

SAS Certifications Tutorials and Materials, SAS Certifications Guide, SAS Certifications, SAS Certifications Syllabus

To create the graph above, we have to use SG Annotation. When rendering a complex graph, my preference is to layer multiple plots to get the results. This works well because all plots work together with the axes, and everything gets scaled and placed correctly. But when one needs to do some customization outside the data area (like in this case with the x-axis values) one needs to use SG Annotation.

Now, the process is simple once you understand the basics, and code needed is just a few lines. What we need to do is to find all the category values, and then add them to the annotation data set with a 45 degree rotation placed with the y coordinate just below the x-axis. The x coordinate will be the category value itself, and SGPLOT will do the rest of the work.

The annotation code and a few observations from the data set are shown below. In this case all values for “model” are unique, but this will work for multiple occurences too.

data anno;
set carssubset(keep=model);
by model;
if first.model then do;
id=’a’; function=’text’; x1space=’datavalue’; y1space=’wallpercent’; label=model;
xc1=model; y1=-3; anchor=’right’; width=60; rotate=45; output;
end;
run;

One obervation is created for each category value. The Function is “Text” and the Label is the text string to be drawn. The x coordinate (XC1) is the category value itself in data space (X1Space = “DataValue”). XC1 is used instead of X1 because the value is character. The y coordinate (Y1) is 3% below the wall (Y1Space = “WallPercent”). The text is anchored on the right with a rotation of 45 degrees.

SAS Certifications Tutorials and Materials, SAS Certifications Guide, SAS Certifications, SAS Certifications Syllabus

proc sgplot data=carssubset sganno=anno pad=(bottom=45pct left=25pct);
vbar model / response=mpg_city dataskin=pressed
filltype=gradient fillattrs=graphdata3;
xaxis display=(novalues nolabel);
run;

In the program code, the x-axis tick values are suppressed, and padding is added to bottom and left to make space for the new values. The category values in the data set need not be in any particular order. They just have to be there, with the x-value of the category variable. The procedure will automatically put them where they need to go. You can even rename some of the labels if you want. If you change the order of the x-axis in the code, the same annotation data set can still be used, and the procedure will map the values to the right place as shown below. For completeness, we may need to add back the x-axis label using annotation

SAS Certifications Tutorials and Materials, SAS Certifications Guide, SAS Certifications, SAS Certifications Syllabus

Having shown you how to get the Diagonal2 orientation with SAS 9.40M3 version, I would be remiss to not say that for long category labels, one should also consider using a HBAR, which may also give good results.

SAS Certifications Tutorials and Materials, SAS Certifications Guide, SAS Certifications, SAS Certifications Syllabus

Full SAS 9.40M3 code:

%let gpath=C:\;
%let dpi=200;
ods html close;
ods listing gpath=”&gpath” image_dpi=&dpi;

/*–Graph with regular axis–*/
ods graphics / reset width=5in height=3in imagename=’Heart1′;
proc sgplot data=sashelp.heart;
vbar deathcause;
run;

/*–Subset number of cars–*/
data carssubset;
set sashelp.cars(where=(origin=’Asia’ and type=’Sports’));
run;

/*–Sort by Model–*/
proc sort data=carssubset out=carssubset;
by model;
run;

/*–Graph with regular axis–*/
ods graphics / reset width=5in height=3in imagename=’Cars1′;
proc sgplot data=carssubset;
vbar model / response=mpg_city dataskin=matte fillattrs=graphdata2;
run;

/*–Find all categories–*/
proc means data=carssubset noprint;
class model;
output out=cars(where=(_type_ eq 1))
mean=mean;
run;

/*–Create annotation data set for all categories–*/
data anno;
set carssubset(keep=model);
by model;
if first.model then do;
id=’a’; function=’text’; x1space=’datavalue’; y1space=’wallpercent’; label=model;
xc1=model; y1=-3; anchor=’right’; width=60; rotate=45; output;
end;
run;

/*–Graph with custom diagonal axis–*/
ods graphics / reset width=5in height=3in imagename=’Cars2′;
proc sgplot data=carssubset sganno=anno pad=(bottom=45pct left=25pct);
vbar model / response=mpg_city dataskin=pressed
filltype=gradient fillattrs=graphdata3;
xaxis display=(novalues nolabel);
run;

/*–Graph with custom diagonal axis–*/
ods graphics / reset width=5in height=3in imagename=’Cars3′;
proc sgplot data=carssubset sganno=anno pad=(bottom=45pct left=25pct);
vbar model / response=mpg_city dataskin=pressed
filltype=gradient fillattrs=graphdata4;
xaxis display=(novalues nolabel) reverse;
run;

/*–HBar–*/
ods graphics / reset width=4in height=3in imagename=’Cars_HBar’;
proc sgplot data=carssubset;
hbar model / response=mpg_city fillattrs=graphdata6 dataskin=pressed filltype=gradient;
yaxis valueattrs=(size=7);
run;

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s