Marcia Surratt

11月 282018
One of the great things about programming with SAS® software is that there are many ways to accomplish the same task. And, since SAS often adds new features that can make a task easier, it's important to stay informed.

This blog shows a few samples of graphs and explains how you can use new functionality to make the old graphs look new again. Over the past several releases, SAS has added more options and procedures for ODS Graphics. While your tried-and-true SAS/GRAPH programs still work, ODS Graphics can create modern-looking graphs with less code, while providing more output options. And, ODS Graphics is part of Base SAS, which means that all of these techniques work in SAS University Edition.

Note: All the graphs in this blog are created using the fifth maintenance release of SAS® 9.4M5 (TS1M5). Not all options are available in prior releases of SAS.

Adding special symbols on a graph

The following graph is created with the DATA Step Graphics Interface (DSGI), which draws the horizontal bars and airplanes as well as places the text.

However, the DSGI is not supported in releases after SAS® 9.3. In SAS 9.4 and later, you can create a similar graph using the SYMBOLCHAR statement in the SGPLOT procedure. Using this statement in PROC SGPLOT references the hexadecimal value for the airplane symbol, as shown below:

To create this graph with PROC SGPLOT, submit the following code:

data planes;
   input month $ number;
   xval2=number + 2000;
   format number comma8.;
Jan 13399
Feb 13284
Mar 14725
Apr 15370
May 16252
Jun 15684
Jul 15313
Aug 16005
title1 height=14pt 'Number of Flights at Raleigh Durham International Airport';
title2 height=14pt 'By Month for 2018';
footnote1 height=12pt 'Source: Federal Aviation Administration TFMSC Report (Airport)';
proc sgplot data=planes noautolegend noborder;
hbarbasic month / response=number fillattrs=(color=graydd) nooutline
barwidth=0.5 baselineattrs=(thickness=0px);
symbolchar name=airplane char='2708'x / hoffset=0.3 voffset=0.05;
scatter x=number y=month /markerattrs=(symbol=airplane size=60px
scatter x=xval2 y=month / markerchar=number markercharattrs=(size=14pt);
xaxis offsetmin=0 display=none;
yaxis display=(noline noticks nolabel) valueattrs=(size=14pt)
offsetmin=0.025 offsetmax=0.025;

For information about PROC SGPLOT, see SGPLOT Procedure in SAS® 9.4 ODS Graphics: Procedures Guide, Sixth Edition.

For more information about the SYMBOLCHAR statement, see the section "SYMBOLCHAR Statement" in the "SGPLOT Procedure" chapter of SAS® 9.4 ODS Graphics: Procedures Guide, Sixth Edition.

Assigning colors to data values

The next example graphs show the results for a fictitious ice-cream flavor survey. Because not all the ice cream flavors are present in each survey group, macro code is used to conditionally define the PATTERN statements based on the values in the data.

You can achieve the same more easily by using attribute maps in PROC SGPLOT to associate the attributes, such as color, with data values so that the same color is always associated with the same data value. The following graph, which is similar to the one above, is created using this method:

To create this graph, submit the following code:

/* Create the input data set ICECREAM */
data icecream;
   input @1 Flavor $10. @12 Rank 1. @14 GRP $1.;
Strawberry 2 B
Chocolate  1 B
Vanilla    3 B
Strawberry 2 A
Vanilla    1 A
proc sort;
by grp;
data attrmap;
length value fillcolor linecolor $10;
input value $ fillcolor $;
Strawberry pink
Chocolate CX7B3F00
Vanilla beige
options nobyline;
title "Ice Cream Survey for Group #byval(grp)";
proc sgplot data=icecream dattrmap=attrmap noautolegend;
by grp;
vbar flavor / response=rank group=flavor attrid=barcolors dataskin=pressed;

I changed the colors for the bars in the PROC SGPLOT code so that the bar colors look more like the ice cream that they represent. I also added the DATASKIN= option for the bars to enhance the visual appeal of the bars in the graph.

For more information about attribute maps, see the section Using Attribute Maps to Control Visual Attributes in the SAS® 9.4 ODS Graphics: Procedures Guide, Sixth Edition.

Combining BY-group graphs into a single page

The following graph shows two plots that are created by using PROC GPLOT with a BY statement. The graphs are then paneled side-by-side with the GREPLAY procedure.

You can use the SGPANEL procedure to create the same plots in side-by-side panels. The benefit to this method is that you need only one procedure both to create the plots and to panel them, as shown below:

To create these paneled plots, submit the following code:

proc sgpanel data=sashelp.class;
panelby sex / novarname rows=1 columns=2;
scatter x=age y=height;

Placing symbols and labels on a map

The next graph uses the Annotate facility with the SAS/GRAPH GMAP and GPROJECT procedures to place a symbol and city name at the location of select cities in North Carolina.

Beginning with the fifth maintenance release of SAS 9.4M5 (TS1M5) in 64-bit Windows and 64-bit Linux operating environments, you can use the SGMAP procedure to create such maps. Using this method, you can create maps that show much more detail.

You can use PROC SGMAP with the OPENSTREETMAP, SCATTER, and TEXT statements to create a similar graph, as shown below:

To create this map, submit the following code:

data cities;
input y x city $20.;
35.6125 -77.36667 Greenville 
36.21667 -81.67472 Boone
35.913064 -79.056112 Chapel Hill
data dummy;
input y2 x2;
33.857977 -84.321869
36.548759 -75.460423
data cities;
set cities dummy;
title1 h=10pt 'Place points on a map at city locations';
proc sgmap plotdata=cities;
scatter x=x y=y / markerattrs=(color=red size=10px symbol=circlefilled);
scatter x=x2 y=y2 / markerattrs=(size=0px);
text x=x y=y text=city / textattrs=(size=10pt) position=right;

Because the OPENSTREETMAP statement is used in PROC SGMAP, more detail (for example, cities and roads) is included in the map.

The DUMMY data set adds coordinates to the points that are plotted to modify the display area of the map.

For more information about controlling the display area of the map, see the article How to Control Map Display Area with PROC SGMAP.

For more information about PROC SGMAP, see the SGMAP Procedure chapter in SAS/GRAPH® and Base SAS® 9.4: Mapping Reference.

See also

Many of these features have been covered in more depth within other blog articles. Visit these articles to learn more!
Examples of adding special symbols in your charts using the SYMBOLCHAR statement
Using the new SGMAP procedure to create maps in Base SAS
Adding data-driven features to your charts with ATTRS options
Controlling your graph appearance with DATASKIN and FILLTYPE options

Making great graphs even better with ODS Graphics was published on SAS Users.

9月 152017

ATTRS The SGPLOT procedure (as well as other ODS Graphics procedures) does a great job of creating nice- looking output with very little coding. However, there are times when you want to make adjustments to the output's appearance. For those occasions, we have an ATTRS for that!

The statements in PROC SGPLOT include many options that enable you to change the attributes for parts of the plot. Each of these options ends in ATTRS, which makes them easy to find in code.

Before you can change the attributes, you need to know which part of the plot you want to change.  For example, do you want to change the color of the line, the marker symbol, the size of the label font, and so on? Once you know the part of the graph that you want to change, you can search the PROC SGPLOT documentation for an ATTRS option.

In the following PROC SGPLOT code, we have added some ATTRS options to demonstrate the types of changes you can make to a graph.

proc sgplot data=sashelp.class;
vbar age / stat=freq datalabel datalabelattrs=(size=12pt color=blue)
fillattrs=(color=cx66A5A0) transparency=0.3 
dataskin=matte name='bar' 
legendlabel='Frequency of age';
vline age / stat=percent markers 
markerattrs=(symbol=circlefilled color= cx01665E size=12px) 
lineattrs=(color=cxD05B5B thickness=3px) 
curvelabel='Percent Line' 
curvelabelattrs=(size=11pt style=italic)
curvelabelloc=inside curvelabelpos=min 
name='vline' legendlabel='Percent of age' y2axis;
refline 4 / axis=y lineattrs=(pattern=2 thickness=2px) label='Refline' 
labelattrs=(size=12pt) labelpos=min labelloc=inside;
xaxis valueattrs=(size=10pt color=navy);
yaxis labelattrs=(size=12pt weight=bold) offsetmin=0;
keylegend 'bar' 'vline' / title='My legend' 
titleattrs=(color=blue size=14pt)
valueattrs=(size=12pt) noborder;


The figure below shows the graph that is produced by this PROC SGPLOT code. In the figure, some labels are added to help you identify the part of the graph that is modified using an ATTRS option. Note that this graph depicts only some of the ATTRS options that are available. For other ATTRS options, see the SAS® 9.4 ODS Graphics: Procedures Guide, Sixth Edition for the specific plot statement that you want to use.

In this figure:

  • The LABELATTRS= option enables you to change the color, font family, font weight, font style, and size for the axis or reference line labels.
  • The LINEATTRS= option enables you to change the color, pattern, and thickness for the plot line.
  • The CURVELABELATTRS= option enables you to change the color, font family, font weight, font style, and size for the text that is added by the CURVELABEL= option.
  • The DATALABELATTRS= option enables you to change the color, font family, font weight, font style, and size for the text that is added by the DATALABEL= option.
  • The MARKERATTRS= option enables you to change the color, size, and symbol for the plot markers.
  • The FILLATTRS= option enables you to change the color and transparency of the bar colors.
  • The VALUEATTRS= option enables you to change the color, font family, font weight, font style, and size for the axis tick-value labels or legend value labels.
  • The TITLEATTRS= option enables you to change the color, font family, font weight, font style, and size for the legend title.

For more information about attribute options, see the Commonly Used Attribute Options section of the SAS® 9.4 ODS Graphics: Procedures Guide, Sixth Edition.

The ATTRS options affect all of the output that is produced by that statement. This means that if you include the GROUP= option, all of the groups use the attributes that are specified in the ATTRS options. This behavior is great if you want all of the lines to use the same line pattern, but it can be a problem if you want to specify colors for each of your lines.

Beginning with SAS 9.4, the STYLEATTRS (notice the ATTRS ending) statement is part of the SPLOT (and SGPANEL) procedure to enable you to define attributes for grouped data.

For example, the following code uses the DATACONTRASTCOLORS= option to specify the colors for the marker symbols and the DATASYMBOLS= option to specify the symbols that are to be used.

ods graphics / attrpriority=none;
proc sgplot data=sashelp.class;
styleattrs datacontrastcolors=(pink blue)
datasymbols=(circlefilled squarefilled);
scatter x=age y=height / group=sex markerattrs=(size=10px);
xaxis valueattrs=(size=12pt) labelattrs=(size=14pt);
yaxis valueattrs=(size=12pt) labelattrs=(size=14pt);
keylegend / valueattrs=(size=12pt) titleattrs=(size=14pt);


You also might need to add the ATTRPRIORITY=NONE option in your ODS GRAPHICS statement to cycle the colors and symbols as expected. For more information about how the attributes are applied to the grouped values, see the How the Attributes Are Cycled section of the SAS® 9.4 ODS Graphics: Procedures Guide, Sixth Edition.

The attributes that are listed in the STYLEATTRS statement are associated with the group values in the order in which they appear in the data set. This behavior can cause the same value to be associated with a different color when you use the same code with another set of data.

To associate an attribute with a specific data value, you can define an attribute map. The attribute map is a data set, referenced in the DATTRMAP= option in the PROC SGPLOT statement, which includes variables that indicate to the SGPLOT procedure how to assign attributes to the group variable values.

Within the attribute map, the ID variable identifies the variables that are specific to a particular set of group values. The VALUE variable identifies the data value for the group variable that you want to associate with attributes. Note that if the variable for the GROUP= option has an associated format, the VALUE variable in the attribute map needs to contain the formatted value.

The other variables in the attribute map data set define attributes such as color, symbol, line thickness, and so on.

For example, the following code defines an attribute map to assign the color pink and the filled-circle  symbol to group value F and the color blue and the filled-square symbol to the group value M:

data myattrmap;
length markersymbol $12;
input value $ markercolor $ markersymbol $;
F pink circlefilled
M blue squarefilled
proc sgplot data=sashelp.class dattrmap=myattrmap;
scatter x=age y=height / group=sex markerattrs=(size=10px) attrid=scattersymbols;
xaxis valueattrs=(size=12pt) labelattrs=(size=14pt);
yaxis valueattrs=(size=12pt) labelattrs=(size=14pt);
keylegend / valueattrs=(size=12pt) titleattrs=(size=14pt);


Your attribute-map data set can contain multiple attribute maps, using a different value for the ID variable to distinguish each of the attribute maps. For more information about attribute maps, see the Using Attribute Maps to Control Visual Attributes section of the SAS® 9.4 ODS Graphics: Procedures Guide, Sixth Edition.

As you can see, there are many ways to assign attributes to plot elements. So, the next time you want to make a change to the visual appearance of your graph, remember that we have an ATTRS for that!

If you would like to see how to make attribute changes using a style template, read Dan Heath’s 2017 SAS Global Forum paper, Diving Deep into SAS® ODS Graphics Styles.

PROC SGPLOT: There’s an ATTRS for that was published on SAS Users.

8月 202016

ProblemSolversIf you are using the second maintenance release of SAS 9.3 (TS1M2) or later, you might have noticed that you have several map-related libraries that are defined for you.

  • The MAPS library contains the old map data sets that have been provided with SAS/GRAPH® software for many years.  The source for these data sets was mainly freely available data or purchased data. As a result, it became difficult or impossible to provide updates to this data.
  • The MAPSGFK library contains new map data sets that are licensed through GfK Geomarketing and that are provided as part of SAS/GRAPH software.
  • The MAPSSAS library points to the same location as the MAPS library.

Determining which library to use

You should use the MAPSGFK data sets to produce your maps.  There are several advantages to using the MAPSGFK data sets:

  • The older MAPS library data sets contain outdated data, and this library will not be updated.
  • The MAPSGFK data is updated more frequently.
  • The MAPSGFK data sets standardize the variables in the data set. For example, the X and Y variables always contain the projected values, and LONG and LAT always contain the unprojected values.

Each of the data sets also contains the ID variable, as shown in the following example, to enable you to create a map without knowing about the boundaries that are contained in the data set.

proc gmap data=mapsgfk.ireland_attr map=mapsgfk.ireland;
id id;
choro idname;

As mentioned above, the MAPSGFK library data sets contain both projected and unprojected values, which is helpful when you use annotation with maps or when you create a subset of a map.

  • The MAPSGFK.PROJPARM data set contains the parameters that were used when the projected data was created for each of the data sets.  You can use these parameters with the GPROJECT procedure when you project an annotate data set. For more information about projecting an annotate data set using MAPSGFK.PROJPARM, see the sample code that appears in the section Code to Project Annotate Data with a GfK Map Data Set ("Chapter 37: GMAP Procedure") in SAS/GRAPH® 9.4: Reference, Fourth Edition.
  • Many of the MAPSGFK data sets include a lower level of hierarchy  for boundaries than was available previously in the map data sets, as shown in this example:
proc gmap data=mapsgfk.africa1 map=mapsgfk.africa1;
   id id;
   choro id / nolegend;

This code sample generates the following output:


You can use the GREMOVE procedure to remove internal boundaries that you don’t want as part of your map.

  • In earlier releases, the names of the map data sets in the MAPS library were limited to eight characters. The MAPGSFK data sets do not have that restriction, so you can use longer names. The longer data-set names enable you to determine the map data-set content more easily.

Determining which MAPSGFK data sets to use

To help you determine which data set to use to create your map, you can use dictionary tables in the SQL procedure to generate a list of the data sets that are contained in the MAPSGFK library, along with their associated labels.

This example illustrates how you can view the dictionary table for selected data sets (in this case, MEMNAME and MEMLABEL):

proc sql;
   select memname, memlabel from dictionary.tables
          where libname='MAPSGFK';

The following output is a partial display of the results:


The data sets that end in _ATTR are the attribute data sets for the map data set of the same base name. You can use the attribute data sets to obtain names and other information that is associated with variables in the map data set.

You can determine more information about the contents of the data sets using the DICTIONARY.MEMBERS dictionary table in PROC SQL.

proc sql;
   select name, type, length, label from dictionary.columns
          where libname='MAPSGFK' and memname='NAMERICA';

The following output shows the results:


In some cases, changing your existing PROC GMAP code to use the MAPSGFK data sets rather than the MAPS data sets might be as simple as changing the data set name in the MAP= option of the PROC GMAP statement. In other cases, this changing data sets can include changing the variables that are listed in the ID statement of PROC GMAP, including using a GREMOVE procedure step to remove a lower-level map boundary to or remove or modify a GPROJECT procedure step. You can find tips about modifying your existing PROC GMAP code to work with MAPSGFK data sets in the section Using GfK Map Data Sets with Existing Code ("Chapter 37: GMAP Procedure") in  SAS/GRAPH® 9.4: Reference, Fourth Edition.

You can find more information about the new map data sets and modifying your existing map programs to use the MAPSGFK data sets in the SAS Global Forum paper The New SAS® Map Data Sets (by Darrell Massengill) and in the SAS/GRAPH Concepts section of SAS/GRAPH® 9.4: Reference, Fourth Edition.

tags: Problem Solvers, SAS Programmers

MAPS, MAPSGFK and MAPSSAS, Oh my! was published on SAS Users.

10月 152015

ProblemSolversA coworker was recently in need of some simple graphics to include in a slide show to accompany her SAS Global Forum paper. After listening to what she wanted, I decided that I could use PROC SGPLOT to create those images for her.

The first image was a set of stacked blocks displaying the letters A, B, and C. Since blocks are drawn with only four coordinates, we can draw those using the POLYGON statement. We can use the MARKERCHAR option in the SCATTER statement to draw letters within each block.

The POLYGON statement was added to PROC SGPLOT in the first maintenance release of SAS 9.4 (TS1M1) and enables you to define the X and Y coordinates to draw a polygon. The ID required argument in the POLYGON statement identifies each set of X, Y coordinates for a particular polygon.

In a DATA step, we defined the coordinates for each of the blocks, the center of the block, and the letter to use for the marker character:

data blocks;
  input x y letter $ xcen ycen;
10 10 B 15 15
10 20 B 15 15
20 20 B 15 15
20 10 B 15 15
16 20.5 A 21 25.5
26 20.5 A 21 25.5
26 30.5 A 21 25.5
16 30.5 A 21 25.5
22 10 C 27 15
32 10 C 27 15
32 20 C 27 15
22 20 C 27 15

In PROC SGPLOT, we defined the POLYGON statement before the SCATTER statement so that the letters are drawn on top of the filled blocks.

proc sgplot data=blocks noautolegend noborder;
  polygon x=x y=y id=letter / outline lineattrs=(thickness=6px )
            fill  dataskin=matte FILLATTRS=(color=cxEDE3BB) group=letter;
  scatter x=xcen y=ycen / markerchar=letter markercharattrs=(size=80)
  yaxis display=none;
  xaxis display=none;

PROC_SGPLOT1You can build on this code to add tops and sides to create a three-dimensional look for your blocks.

An image of an old fashioned chalkboard with writing on it was also needed. Similar to the blocks, the chalkboard can be drawn using the POLYGON statement with coordinates for the board and a frame. We can even define coordinates to draw a piece of chalk and an eraser.

data board;
  input x y part $;
9.5 9.5 frame
9.5 40.5 frame
50.5 40.5 frame
50.5 9.5 frame
10 10 board
10 40 board
50 40 board
50 10 board
15 10.2 chalk
15 10.75 chalk
18 10.75 chalk
18 10.2 chalk
30 10.2 eraser
30 11.5 eraser
35 11.5 eraser
35 10.2 eraser

To add the writing on the chalkboard, we can define an SG annotation data set and reference it in the PROC SGPLOT statement using the SGANNO option.

In a DATA step, specify the TEXT annotate function and use the X1 and Y1 annotate variables to define the location of the text. The DRAWSPACE variable specifies that the X1 and Y1 variables are in relation to the percentage of the wall space, placing the text in the center of the chalkboard. Other variables can be added to modify the text attributes.

data sganno;
  x1=50; y1=50;
  label='1 + 2 = 3';
  textfont='Albany AMT';

To define the colors for each piece of the chalkboard, we can define an attribute map and reference it in the PROC SGPLOT statement using the DATTRMAP option and in the POLYGON statement using the ATTRID option.
In a DATA step, define the ID required variable to contain the name of the attribute map. The VALUE required variable contains the value of the item to be changed, which in this case is the polygon ID value. The FILLCOLOR variable contains the name of the color to be used for each polygon.

data attrmap;
   input value $ fillcolor $;
frame cxBFA40B
board delg
chalk white
eraser black

Adding the annotation and attribute map to the PROC SGPLOT step, we create the chalkboard.

proc sgplot data=board sganno=sganno dattrmap=attrmap
      noautolegend noborder nosubpixel;
  polygon x=x y=y id=id / group=id fill outline dataskin=matte
  xaxis display=none;
  yaxis display=none;

PROC_SGPLOT2Finally, we created a school house. Using the techniques we have used so far, we can define all the parts of a school house to draw the building, door, windows, and add the word “school.”

data school;
  input x y part $;
  x1=44.25; y1=20;
40 10 building
40 60 building
45 75 building
50 60 building
50 10 building
44 10 door
44 35 door
46 35 door
46 10 door
45 75 roof
40 60 roof
39 59 roof
45 78 roof
51 59 roof
50 60 roof
41 30 windowl
41 50 windowl
43 50 windowl
43 30 windowl
47 30 windowr
47 50 windowr
49 50 windowr
49 30 windowr
data attrmap;
  input value $ fillcolor $;
building cxF52707
door cxc4a854
roof black
windowl white
windowr white
data panes;
  linecolor='black'; linethickness=5;
  x1=41; y1=40; x2=43; y2=40; output;
  x1=42; y1=50; x2=42; y2=30; output;
  x1=47; y1=40; x2=49; y2=40; output;
  x1=48; y1=50; x2=48; y2=30; output;
  function='text'; width=25;
  x1=45; y1=38; label='SCHOOL';
  textcolor='black'; textsize=20; textweight='bold';
proc sgplot data=school dattrmap=attrmap sganno=panes noborder noautolegend;
  polygon x=x y=y id=part / outline lineattrs=(thickness=4px color=black )
     fill  dataskin=matte group=part attrid=school;
  scatter x=x1 y=y1 / markerattrs=(color=black symbol=circlefilled);
  xaxis display=none;
  yaxis display=none;


Think of all the great images you could create with PROC SGPLOT and a little imagination!

tags: Problem Solvers, PROC SGPLOT, SAS Programmers

PROC SGPLOT: It isn’t just for plots anymore was published on SAS Users.