proc template

1月 072014
 

Because I began my SAS career in the Publications division, I like to think that I have a keen eye when it comes to SAS documentation. When I first visited the SAS 9.4 online documentation, I immediately noticed that it had a different look. Examine the image below; can you see what I mean? (Click on the image to see a larger version.)

Aside from a few layout enhancements and more helpful details, I noticed the use of a different typeface for the text. It's a font that I didn't recognize, and I wondered how it had been installed on my system.

It turns out that this font face (named "Lato") is not installed on my system; it's a web font. A web font is downloaded and rendered "on the fly" by your web browser. This gives the web designer more control over the exact appearance of the text, even across different operating systems and devices that share only a small subset of generic font styles.

There are different sources for web fonts. Some are free to use, while others require a nominal licensing fee. If you have a particular typeface that is important to your company brand, it might be worth a licensing fee to ensure that this typeface is used consistently in all of your web content. However, the SAS documentation (and many other sites) use the free Google Fonts.

After I learned all of this I wondered: how can I use web fonts in SAS ODS output?

Specifying a web font in ODS HTML

There are three ways to "import" a web font in your HTML content:

  1. using a <link> tag to reference a directive from an external style
  2. using an @import directive from within a CSS file or <style> tag
  3. using JavaScript to dynamically insert a web font style reference into the page.

The Google Font web site provides code snippets for each of these in HTML.

Once you import the font, you must then reference the font name in CSS "font-family" style attributes for the different element classes that you want to affect. For example, if you want ODS tabular data to use the Lato font, you must change the "data" class to include it:

.data {
  font-family: 'Lato', sans-serif;
}

I decided that the <link>-tag approach was the simplest method to import the web font. I copied the <link>-tag directives from the Google Fonts entry for Lato and Droid Sans, and then "injected" them into the ODS HTML output by using the HEADTEXT option. Then I used PROC TEMPLATE to modify the style attributes for specific ODS-related style classes; these attributes will translate into CSS when SAS creates your HTML. Here's the program:

/* These snippets copied from http://www.google.com/fonts facility    */
/* Macro for HEADTEXT option, since the value cannot exceed 256 chars */
%macro ods_html_webfont;
<link href='http://fonts.googleapis.com/css?family=Lato:400,700' 
  rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Droid+Sans:400,700' 
  rel='stylesheet' type='text/css'>
%mend;
 
proc template;
  define style webfont;
    /* for this example, inherit existing style elements from HTMLBLUE */
    parent=styles.htmlblue;
  style header from header /
    fontfamily="'Droid Sans', sans-serif";
  style data, body from _self_ /
    fontfamily="'Lato', sans-serif";
  class titlesandfooters /
    fontfamily="'Lato', sans-serif";
  end;
run;
 
ods html (id=wf)
   file="c:\temp\wf_test.html"(title="Web Fonts Test") 
   style=webfont 
   headtext="%ods_html_webfont";
title "A new look for my report";
proc means data=sashelp.cars;
run;
ods html (id=wf) close;

Here's the result as seen in my Chrome browser:

(Want to compare this to a version that doesn't use web fonts?)

Limitations of web fonts

Before you consider using web fonts in all of your SAS-generated content, there are a few restrictions that you should review:

  • Web fonts can be used only in HTML output -- output that you intend to display in a web browser. The browser will download and render the font based on CSS or JavaScript directives. This means that this technique won't work for RTF or PDF output.
  • Web fonts can apply to textual content only, and not to images that are generated by SAS graphical procedures. SAS graphical output is usually rendered into an image file (such as a PNG file) within your SAS session. The appearance is controlled by SAS styles that are defined in your SAS session, and any referenced fonts must be accessible to SAS.
  • Because web fonts must be downloaded by the browser as the HTML page loads, this can have an impact on how quickly the page is rendered. Each Google web font provides some guidance about this potential impact. For the best response, include references to the minimum number of typefaces that you need for the content.
  • And of course, for a web font to download you must be connected to the Internet. It's a good idea to always specify a fallback font family (ex: sans-serif) in your styles so that even if your web font can't load, your style still provides some cue for how to render the text.
tags: CSS, ods, PROC TEMPLATE, SAS 9.4, SAS tips, web fonts
8月 312013
 
This week's SAS tip is from Kevin D. Smith and his new book PROC TEMPLATE Made Easy: A Guide for SAS Users. Kevin is a software developer at SAS with extensive experience supporting PROC TEMPLATE and underlying ODS technologies. We're excited that Kevin decided to write his book and hope [...]
5月 152013
 
We’re just coming back from SAS Global Forum, and what a show! SAS Books was there to provide users with the highest-quality resources for learning SAS, and our users were there to tell us what new books they were most looking forward to reading. Kevin Smith's PROC TEMPLATE Made Easy: [...]
3月 182013
 
If you’ve been following along this year, you know that I spoke to Sanjay Matange last month. Sanjay has a top-selling book to his credit and juggles work, speaking engagements and book writing. Another SAS employee who will soon add “Author” to his name is Kevin D. Smith. Kevin is [...]
10月 032011
 
Most SUG presentations are written in PowerPoint – they may even be written in Word first, and then fancied up a bit in PowerPoint – but they are rarely written in SAS. But Louise Hadden, from Abt Associates Inc, had a need to produce a lot of PDF presentations. She [...]
7月 262011
 
contributed by SAS Publishing's Shelly Goodin For me, SAS Global Forum wouldn't be the same without getting a chance to catch up with SAS Press author Phil Holland. Besides being extremely knowledgeable about SAS (he's been using it since 1981), he is as enterprising and approachable as his popular book [...]
6月 202011
 

The scatterplot is one of the most ubiquitous, and useful graphics. It's also very basic. One of its shortcomings is that it can hide important aspects of the marginal distributions of the two variables. To address this weakness, you can add a histogram of each margin to the plot. We demonstrate using the SF-36 MCS and PCS subscales in the HELP data set.

SAS
SAS provides code to perform this using proc template and proc sgrender. These procedures are not intended for casual or typical SAS users. Its syntax is, to our eyes, awkward. This is roughly analogous to R functions that simply call C routines. Nonetheless, it's possible to adapt code that works. The code linked above was edited to set the transparency to 0 and to change the plotted symbol size to 5 from 11px. These options appear in the scatterplot statement about midway through the code.

Once the edited code is submitted, the following lines produce the plot shown above.

proc sgrender data="C:\book\help.sas7bdat" template=scatterhist;
dynamic YVAR="mcs" XVAR="pcs"
TITLE="MCS-PCS Relationship";
run;


R
For R, we adapted some code found in an old R-help post to generate the following function. The mtext() function puts text in the margins and is used here to label the axes. The at option in that function centers the label within the scatterplot data using some algebra.

scatterhist = function(x, y, xlab="", ylab=""){
zones=matrix(c(2,0,1,3), ncol=2, byrow=TRUE)
layout(zones, widths=c(4/5,1/5), heights=c(1/5,4/5))
xhist = hist(x, plot=FALSE)
yhist = hist(y, plot=FALSE)
top = max(c(xhist$counts, yhist$counts))
par(mar=c(3,3,1,1))
plot(x,y)
par(mar=c(0,3,1,1))
barplot(xhist$counts, axes=FALSE, ylim=c(0, top), space=0)
par(mar=c(3,0,1,1))
barplot(yhist$counts, axes=FALSE, xlim=c(0, top), space=0, horiz=TRUE)
par(oma=c(3,3,0,0))
mtext(xlab, side=1, line=1, outer=TRUE, adj=0,
at=.8 * (mean(x) - min(x))/(max(x)-min(x)))
mtext(ylab, side=2, line=1, outer=TRUE, adj=0,
at=(.8 * (mean(y) - min(y))/(max(y) - min(y))))
}

The results of the following code are shown below.

ds = read.csv("http://www.math.smith.edu/r/data/help.csv")
with(ds, scatterhist(mcs, pcs, xlab="MCS", ylab="PCS"))