Some IDL Tools

Here are some tools I wrote in the IDL language from Research Systems, Inc.

Color management


First off, this only matters if you run IDL on displays with different characteristics (e.g. 8-bit and 24-bit color); the rest of the class can go ahead to the next section.

IDL recently (around version 6.2) changed how it uses and stores defaults. Things that used to be manageable no longer are. The right way to do this was to have an .Xdefaults which set the appropriate values for whatever display you were currently using (of course ssh completely breaks Xdefaults because programs don't know what display they are running on). The new IDL scheme of storing things in files in .idl means customizing settings based on display is impossible.

As far as I can tell, the only thing to do is to call a routine from .idl_startup that is full of getenv()'s and spawn,'xdpyinfo...' that figures out where it is running and has hardcoded values for graphics device type and number of colors (or reads these from environment variables).

Given that such severe changes happened in a minor release (between 6.0 and 6.2), I imagine that it will change more soon.


IDL is great, but its facilities for managing colors are horrible. In particular there is no way to use colors which works on both 8 bit and 24 bit graphics without major kludging. I wrote to solve this problem.

The routine determines what the depth of the graphics device is and defines a system variable !col that you use to specify colors. For example, plot,x,y,color=! will generate a plot that is green or as close to green as possible in the current color table. All the colors defined in a normal rgb.txt are available, e.g. oplot,x,y,col=!col.darkseagreen3.

The new system variable also emulates a color table on 24-bit graphics devices. To emulate a 32-element color table using IDL's "rainbow" color table (number 39), run col_define,39,32. The color table elements are stored in a vector !col.ct. Plot using the color table like this: for i=0,31 do oplot,x[i,*],col=!col.ct[i]. The output will be identical whether you are using 8-bit or 24-bit graphics.

Here is an example.

It should now work for 16-bit graphics too. IDL with 16-bit graphics under XFree86 is very strange. Actually, it is even weirder than I thought: see comments in code. The handling of 16 bit graphics has changed IDL 5.5. I have not tested the code to see what it does now.

TVSCL for 24-bit graphics

In IDL on 24-bit graphics devices, tvscl makes grey plots. The routine mytvscl makes color plots on a 24-bit graphics display, with the option of picking a color table and number of colors by passing options. All options and behavior of tvscl are (should be) operational.



to see the difference.

More little stuff

This is mostly dumb little stuff. If it wasn't put into little routines I would just keep writing the same little bits over and over.

Find the phase of a complex number (oddly, atan(z) did this for complex z in IDL 5.4; it doesn't in 5.5)

function cmphase,z,degrees=degrees
   If n_params() eq 0 then begin
      print,"  usage:  cmphase(z[,/degrees]"
   phase = atan(imaginary(z),float(z))
   if keyword_set(degrees) then  $

Square root of complex numbers.

function ccsqrt,z
  ;; This function calculates the square root of the elements in the
  ;; array z.  Moreover, if z is approximately smooth, then the
  ;; returned array will be approximately smooth.  This is done by
  ;; arbitrarily choosing which root to return.  In any case, the
  ;; square of the value returned will equal z.
  r = abs(z)
  th = cmphase(z)
  nz = n_elements(z)
  ;; easy part is the sqare root of the amplitude
  sr = sqrt(r)
  ;; we want the phase to vary approx continuously and go above 2pi or
  ;; wherever it needs to go. 
  ;; find phase jumps.
  p = round((th[1:nz-1]-th[0:nz-2])/(2*!pi))
  pt = total(p,/cumulative)
  th = th-[0,pt]*2*!pi
  sz = sr*exp(complex(0,th/2))

Convert number to string padded with zeros to a certain length. Useful for generating file names in a loop, as in openw,unit,basename+zpstring(index,3).

function zpstring,num,lngth
;; Returns the integer num in a string  with the length padded with
;; zeros on the  left for a total length of lngth
  if not ( (size(num))(1) eq 2 and (size(lngth))(1) eq 2 ) then begin
    print,'  usage: astring=zpstring(num,lngth)'
    print,'   e.g.: print,zpstring(2,3)'
    print,'         002'
  ndig = floor(alog10(num))+1
  if ndig gt lngth then begin
    print,'zpstring: input ',strtrim(string(num),2), $
        ' is longer than length=',strtrim(string(lngth),2)
  if lngth gt ndig then begin
    s1 = string(bytarr(lngth-ndig)+48B)
  endif else begin
    s1 = ''
  s2 = strtrim(string(num),2)

What value of i gives array[i] closest to value?

function findindex,array,value
  if n_params() eq 0 then begin
    print,'  usage: z=findindex(array,value)'
  dummy = min(abs(array-value),indy) 

Make idl beep. Useful when running long analysis. IDL> LongRoutine & bleep,n=3 will make the terminal beep three times when the routine returns, letting me know that I should pay attention to it.

pro bleep,n=n
  ;; this beeps.  Duh.
  if n_elements(n) eq 0 then $
      n = 1
  for i=1,n do begin
  ;; it is less useful if terminal is set to visual bell

Put a list in random order. This implementation is actually slightly clever. Or maybe there are just a lot of dumb ways to implement this. (OK, I just read that this is the Fisher-Yates algorithm as implemented by Durstenfeld. But I swear I thought it up myself.)

pro randomize,a
  n = n_elements(a) 
  if n lt 1 then begin
    print,' usage: randomize,SomeArray'
    print,'   Elements of SomeArray are placed in random order'
  for i=n-1,1,-1 do begin
    ;; pick at random one of the first i elements
    indy = floor(randomu(seed)*(i+1))
    ;; move this element to the ith position
    tmp = a[i]
    a[i] = a[indy]
    a[indy] = tmp

Empty the keyboard buffer. Useful to run before you wait for keypress, because get_kbrd(1) will take a key press from the buffer, if there is one; it does not necessarily wait for a new key press.

pro empty_keyboard_buffer
   repeat begin
      ans = get_kbrd(0)
   endrep until ans eq ''

A Hint

I can never remember the arguments to routines, so I find it useful to have a routine called with no arguments print a usage message and return harmlessly. If a routine is more likely to be called from another routine, rather than from the command line, the check for improper arguments emits a message instead, stopping everything in its tracks to give you a chance to figure out what went wrong.

Last updated Dec 13 2007.