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 (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.)
- 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.
- 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.
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.
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
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!
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
.......
-----------------------------