IDL Tutorial: Scripts, Procedures, and Functions
Of course you won't get very far with IDL if you have to type everything one line at a time. It would also help to store lists of commands that you find yourself repeating a lot. There are three kinds of command lists that you can use:
Scripts are really nothing more sophisticated than a list of IDL commands in a file.
Copy this file to a work space, say, into your public space (right click, save as).
Have a look at the script in a text editor (textpad works well here; I prefer emacs). If there is a command or a command option that you don't understand, try using the IDL online help to figure it out.
Next, in IDL, change the default working directory to the directory where you placed the script:
or whatever is appropriate. Notice that cd is a procedure to change the current working directory. It takes a single argument, a text string giving the name of the working directory. (By the way, cut and paste can save a lot of headaches in directory changes.)
Execute the script:
Hopefully, you experienced a little magic here.
Now, copy the script to a new file, say, example2.pro. Change to script to do something new. Replace sin with cos, plot y vs. z, whatever floats your boat. Then
Not too shabby, eh?
When Things Go Horribly Wrong
Before we delve deeper into programming, please recognize that you will eventually write a program that's going to crash. I even put an intentional crash in the examples below. Perhaps there's some typo in your code, or you accidentally divide by zero, or who knows. When a procedure or function crashes in IDL, the command prompt will return, but IDL will be left in the middle of the program where the crash occurred.
Why this is good: You can display variables deep in the code to see what might have gone wrong.
Why this is bad: If you are buried deep in some sub-procedure or sub-function of the parent program, then you may not have access to the original variables that you sent to the program. For example, suppose you wrote a program that enhances the contrast of a digital image. That program may need to call upon a homebrewed function, which crashes owing to some bug. If you try to run the code again, it will fail because it no longer recognizes the variable that stored the original image!
You can think of programs and functions as geological layers in the soil. You are at the top, the pinnacle of evolution, but you are sending data down into the procedure strata to be processed. If your procedure calls another procedure, or function, that called procedure occupies the next deeper layer, and so on. But suppose your data are sent 5 layers deep (a procedure calls a procedure calls a procedure...) and then crashes. IDL will print some useful debugging info, such as the name of the function that crashed, and the line number in the text file, but you are still stuck 5 layers removed from your original procedure call.
To get back to the top level and restore your variables, simply enter,
Retall is a sort of ejection seat in the event of a crash. Then, fix your code and recompile it:
The command .run is the simplest way to compile an IDL procedure or function after it has been modified. (.run will also, by default, take you to the surface, but you may not want to recompile right away.)
We've already applied a simple example of a function call:
y = sin(x)
In this case, IDL applies the function sin to each element of the array x and stores the result in y. sin is a function because it expressly returns a value that can be evaluated directly by another variable.
Let's make our own function. Open a new text file called stepfunction.pro and enter the following commands.
function stepfunction, x, a
Notice that return is a necessary command for a function.
Save the file, and then execute it:
print, stepfunction(1, 3.)
print, stepfunction(5, 3.)
Do the results make sense?
Now, this function is a good example of poor programming practice. This code can only handle scalar values of x (assuming a scalar value for a). What we'd like to do is pass an array of values x to compare with a scalar a. For example, if you try the following,
x = findgen(10)
plot, x, stepfunction(x, 5.)
the code will crash. Try it, and see if you can interpret the error message.
Now, let's try rewriting the code to be more arrays friendly. There are different ways to do this; see if this example makes sense to you.
function stepfunction, x, a
Re-compile and try,
x = findgen(10)
plot, x, stepfunction(x, 5.), psym=4, yrange=[-0.5,1.5]
Do the results make sense this time? By the way, the code necessarily expects the argument a to be scalar.
Write an IDL function to generate the sinc function: sinc(x) = sin(x) / x. Plot it. There had better not be any infinities! Taylor-expand sin(x) for small x to see what I mean.
Well, once you've written a couple of functions, all the surprise is lost. The code in a procedure is essentially identical, except that there is no return value. Procedures are also called directly and not as the argument of a variable assignment. For example, plot is a procedure:
plot, x, y
Make a new file called plotagauss.pro, and enter the following commands:
pro plotagauss, center, sigma, X=x, Y=y
Compile, and try
plotagauss, 1.0, 3.0
plotagauss, 2.0, 5.0
Pay attention to what happens to the axes. What we'd really like to do is plot two gaussians to compare. Happily, I allowed for the possibility of keywords. Keywords are optional arguments that can be passed to procedures or functions as additional inputs or to recover outputs. Try the following,
plotagauss, 1.0, 3.0, X=x1, Y=y1
plotagauss, 2.0, 5.0, X=x2, Y=y2
plot, x1, y1
oplot, x2, y2, linestyle=1
See if you can explain what happened here. Notice that oplot takes the keyword linestyle as an input. linestyle = 1 means plot a dotted line, instead of the default solid line.
Back to Index
Last modified by Jack Gallimore.