IDL Tutorial for Novice

This is a brief introduction to IDL for someone who wants to look into existing codes and/or start writing some little programs of their own. Looking through the first few chpters in "IDL Basics" is highly recommended to get used to IDL.

IDL Overview

IDL (Interactive Data Language) is a software that lets a user to analyse and visualize the data in an environment where the user can "feel" like he/she were actually inside the program codes. The conventional programming languages like C or Fortran tends to produce something that feels like "black boxes", which one hardly ever gets to peek into to understand how it actually works. Even for the programmer they are hard to get into for improving or debugging. But IDL creates and an unique environment where the user can stop the program at almost any level of subroutine hirachy, check the values of the varibles at the current level of the subroutine, display the varibales graphically, or define new varibles and try diferent approach, and so on, all on the fly at relative ease. In some sense, IDL is a sort of perpetual "debugging mode".

Because of this, programs coded in IDL tends to be slower compared to the equivalent programs coded in C or Fortran. But this issue of speed matters only for cases involving huge amount of data and/or great many number of iterations. For most other cases, IDL is fast enough. (When a IDL code take 2 seconds and a equivalent C code takes .0001, the difference is no big deal. But if it has to be iterated million times, then the speed does matter.) Another possible disadvantage of IDL is that IDL codes are too easy to modify and tends to be changing all the time especially when many programmers are involved. (I guess too much of a good thing is always a problem.)

Syntex

Case Insensitive
IDL itself is case insensitive. But since unix, the operating system, is case sensitive, when specifing a input/output file, the filename must be case-matched inside the IDL string variable.
Comments
Comments in IDL are denoted by semi-colons (;). The rest of the line after a semi-colon is ignored as comments. (Semi-colons inside a quotation mark are not treated as comment marks but as a simple character, like >>>> line = "None of these are comments; nor these.")
Comma !!!!!
"," is the ultimate separator in IDL syntex. Once separated by a comma having blank spaces does not matter. The only exception of comma as the syntex separator is for system commands that starts with a dot (like .run)
Quotation mark : Either single or double
"Test" and 'Test' are equivalent. So use either one which is more convenient likeline = "It's raining!" & print,line will print to the screen : It's raining!
Arrays : definition and indexing
Array definition is denoted by square brackets like >>>> a = [-1,3,2,5,8,0]

To index a part of the array, use parenthesis like >>>> b = a(0)

Contiguous ranges of indices can be denoted by colons like >>>> b = a(0:4) which is equivalent to >>>> b = a([0,1,2,3,4])

Wild card (*) denotes every index >>>> b = a(*) or to the end >>>> b = a(2:*)

(The indexing of arrays is now also possible with square brackets instead of parenthesis. The square bracket can be useful in emphasizing arrays from functions as in sin[0], not to be confused with trignometric sine function, sin(0). All of the above indexing rules apply to multi-dimensional array like >>>> d = c[[0,2,4], 5:*] if c were 2-dimensional array.)

Special Commands (.**** : .run .step .skip .continue)
There are a few special commands that begin with a dot and does not take a comma as syntex separators. Look below.

Useful IDL Commands

help (as in >>>> help,/structure,!d)
This shows the status of variables. Structure keyword is useful for structured variables.
print (as in >>>> print,'Area of a circle of radius 4.5 =',!pi*4.5^2)
This print to the screen values of variables and/or expressions.
= (as in >>>> greeting='Hello, dear' OR a=[2,5,1] OR a(0)=-2)
Simple assignment creates a new variable or overwrites the existing one.
.run (as in >>>> .run tracker OR .run ~rknop/idlpro/tracker.pro)
This compiles the program text file. Usually this is not needed since IDL compiles the code it is told to execute for the first time. Once compiled, IDL reuses the compiled module whenever the subroutine is called again. So, in the following situations you must to do this step manually :
  • The code is modified after it is complied already and you want to use the new modified version.
  • There are several versions of the same subroutine and you want to use one that does not have the first priority. (Path needed to be specified)
  • The subroutine is not in a directory of $IDL_PATH, like when you try to use someone else's personal code. (Path needed to be specified)
dlib (as in >>>> dlib,'tracker')
This locates the source code of the module and shows the full path name and displays the documentation section of the code, if the code has the doumentation section. (IDL only finds the code of highest priority among the $IDL_PATH so if you did ".run ~rknop/idlpro/tracker" then dlib,'tracker' will still show documentation of default tracker.pro (probably $DEEPHOME/idlpro/tracker.pro) while the actual compiled code working for you is ~rknop/idlpro/tracker.pro)
stop
If put inside the code, the execution is halted at that line. Then you can poke around inside and check the variable status. The more elegant way of doing this is using "breakpoint" command explained in the IDL reference manual.
.step
This let's you to execute and advance by one line of the code when it is suspended either by "stop" or by using the breakpoint routine (or by Control-C).
.skip
This is similar to .step but skips the excecution of the next line.
.continue
This let the execution continue on when suspened.
retall
This returns all the way up to the main level from whatever the subroutine the execution has been suspended at, andoning all unfinished parts. This is recommened when you want to "start over".
return (for procedures) OR return,value (for functions)
This returns back to the parent level from the suspension. Since most call to a subroutine expects certain result done, returning manually usually causes some kind of error in the parent level.

IDL Basics

Since all programming tasks boil down to variable manupilations of some kind, understanding how the variable is handled in IDL is crucial. Once a few simple rules of IDL variables are understood, understanding IDL codes is not very difficult.

Variable Types

IDL does not require varibales to be pre-declared. The statements below create or overwrite variables. a = 100 ;a becomes 2-byte integer 100 b = fltarr(100,200) ;b is 100x200 array of 4-byte floating points set to 0 c = fltarr(100,200) + a ;c is like b but set to value of a(=100) c = 'hello' ;c is now a string : hello c = strarr(3,4) ;c is 3x4 string array set to empty string c(0,0) = 'William' & c(1,0)="Jefferson" & c(2,0)='Clinton' ;& is for multiple ;statements on one line c(1,*) = ["John", 'Fitzerald', 'Kennedy'] c(2,0:2) = ["It's ", "the end ", "of names!"] b = [['William','Jefferson','Clinton'],['John','Fitzeral','Kennedy'], $ ;$=contiuation mark ["It's ",'the end ', 'of names!'] ] ;b is the same as c a = strupcase(c) ;a is the same as c but all in uppercase letters The indexing of arrays in IDL starts, as in C, with 0, not 1. But for multi-dimensional array it follows "x,y" conventions and the order goes : a(0,0) a(1,0) a(2,0) a(1,0) ..... a(2,1) a(2,2). The left index changes rapidly in IDL. (It is the opposite of C in this aspect.)

As the example above shows, string arrays does not need to be strings of the same length. Other than that, an array of mixed type or of mixed dimension is not allowed. However IDL supports "structure" variables where each element of the array is of certain combination of mixed type scalors and arrays.

a ={student_info, name:'', dob:intarr(3), address:strarr(3), sex:'', $ telephone:'',height:0.0, weight:0.0, testscores:fltarr(3,5)} ;student_info structure is definded on A b ={student_info} ;b becomes a copy of already defined student_info structure c = replicate(b,50) ;c is array of student_info structure for 50 students c(0).name = 'John Jackson' ;The first entry is for John Jackson c(0).dob = [28, 7, 1983] ;His Date of Birth date is June 28, 1983 !!!! c(0).testscore(2,4) = 96.5 ;John Jackson's last testscore is 96.5 c(0).dob(1) = 6 ;Correct the mistake above d = replicate({student_info},50,3) ;There are 3 class rooms 50 students each d(*,2) = c ;John Jackson's class is room 3

Subroutines : Procedure, Function, Parameters, Keywords

IDL codes are text files with names ****.pro. There are two types of subroutines : procedure and function. Their difference is very minimal and most tasks can be programed in either way. Let's take a look at a simple example. ----------addtwo_p.pro-------------------- pro addtwo_p,a,b,sum,squared=squared,silent if n_params() lt 2 then begin sum = -9999999 return endif if keyword_set(squared) then sum = sqrt(a^2+b^2) else sum = a+b if not keyword_set(silent) then print, 'Sum =',sum return end ------------------------------------------- ---------addtwo_f.pro---------------------- function addtwo_f,aa,bb,squared=sq,silent=silent if n_params() lt 2 then return,-9999999 if keyword_set(sq) then sum = sqrt(aa^2+bb^2) else sum = aa+bb if not keyword_set(silent) then print, 'Sum =',sum return,sum end -------------------------------------------- addtwo_p.pro is a procedure which can take upto 4 "parameter" and 1 "keyword" input/output variables. addtwo_f.pro is a funtion that takes upto 2 parameters and 2 keywords. But they are doing the same thing. The syntex will be : a = 3 & d = -4 addtwo_p,a,d,sum,/squ ;"/squ" means "squ=1" which in turn is understood as ;"squared=1". So c becomes 5.0 and "Sum = 5.000000" ;is printed on the screen. sum=addtwo_f(a,d,/squ) ;The same using function addtwo_p,30,d*10,/s ;Message "Sum = 50.00000" is on the screen but the ;sum retains 5.0 since new value 50.0 is not returned ;since addtwo_p is called with only 2 parameter. junk=addtwo_f(30,d*10,/sq) ;Here "/s" does not work because "silent=" also ;starts with "s" addtwo_p,300,-400.0,sum,1 ;now sum becomes -100 without the message. sum = addtwo_f(300,-400.0,silent=1) addtwo_p,1,2,sum,1,/s ;sum becomes sqrt(5) without a message sum=addtwo_f(1,2,si=1,/sq) ;For keywords, order does not matter!

Local vs. Global, Variable vs. Expression

In the above examples, all the variables appearing inside the addtwo_*.pro are local variables, meaning their existance and values are limited to inside of that particular routine. That means even if addtwo_p.pro and addtwo_f.pro is put into a single file, SUM in addtwo_p.pro and SUM in addtwo_f.pro has nothing to do with each other. This is the standard practice of most programming languages. So if one wants to check the value of the first input parameter, one has to type : help, a ; if the action is stopped in addtwo_p.pro ; OR help, aa ; if the action is stopped in addtwo_f.pro So the parameters and keywords are bridges to pass local variables from one subroutine to another. In this process of communicating between routines, the distinction between "variable" and "expression" is worth noticing. "Variable" is name of the variable with no indexing or operation. The rest is expression. When the variable apears as a parameter or a keyword in a call to any subroutine, the actual variable ("pointer" in C language) is passed to the subroutine so when the subroutine changes the value of that variable, the variable is really changed! But when expression is the parameter to the call, original variable is nerver passed to the subroutine, just a new variable with the coped value(s) of the expression at the parameter. Example : ------square.pro----- pro square,b b = b^2 print,b end --------------------- a = [2,3] square, a(*) ;although A(*) is the same to us humans as A, not to IDL ;A(*) is an expression while A is a variable ;The subroutine prints 4 9 on the screen but ;A is still [2,3], not [4,9] square, a(0) ;again 4 is on the screen but A(0) is still 2 square, a ;Now the variable A is used so A becomes [4,9]

Sometimes, One want to have gloval variables which can be recognized from any level of subroutine, like current graphic setting or constants like \pi or e. IDL has two kinds of gloval variables : system variables and common blocks. System variables are marked by ! in front. Example of this is !d,

help, !d, /structure Common block is like a "membership" system. Once a common block is declared, any program that wants to recognize the set can do so. Example : -----somewhere out there...------- common HOU_staff, aaa,bbb,ccc,ddd common HOU_student, names, times, scores --------------------------------- ------jjjj.pro--------------- pro jjjj,..... common hou_staff times = ddd ;TIMES is local and DDD is global ....... ----------------------------- ------mmmm.pro--------------- function mmmm,..... common hou_staff common hou_student times = ddd ;TIMES is global as well ....... -----------------------------