O Christmas tree,

O Christmas tree,

Last year a fractal made thee!

O Christmas tree,

O Christmas tree,

A heat map can display thee!

O tree of green, adorned with lights!

A trunk of brown, the rest is white.

O Christmas tree,

O Christmas tree,

A heat map can display thee!

Last week I showed how to use a heat map to visualize values in a matrix. To simplify the discussion, I allowed the ODS graphics in SAS to automatically choose colors based on the current ODS style. However, it is often useful to specify colors in order to improve the interpretability of a heat map. For example, in a recent article about how to specify colors in a mosaic plot, I used blue colors to represent negative values, white for nearly zero values, and red for positive values.

In the SAS Graph Template Language (GTL), you can use the DISCRETEATTRMAP statement and the DISCRETEATTRVAR statement to associate a color with each value in a matrix. Suppose that you want have a matrix with a small set of values, and you want to visualize the values by using the following colors:

- A missing value (.) is represented in the heat map by the color white
- The value 0 is represented by green
- The value 1 is represented by red
- The value 2 is represented by blue
- The value 3 is represented by yellow
- The value 4 is represented by brown

To illustrate assigning colors to values, I will create a "Christmas tree matrix." (You can think of each cell of the matrix as a "pixel" in the heat map.) The following program uses two helper functions (ROW and COL), which are explained in an article about how to fill specific cells of a matrix. The matrix is defined to have 100 rows and 101 columns. The trunk of the tree is 10% of its height. Within the "leafy" portion of the tree, I'll use the SAS/IML SAMPLE function to randomly place lights of three different colors.

proc iml; /* define helper functions ROW and COL */ start row(x); /* return matrix m such that m[i,j] = i */ return( repeat( T(1:nrow(x)), 1, ncol(x) )); finish; start col(x); /* return matrix m such that m[i,j] = j */ return( repeat(1:ncol(x), nrow(x)) ); finish; /* parameters for the tree dimensions */ h = 100; w = h+1; b = int(h/10); M = j(w, h, .); /* initialize h x w matrix to missing */ x = col(M); /* column numbers */ y = w + 1 - row(M); /* reverse Y axis */ /* define the leafy portion of the tree */ TreeIdx = loc(y>b & y<=2*x & y<=-2*x+2*h); /* a triangle */ M[TreeIdx] = 0; /* place lights randomly within tree */ N = int(0.12*ncol(TreeIdx)); /* use 12% of tree area */ call randseed(1225); do i = 1 to 3; /* 3 colors */ idx = sample(TreeIdx, N, "WOR"); /* sample without replacement */ M[idx] = i; end; /* define the trunk */ width = int(b/2); TrunkIdx = loc( y<= b & abs(x-nrow(M)/2)<width ); M[TrunkIdx] = 4; /* write matrix in "long form" to SAS data set */ Row = row(M); /* row index */ Col = col(M); /* col index */ create Tree var {"Row" "Col" "M"}; append; close Tree; quit;

As in last week's article, I'll use a GTL template to define the heat map. However, this time I'll associate specific colors to data values. The following template defines a green tree with a brown trunk that is decorated with red, blue, and yellow lights:

proc template; define statgraph HeatmapTree; dynamic _X _Y _Z; begingraph; discreteattrmap name="christmastree"; value '.' / fillattrs=(color=WHITE); /* background color */ value '0' / fillattrs=(color=GREEN); /* tree color */ value '1' / fillattrs=(color=RED); /* ornament color 1 */ value '2' / fillattrs=(color=BLUE); /* ornament color 2 */ value '3' / fillattrs=(color=YELLOW); /* ornament color 3 */ value '4' / fillattrs=(color=BROWN); /* tree trunk color */ enddiscreteattrmap; discreteattrvar attrvar=Alias var=_Z attrmap="christmastree"; layout overlay / xaxisopts=(type=discrete display=none) yaxisopts=(type=discrete display=none reverse=true); heatmapparm x=_X y=_Y colorgroup=Alias / xbinaxis=false ybinaxis=false primary=true; endlayout; endgraph; end; run; ods graphics / width=500 height=800; proc sgrender data=Tree template=HeatmapTree; dynamic _X="Col" _Y="Row" _Z="M"; run;

The resulting heat map is shown at the beginning of this article.

You might not have many occasion where you need to use SAS to draw Christmas trees, but the same technique enables you to assign colors to any heat map that contains a small number of values. For matrices with a larger number of values, use the RANGEATTRMAP and RANGEATTRVAR statements to specify colors for a gradient color ramp, as shown in Chris Hemedinger's blog post.

This is my last post until after the Winter Break. I am taking a 10-day hiatus from blogging to recharge my mental batteries. If you've enjoyed reading any of my 100+ blog posts in 2013, please subscribe through an RSS feed and tell your friends. I look forward to learning and sharing more SAS programming techniques in 2014.