Fanning Software Consulting

Changing Colors in cgWindow

Facebook Twitter RSS Google+

QUESTION: I followed your instructions for creating a color-filled contour plot with out-of-bounds colors, except that I put the plot in the resizeable graphics window, cgWindow.

All was well until I wanted to change the colors in the contour plot. I found I could easily change the colors for the contour plot itself with cgLoadCT, simply by setting the Window keyword. But, I could not find a way to change the out-of-bounds colors. Here is my code. Can you help?

   data = cgDemoData(2)
   nlevels = 12
   oob_low = 0
   oob_high = nlevels
   levels = Indgen(nlevels)*100 + 100
   range = [Min(levels), Max(levels)]
   TVLCT, cgColor('Hot Pink', /Triple), oob_low
   cgLoadCT, 33, NColors=nlevels-1, Bottom=1
   TVLCT, cgColor('Tan', /Triple), oob_high
   cgContour, data, Levels=[Min(data),levels], /Fill, C_Colors=Indgen(nlevels+1), $
     /Outline, Position=[0.1, 0.1, 0.9, 0.8], /Window
   cgColorbar, NColors=nlevels-1, Bottom=1, OOB_High=Fix(oob_high), $
       OOB_Low=Fix(oob_Low), /Discrete, /Fit, Range=range  , /AddCmd    
A filled contour plot with out-of-bounds colors
A filled contour plot with out-of-bounds colors.

ANSWER: Yes, this can be a little confusing. The way cgWindow works is that when the window is first created it loads whatever colors are in the color table into its internal color vectors. Then, whenever it needs to draw the graphics commands that have been loaded into it, it first loads the IDL color table with these internal color vectors. In this way, the window can protect its own colors.

As you have discovered, one way to update the color vectors that are stored internally is to use the cgLoadCT command with the Window keyword, like this.

   cgLoadCT, 5, NColors=nlevels-1, Bottom=1, /Window

Those colors are immediately changed in the cgWindow graphics plot.

Contour colors changed.
The contour colors have changed, but not the out-of-bounds colors.

Unfortunately, the Window keyword may give you a false sense of what is happening. Normally, when you use a Window or AddCmd keyword on a Coyote Graphics command, that command is added to the command list in the cgWindow. But, that is not what is actually happening here.

Instead, what is happening is that colors are being loaded into the IDL hardware color table table, and then the color vectors of that color table are being sent directly to the "command object" that is at the heart of cgWindow. The cgLoadCT command itself is not being loaded in cgWindow. (This kind of communication with IDL objects has been a feature of Coyote Library color routines from the very beginning, and is one of the features that have always separated them from normal IDL color handling routines.)

Knowing this, you might be tempted to look for the Coyote Graphics equivalent of TVLCT. It would be possible to write such a thing, no doubt, but that is generally not what is done with cgWindow.

Instead, what is done is to load the hardware color table in IDL normally, then copy it into a 3-by-256 byte array, and pass this directly to the cgWindow with the cgControl command and the Palette keyword. The code looks something like this.

   TVLCT, cgColor('Red', /Triple), oob_low
   cgLoadCT, 4, NColors=nlevels-1, Bottom=1, /Brewer, /Reverse
   TVLCT, cgColor('Yellow', /Triple), oob_high
   TVLCT, rgb, /Get
   cgControl, Palette=rgb

The output now looks like the figure below, with both the contour colors and the out-of-bounds colors changed.

All contour colors have changed.
All contour colors have changed when the palette is passed to cgWindow.

If you prefer not to load the hardware color table, you can get the color palette out of the cgWindow, manipulate it, and put it back. The commands to do so would look like this. Again, the window will update itself when you are finished and you will see the new colors on the display.

   void = cgQuery(/Current, ObjectRef=thisWindow)
   thisWindow -> GetProperty, Palette=theseColors
   theseColors[oob_low,*] = cgColor('Purple', /Triple) 
   theseColors[oob_high,*] = cgColor('Cyan', /Triple) 
   thisWindow -> SetProperty, Palette=theseColors, /Update

Version of IDL used to prepare this article: IDL 7.1.2.

Written: 20 April 2012