SAS supports the ColorBrewer system of color palettes from the ColorBrewer website (Brewer and Harrower, 2002). The ColorBrewer color ramps are available in SAS by using the PALETTE function in SAS IML software. The PALETTE function supports all ColorBrewer palettes, but some palettes are not interpretable by people with color deficiencies (usually called "colorblind" people). Fortunately, the ColorBrewer website includes information about which palettes are colorblind-safe and which are not. You should strive to use only the colorblind-safe palettes when you create graphs that you intend to show to others.
Which palettes are colorblind-safe?
As discussed previously, the most common color vision deficiencies are the inability to distinguish red and green. Therefore, as a general rule, you should avoid using palettes that contain both red and green. The ColorBrewer palettes are split into three different types of palettes:
- A sequential palette enables you to distinguish low and high values for an interval measurement.
- A diverging palette enables you to compare high and low values to an average.
- A qualitative palette enables you to visualize different values of a categorical variable, such as sex, political affiliation, or an arm of a clinical study.
For each type, the following list reveals which palettes are colorblind-safe:
- Sequential palettes: All sequential palettes from ColorBrewer are colorblind-safe. This includes the one-hue palettes (for example, "Blues"), the two-hue palettes (for example, "OrRed," which is an orange-red palette), and three-hue palettes (such as "YlOrRd," which is a yellow-orange-red palette).
- Diverging palettes: Six diverging palettes are colorblind-safe, including the popular "BrBG," which is a brown-blue-green palette. However, three diverging palettes are not colorblind-safe. Avoid using "RdGy" (red-gray), "RdYlGn" (red-yellow-green), and "Spectral" (red-yellow-blue, which passes through green).
- Qualitative palettes: Very few of the qualitative palettes are colorblind-safe. For three categories, you can use "Dark2", "Paired", and "Set2". For four categories, only "Paired" is a colorblind-safe palette. Many qualitative palettes use green as one of the colors.
A SAS IML module for colorblind-safe palettes
After discovering which palettes are colorblind-safe, it is easy to write a wrapper for the PALETTE function in SAS IML that adds a bit of colorblind-safe logic. The following function returns the requested palette if it is colorblind-safe. Otherwise, it returns a vector of missing values and writes an error to the log by using the PrintToLog subroutine.
/* In SAS 9.4, the macro defines a function that emulates the PrintToLog call. See https://blogs.sas.com/content/iml/2023/01/25/printtolog-iml.html */ %macro DefinePrintToLog; %if %sysevalf(&sysver = 9.4) %then %do; start PrintToLog(msg,errCode=-1); if errCode=0 then prefix = "NOTE: "; else if errCode=1 then prefix = "WARNING: "; else if errCode=2 then prefix = "ERROR: "; else prefix = ""; stmt = '%put ' + prefix + msg + ';'; call execute(stmt); finish; %end; %mend; /* Support colorblind-safe palettes as reported by https://colorbrewer2.org/ If the requested palette is not colorblind-safe, return missing values and log a warning. */ proc iml; %DefinePrintToLog start ColorblindSafe(name, numColors ); /* Create a denylist of palettes that are NOT colorblind-safe. The first column is the name of a palette. The second column is 'N' if not safe for any number of colors. Otherwise, '3' or '4' indicates the max number of colors for which the palette is safe. */ NotCBS = { RDGY N, RDYLGN N, SPECTRAL N, ACCENT N, DARK2 3, /* only numColors <= 3 */ PAIRED 4, /* only numColors <= 4 */ PASTEL1 N, PASTEL2 N, SET1 N, SET2 3, /* only numColors <= 3 */ SET3 N }; /* if the requested palette is not colorblind-safe, return a vector of missing values */ ErrPalette = j(1, numColors, .); idx = loc(NotCBS[,1] = upcase(name)); if ncol(idx)=0 then /* name is not on the denylist. Use it! */ return palette(name, numColors); isCBS = NotCBS[idx,2]; /* get value in second column */ if isCBS='N' then do; /* 'N' = not colorblind-safe */ msg = cat("The palette '", strip(name), "' is not colorblind-safe."); call PrintToLog(msg, 1); /* WARNING */ return ErrPalette; end; else do; n = num(isCBS); /* '4' = colorblind-safe only for <= 4 colors */ if numColors <= n then return palette(name, numColors); else do; msg = cat("The palette '", strip(name), "' is colorblind-safe only for ", strip(isCBS) + " or fewer colors."); call PrintToLog(msg, 1); /* WARNING */ return ErrPalette; end; end; finish; /* test the ColorblindSafe function on a few examples */ RedBlue = ColorblindSafe("RdBu", 7); Spectral = ColorblindSafe("Spectral", 5); Pair4 = ColorblindSafe("Paired", 4); Pair5 = ColorblindSafe("Paired", 5); print RedBlue, Spectral, Pair4, Pair5; |
The output shows that the 'Spectral' palette is not colorblind-safe. The 'Paired' palette is safe for four or fewer colors. If the caller requests a colorblind-safe palette, it is returned. Otherwise, the function returns a vector of missing values. The program also writes the following messages to the log:
The messages inform the user that some of the requested palettes are not colorblind-safe.
Summary
SAS software supports the ColorBrewer family of color palettes. Not all the palettes are colorblind-safe. Among the palettes, all sequential palettes are safe, and most of the diverging palettes are safe. However, most of the qualitative palettes are not safe. The SAS IML function in this article creates a denylist of the ColorBrewer palettes that are not colorblind-safe. The function returns a colorblind-safe palette when one is requested. However, the function returns a vector of missing values if the palette is on the denylist.