BookmarkSubscribeRSS Feed
dagremu
Obsidian | Level 7

I'm creating a filled contour plot, using contourplotparm in GTL, and I want to precisely control the color for each filled-in area. SAS, however, takes my color choices only as an input in some algorithm to determine the colors it actually uses. Here's an example:

 

* GTL template for a filled contour plot, with 5 colors. The contour levels must
  be specified when calling SGRENDER.;
proc template;
define statgraph ContourPlotParm;
dynamic _levels _title;
begingraph;
	entrytitle _title;
	layout overlay;
		contourplotparm x=Height y=Weight z=Density /
			contourtype=fill
			levels=_levels
			colormodel=(red yellow green blue purple)
			name="Contour";
		continuouslegend "Contour";
	endlayout;
endgraph;
end;
run;

* render a contour plot with 6 contour levels, and thus with 5 filled-in areas
  between the levels;
ods graphics / width=3in;
proc sgrender data=sashelp.gridded template=ContourPlotParm;
	dynamic _levels='0 0.0003 0.0007 0.001 0.0014 0.0017' _title='Figure 1';
run;

* same as above, but different contour levels;
proc sgrender data=sashelp.gridded template=ContourPlotParm;
	dynamic _levels='0 0.0005 0.0007 0.001 0.0014 0.0017' _title='Figure 2';
run;

Here's the two resulting figures:

Contour plot examples.png

First, note that neither figure uses exactly the colors I wanted: there's no red, there's no yellow, and I'm guessing that the other colors aren't exactly what I specified. Second, note that the two figures have different colors from each other even though I did not change the colors that I specified; the only difference is the contour level values.

 

My question is, how do I get exactly the colors I want? I think another way of asking this is, given the contour levels and the colors that I want, is it possible to come up with a different set of colors such that, when I specify these colors in the colormodel option, SAS ends up actually using the colors I want?

 

The SAS documentation for contourplotparm offers the following hint, but I'm not sure what to make of it:

 

For a contour plot of type FILL, LINEFILL, or LABELEDLINEFILL, the color that is chosen for the first segment is the color for the N+1 inflection point and not the starting color in the color model.
 

Thanks for any help.

6 REPLIES 6
Rick_SAS
SAS Super FREQ

Try using the

LEVELS=(contour-value-list) or NLEVELS= option to make sure that the number of areas matches the number of colors in the color ramp. Here is an example that seems to work, but I had to add a fake color (WHITE) at the lower end of the color ramp to get it to work. Not sure why.

 

proc template;
define statgraph ContourPlotParm2;
dynamic _X _Y _Z _TITLE;
begingraph;
   entrytitle _TITLE;
   layout overlay;
      contourplotparm x=_X y=_Y z=_Z /
        contourtype=fill nlevels=8  
        colormodel=(white red orange yellow green blue magenta grey) name="Contour";
      continuouslegend "Contour" / title=_Z;
   endlayout;
endgraph;
end;
run;

data Have;
do y=-5 to 5 by 0.1;
   do x=-5 to 5 by 0.1;
      z = x*x/20 + y*y/10;
      output;
   end;
end;
run;
proc means data=Have;run;

proc sgrender data=Have template=ContourPlotParm2;
dynamic _TITLE="Contour Plot"
        _X="x" _Y="y" _Z="z";
run;
dagremu
Obsidian | Level 7

Thanks, @Rick_SAS. I think your example works because you used nlevels to create 8 evenly spaced levels. However, in your code, if you replace nlevels=8 with levels=(0 0.3 1 1.3 2 2.5 3 3.75) to create 8 irregularly spaced levels, then the resulting figure no longer uses the colors you chose. In my real use case, I do want to pick my own level values and they are not evenly spaced, so unfortunately your suggestion doesn't work for me. (For context, I'm plotting hazard ratios as a function of two predictor variables. I'm using the levels to bin the HRs into meaningful ranges and they are not evenly spaced.)

ballardw
Super User

I suspect part of the issue revolves around your "levels", 6 boundaryies=>7 groups to display, not aligning with colors, 5, forcing an added interpolation somewhere. Probably compounded by the last group, at least with the level choices you show has very few records compared to the last level.

I can get this to use the 5 colors PLUS one, this way. But since it requires a data step to force your increments onto the density value I suspect it isn't as nice as you hoped.

proc template;
define statgraph ContourPlotParm;
dynamic _levels _title;
begingraph;
	entrytitle _title;
	layout overlay;
		contourplotparm x=Height y=Weight z=Density /
			contourtype=fill
			levels=_levels
			colormodel=(white red yellow green blue purple)
			name="Contour";
		continuouslegend "Contour";
	endlayout;
endgraph;
end;
run;
data toplot;
   set sashelp.gridded;
   array _l(6) _temporary_( 0,0.0003,0.0007,0.001,0.0014,0.0017);
   array _z(6);
   do i= 1 to dim(_l);
      _z[i]= abs(_l[i] - density);
   end;
   tl= whichn(min(of _z(*)),of _z(*));
   density=_l[tl];
run;


proc sgrender data=toplot template=ContourPlotParm;
	dynamic _levels='0 0.0003 0.0007 0.001 0.0014 0.0017' 
         _title='Figure 1'
   ;
run;

This code

proc format;
value density
0              ='     0'
0     <- 0.0003='     0<- 0.0003'
0.0003<- 0.0007='0.0003<- 0.0007'
0.0007<- 0.001 ='0.0007<- 0.001'
0.001 <- 0.0014='0.001 <- 0.0014'
0.0014<- 0.0017='0.0014<- 0.0017'
0.0017<- high  ='0.0017+'
;
run;

ods listing;
proc freq data=sashelp.gridded;
   tables density;
   format density density.;
run;
ods listing close;

Shows the groups with your boundary values:

                       Density    Frequency     Percent     Frequency      Percent
              ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ
                   0                   138        3.83           138         3.83
                   0<- 0.0003         2858       79.39          2996        83.22
              0.0003<- 0.0007          284        7.89          3280        91.11
              0.0007<- 0.001           124        3.44          3404        94.56
              0.001 <- 0.0014          128        3.56          3532        98.11
              0.0014<- 0.0017           61        1.69          3593        99.81
              0.0017+                    7        0.19          3600       100.00

I am thinking of the old GMAPS Levels option where the interpolation was sometimes other than desired.

Anyway that lead me to trying the starting data set with the format.

proc sgrender data=sashelp.gridded template=ContourPlotParm;
	dynamic _levels='0 0.0003 0.0007 0.001 0.0014 0.0017' 
         _title='Figure 1'
   ;
   format density density.;
run;

Which works, as I think you intended IF there are (at least?) 6 colors in the colorlist as in my version above.

 

So you may have to create a format for each different level list. And if you go to 8 levels I would expect this to break again.

 

dagremu
Obsidian | Level 7

Thanks, @ballardw. I think your code *appears* to work at first glance, but that's because the level values (0 0.0003 0.0007 0.001 0.0014 0.0017) are close-to-but-not-quite evenly spaced. If you inspect the color that should be pure red (i.e., cxFF0000) in the figure, it's actually cxFC282E; the other colors are all slightly off too. If you change the levels to (0 0.0005 0.0007 0.001 0.0014 0.0017) so that they are less evenly spaced, then it becomes more obvious that your code has the same shortcomings as mine.

ballardw
Super User

@dagremu wrote:

Thanks, @ballardw. I think your code *appears* to work at first glance, but that's because the level values (0 0.0003 0.0007 0.001 0.0014 0.0017) are close-to-but-not-quite evenly spaced. If you inspect the color that should be pure red (i.e., cxFF0000) in the figure, it's actually cxFC282E; the other colors are all slightly off too. If you change the levels to (0 0.0005 0.0007 0.001 0.0014 0.0017) so that they are less evenly spaced, then it becomes more obvious that your code has the same shortcomings as mine.


When the requirement is "red" and the error is within monitor display size/ gamma/ brightness or other color correction settings affect I call that close enough. If the object is paper print and Pantone type settings that's past my non-paid grade.

I don't use contour plots so have never had to try to force appearance, especially with uneven range values.

 

dagremu
Obsidian | Level 7

I agree, @ballardw, and I didn't mean to seem nitpicky about tiny differences in color. In my real use case, the levels are unevenly spaced, and so the differences in color (between what I specify and what SAS uses) are more pronounced.

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!

Submit your idea!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 6 replies
  • 1045 views
  • 0 likes
  • 3 in conversation