Working with IDL - CRPP
Working with IDL
Martin Schultz
Max-Planck-Institut
für Meteorologie
Hamburg
February 21, 2003
Contents
1 Introduction
1.1 What is IDL? . . . . . . . . . . . . . . . . . .
1.2 Getting Started . . . . . . . . . . . . . . . . .
1.3 A very first example . . . . . . . . . . . . . .
1.4 Integrated Development Environment (idlde)
1.5 Command Line Interface . . . . . . . . . . . .
1.6 Running User-written Procedures . . . . . . .
1.7 The online help . . . . . . . . . . . . . . . . .
1.8 IDL Insight . . . . . . . . . . . . . . . . . . .
1.9 The startup file . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
2
2
3
4
4
5
6
6
2 IDL Basics
2.1 A motivating example . . . . . . . . . . . . . . .
2.2 Data types . . . . . . . . . . . . . . . . . . . . .
2.3 Vectors and Arrays . . . . . . . . . . . . . . . . .
2.4 Matrix operations . . . . . . . . . . . . . . . . .
2.5 Structures . . . . . . . . . . . . . . . . . . . . . .
2.6 Formatting numbers as strings – String functions
2.7 Batch Jobs . . . . . . . . . . . . . . . . . . . . .
2.8 Programs, subroutines, and functions . . . . . . .
2.9 Automatic Compilation . . . . . . . . . . . . . .
2.10 Parameter Passing . . . . . . . . . . . . . . . . .
2.11 Loops . . . . . . . . . . . . . . . . . . . . . . . .
2.12 How to make IDL faster . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
11
11
13
14
16
16
18
18
20
21
21
22
23
3 Debugging
3.1 Argument and Keyword Checking . . . . . . .
3.2 The HELP procedure . . . . . . . . . . . . . .
3.3 Run-control: STOP, .STEP, and .CONTINUE
3.4 Catching Errors . . . . . . . . . . . . . . . . . .
3.5 Math Errors . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
25
25
26
26
27
28
.
.
.
.
.
29
29
29
31
31
36
4 Basic Plotting
4.1 IDL devices . . . . . .
4.2 IDL and colors . . . .
4.3 More on Colors . . . .
4.4 The PLOT command .
4.5 Non-linear Axes . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
i
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
ii
CONTENTS
4.6
4.7
Missing Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Multiple panels on a page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5 Map Plots, Images, Contours
5.1 How to draw a map . . . .
5.2 Contours . . . . . . . . . .
5.3 Block plot . . . . . . . . . .
5.4 Vector Plots . . . . . . . . .
5.5 Images . . . . . . . . . . . .
5.6 3D Plots . . . . . . . . . . .
and
. . .
. . .
. . .
. . .
. . .
. . .
3D
. . .
. . .
. . .
. . .
. . .
. . .
38
39
.
.
.
.
.
.
41
41
43
45
47
48
52
6 Reading and writing of data
6.1 ASCII files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2 Binary Data files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.3 NetCDF and HDF files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
53
57
58
7 Postscript Output
7.1 Creating a postscript plot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2 Another Note on Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
61
62
8 Internet resources on IDL
8.1 Web links, FAQ and newsgroup
8.2 My own IDL library . . . . . .
8.3 The EXPLORE tool . . . . . .
8.4 The Global Atmospheric Model
63
63
65
67
67
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
Output Analysis Package (GAMAP)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Chapter 1
Introduction
1.1
What is IDL?
IDL stands for ’Interactive Data Language’ and is probably best described as a programming
language for data visualization. To my knowledge IDL is most widely used in astronomy, Earth
system sciences, and medical imaging. It is a very powerful language but it takes some effort to
learn. I hope that this book will provide you with some understanding of the concept of IDL
and that you will be able to use IDL efficiently after you have digested the material I am going
to present here. I have written this book based on my own experience as a scientist who needs
to visualize all kinds of data from experiments and models. It addresses my typical colleague
who needs to use IDL but doesn’t have time to learn it. The book provides several ready-touse examples but can also be used as a reference to the basic concepts of the IDL language.
All example programs presented in this book can be found in the course directory faxaelven:
/scratch/local1/m218003/home/IDL/course. The book does not address the more sophisticated
concepts of widgets and object oriented programming. For these topics I gladly refer the reader to
David Fanning’s excellent book on ’IDL Programming Techniques’ which is also worthwile if you
aim for a more fundamental understanding of the IDL language itself.
IDL is developed and distributed by Research Systems, Inc., Boulder, Colorado. The company
was founded in 1977 by Dave Stern, who had written the first version of what would eventually
become IDL. One of the great strengths of IDL is it’s cross-platform compability: The current
version of IDL (5.5) runs on various operating systems such as Unix (various flavors), Linux,
Windows, and MacOS. For the most part, you can run programs written for one platform on
another platform without changes. Research System also strives to ensure backward compability,
and in fact you can often run old programs (back to version 3 or so) without major adaptation
efforts. The long history of IDL ensures that IDL is very stable (with the possible exception of
new features), but it also implies a legacy of ’ancient’ programming style and restrictions. If you
venture into learning IDL you will find some occasions where you ask yourself ’Couldn’t this be
done much easier?’.
This book would not have been written without all the advice I got over the years from various
people all over the world, most notably David Fanning who also maintains a very valuable web
site with many tips and example programs. This is the first version of this book and I would like
to invite you to submit your feedback with suggestions on how to improve this document. Please
send your comments to [email protected] .
1
2
CHAPTER 1. INTRODUCTION
1.2
Getting Started
I assume you have successfully installed IDL or that you have access to an IDL installation in a
workstation cluster. In this case, you might have to set some environment variables in order to be
able to run IDL. Please ask your system administrator for details.
I recommend that you set up the following directory structure in your user domain so that you
can follow the examples in this book:
$HOME/IDL--|
|--/tools
|--/course
(Windows users may want to create C:/IDL/TOOLS and C:/IDL/COURSE instead). In the IDL
directory you should create a so-called startup file (for details see section 1.9) which is a simple
text file containing the following lines:
device,true=24
device,decomposed=0
!PATH=’~/IDL/course:~/IDL/tools:’+!PATH
On Windows machines replace ’ /IDL/course: /IDL/tools:’ with ’C:/IDL/course;C:/IDL/tools;’
and on the Macintosh you need to define it as a comma seperated list. Then you can download
the book examples and my tools collection from the following web site and store these programs
in the respective directories:
http://www.mpimet.mpg.de/~schultz.martin/idlbook
Note: If you use the IDL Integrated Environment (idlde) — this is the only choice on Windows
and Macintosh systems — you can enter the name of the startup file in the File-Preferences-Startup
dialog and add the two directories to the IDL search path with File-Preferences-Paths.
Note: At the MPI-Met in Hamburg, IDL is usually found in the /client/bin directory. If
not, please ask the help desk. If you simply type ’idl’ at the command prompt, you should see a
welcome message and the idl prompt waiting for input. If you see something like “Demo version”
or “Evaluation copy”, then there is very likely a problem with the license manager. Please ask the
help desk in this case.
At MPI IDL is licensed with several floating licenses. The license manager counts the users
and platforms. If one user runs several IDL sessions on the same platform, he/she uses only one
license (10 units), however, if the same user starts IDL on two different platforms, he/she uses
two licenses and may thus keep someone else from working with IDL. You can find out about the
current use of IDL with the command lmstat -a.
We also have a central repository for a number of IDL program libraries. This can be found
in /sw/common/idl/lib. A browsable description of these programs should be on the web again
shortly.
1.3
A very first example
Type idlde at the Unix command prompt or double click the IDL icon on your Windows or
Macintosh system. You should see the Integrated Development Environment appear on the screen.
For now let us ignore the details and just focus on the IDL command line which is at the bottom of
the IDLDE window and starts with the prompt IDL>. Enter the following text into the command
line field:
1.4. INTEGRATED DEVELOPMENT ENVIRONMENT (IDLDE)
3
print,’Hello IDL’
and press the enter key. You should see a copy of the command you entered and the output (Hello
IDL appear in the so-called log window. More information on the various windows in the IDLDE
will be given in section 1.4.
Notice that you can enter IDL commands at the command line and they will be exectued
immediately. This distinguishes IDL as an interpreted language from compiler languages such as
FORTRAN or C. In section 2.8 we will see how it is also possible to write IDL programs which
can be executed repeatedly. In my opinion, it is one of the important features of IDL that you can
’play around’ with your data on the command line, and once you are satisfied with the results you
can put your commands into a program and repeat the analysis as often as you like.
In the above example, PRINT is an IDL command, and the string ’Hello IDL’ is its argument.
Commands and arguments are seperated by a comma in IDL.
Now type
a=5
print,a,a+5
(each line terminated with the enter key). You will see 5 and 10 listed on the display. A is a variable
and it is automatically declared an integer variable with its assignment as shown here (see section
2.2 for more information on data types). A+5 is an expression. It is evaluated as an argument to
PRINT which thus prints out the result (10).
Now hit the arrow-up key, and you should see the last input line (PRINT,A,A+5) redisplayed.
You can edit it as you wish or just hit the enter key again so it will be executed again. That’s
about all you need to know about the IDL command line for now. A more detailed description will
be given in section 1.5 which deals with the Unix command line interface (usually invoked with
the Unix command idl).
Before we move on with an overview of the IDL Integrated Development Environment let us
test whether you installed everything correctly. Please type:
test_bookinstall
at the IDL command line. You should see the following output in the log window:
TESTINSTALL routine found.
Test passed. Tools routine was found.
Do you see a white plot on a black background?
(Y)es or (N)o ? [Enter=yes] :
Press the enter key if everything seems OK, otherwise follow the instructions outlined in the screen
output.
For the remainder of the book I will mark lines that you should enter directly at the IDL prompt
with a preceeding IDL> whereas program listings (which are stored in text files) don’t show the
IDL> prefix.
1.4
Integrated Development Environment (idlde)
The integrated environment is started with the command idlde (on Windows and Macintosh
platforms, this is what you get if you click the IDL icon). It consists of a menu bar, several icons,
the program file window, the log window, and the command line. For more information about the
development environment, consult the online help:
4
CHAPTER 1. INTRODUCTION
1. type idlhelp & at the unix prompt
2. select Help -- Index search and type idl
3. select Development Environment (IDLDE) as topic and select
The IDL for Motif Interface.
1.5
Command Line Interface
If you start IDL by typing idl on one of the Sun workstations at the Max-Planck-Institut in
Hamburg, you will see the following information displayed (version number may change, of course):
IDL Version 5.2 (sunos sparc). Research Systems, Inc.
Installation number: 80777-0.
Licensed for use by: MPI fuer Meteorologie
For basic information, enter "IDLInfo" at the IDL> prompt.
IDL>
The last line is the IDL prompt where you can now enter IDL commands or statements as
explained in section 1.3. You can use the up-arrow and down-arrow keys to scroll through a
command line history buffer and edit a command line before submitting it by pressing the return
key.
Tip: In order to increase the number of lines in the history buffer, set the !EDIT INPUT system
variable in your IDL startup file (see section 1.9).
That’s basically all there is to the command line interface. It is my favorite because it is
so simple and plain. In addition to it you will need an editor such as vi or emacs on Unix or
the Notepad (better WordPad) in Windows. Just one more sentence: while it may seem at first
glance that the integrated environment is much more powerful for debugging your programs and
watching the variable status, these things can all be done from the command line as well. This
will be covered in chapter 3.
1.6
Running User-written Procedures
In order to run a user-written procedure, simply type its name and possible arguments. As an
example, let me introduce the usage procedure which you can find among my tools library and
which accepts the name of a procedure as a string parameter. Here we will apply it on itself:
IDL> usage,’usage’
% Compiled module: USAGE.
% Compiled module: FILE_EXIST.
% Compiled module: STR_SEP.
USAGE:
; CALLING SEQUENCE:
;
USAGE,routinename
;
; INPUTS:
;
ROUTINENAME -> (string) name of the routine for which help information
1.7. THE ONLINE HELP
5
;
shall be provided. Tip: to get help for the current routine use
;
function routine_name().
;
; KEYWORD PARAMETERS:
;
/PRINTALL -> prints complete header information. Normally, only
;
"user relevant" information is displayed.
;
; OUTPUTS:
;
prints usage information on the screen.
;
; EXAMPLE:
;
Error checking :
;
;
if (n_params() ne 2) then begin
;
print,’Invalid number of arguments!’
;
usage,routine_name()
;
endif
;
;
Get the idea what to type from the command line:
;
usage,’my_routine_with_too_many_arguments’
;
As you can see, the usage procedure displays information on how to use an IDL procedure or
function. I am sure this will be quite handy on several occasions.
The three lines that begin with % Compiled module: demonstrate how IDL automatically
compiles procedures if you just type the procedure name. If you type usage,’usage’ again, you
will notice that these lines are not displayed again. For details on how autocompilation works, see
section 2.8.
Note: Even though IDL claims that it ’compiles’ a routine, it remains an interpreted language
after all. The compiling step simply condenses the code into a form where it can be processed
much faster. The fact that IDL interpretes its code at runtime has the advantage that you can
dynamically EXECUTE procedures whose name may not even be known when you start a program.
1.7
The online help
Once you have learned how to operate with the online help, you can almost dump the printed
manuals into the garbage. The complete manuals are online and you can search for keywords and
routines much more efficiently than in the printed manuals. Yet: even if you know how to use
the online help you may occasionally run into trouble finding the information that you need. This
topic keeps popping up in the IDL newsgroup (see section 8.1) but it is apparently non-trivial to
solve these problems.
You start the online help either by typing idlhelp at the unix prompt or by typing ’?’ at the
IDL command line prompt. In Windows you need to double click on the IDL Help icon. From the
integrated environment you can select help with your mouse.
Upon startup, the help will present itself with the ’Online Help Navigator’ which gives you —
among other links — three entry points to look for a routine:
• Alphabetical list of routines
• List of Routines by Application
6
CHAPTER 1. INTRODUCTION
• Language Features Quick Reference
Just browse around in these three sections and see what you find. You can always get back to
the front page by selecting Navigate - Contents and then the IDL Online Help Navigator.
Another powerful way to look for a specific routine is the search by index (Navigate - Index
Search). Type the first few characters of what you are looking for and you will be presented with
a list of likely matches. You have to be creative, however, because sometimes you will just not
find information at the place where you think it should be. Example: PLOT will list ’plot object’
as first entry whereas it is more likely that you are looking for help on the PLOT command. This
is listed under ’PLOT procedure’.
Help on a specific routine is structured into the following sections: Purpose, Calling Sequence,
Arguments, Keywords, Example, See Also. It is usually fairly complete, although not everything
is covered. If you forgot the name of a specific routine, it is often a good idea to look for a similar
routine and then inspect the ’See Also’ section. Or you can try to locate the routine via the ’List
of Routines by Application’ section.
Tip: Some information is embedded a little deeper, e.g. the description of the netCDF or
HDF routines. For these, you have to open the ’book’ on Scientific Data Formats first (Click on
Navigate - Contents and select the book (double click), then open it by double clicking on ’Open
...’. Once you are there it is straightforward to use.
1.8
IDL Insight
Insight is Research System’s answer to the meriad of Windows based plotting programs that allow
the user to select the actions by mouse rather than typing commands. I’ve been told it is not bad
for starters, but it lacks some of the flexibility you have with the IDL language. Personally, I have
never used it, so I can’t tell you much about it either.
1.9
The startup file
A startup file is your best chance to configure IDL according to your needs and your platform’s
possibilities. There are some options in IDL which can only be set before the first graphics window
is opened or before the command line is displayed on the screen. These must be set in a startup
file which is a simple text file with IDL commands. You can tell IDL where to find it by setting
the IDL STARTUP environment variable.
At the MPI-Met, we use a common startup file, which will automatically give access to the
system-wide libraries, but also allows for customization by the user. Please make sure that your
IDL STARTUP environment variable points to /sw/common/idl/idl startup.pro (unless you are
working under Solaris 5.6 or Windows - then you are on your own).
You can then grab a copy of the .idlrc file provided in /sw/common/idl/.idlrc, adapt this file
to your needs and store it in your home directory. In the .idlrc file, you can set your name and
email address and lateron use this in your programs by accessing the !USER system variable. The
system-wide startup file will attempt to execute this script, but IDL will also run without.
In case you are interested, here is a copy of the startup file we use at MPI-Met:
; Preferences file for IDL
; Platform independent version, Martin Schultz 11 March 2001
; (may not work on all platforms yet)
; 1. Set filepath delimiter according to platform
1.9. THE STARTUP FILE
7
dl = ’/’
; Assume Unix as default
IF !VERSION.OS_FAMILY EQ ’Windows’ THEN dl = ’\’
IF !VERSION.OS_FAMILY EQ ’Mac’ THEN dl = ’:’
; 2. The IDL main directory (don’t change)
idlexedir = !DIR + dl
; 3. Set default directory for MPI library
idlmpilib=’/sw/common/idl/lib/’
; Assume Unix as default
IF !VERSION.OS_FAMILY EQ ’Windows’ THEN idlmpilib=’’
IF !VERSION.OS_FAMILY EQ ’Mac’ THEN idlmpilib=’’
; 4. Get user name, login ID and home directory
; (name can be overwritten in users .idlrc file)
name = ’nobody’
cmd=’finger $USER | head -1 | cut -d ":" -f 3’
IF !Version.OS_Family EQ ’unix’ THEN spawn, cmd, r
IF N_Elements(r) GT 0 THEN nuser=n_elements(r)
IF N_Elements(r) GT 0 THEN name=StrTrim(r[nuser-1],2)
user = strtrim(getenv("USER"),2)
homedir = strtrim(getenv("HOME"),2)
; 4. Set defaults for other user settings
initials = ’..’
email = ’[email protected]’
idlusrdir = homedir + dl + ’IDL’ + dl
idlusrlib = idlusrdir + ’lib’ + dl
USE_OBSOLETE = 0
QUIET = 0
!PATH = ’’
;
;
;
;
;
;
The user initials
The user email address
The user IDL home directory
The IDL user’s personal library directory
Use obsolete system library routines
Don’t display settings
; 5. Define system variable with user information
defsysv, ’!USER’, { NAME:name,
$
INITIALS:initials,
$
USERID:user,
$
EMAIL:email,
$
HOMEDIR:homedir,
$
IDLUSRDIR:idlusrdir,
$
IDLUSRLIB:idlusrlib,
$
IDLMPILIB:idlmpilib
}
; 10. Increase length of input buffer
!EDIT_INPUT=50
8
CHAPTER 1. INTRODUCTION
; 6. Try to locate user’s .idlrc file and execute it. If not there, issue warning
usrfile = ( Findfile(homedir+dl+’.idlrc’) )[0]
IF usrfile EQ ’’ THEN print,’%% No .idlrc file found in ’+homedir
IF usrfile EQ ’’ THEN print,’%% Some settings in !USER may not be correct’
cd, current=curdir
cd, homedir
@.idlrc
cd, curdir
QUIET = Keyword_Set(QUIET)
; 7. Build IDL search path
; Normally, users will have defined their own directories in .idlrc so we
; have to append the common libraries to the !PATH variable
; 7.1 remember user path settings for status report
UPATH = !PATH
; 7.2 MPIfM wide libraries
XPATH = $
!USER.IDLMPILIB +’martin_schultz:’ + $
!USER.IDLMPILIB +’mgs_newobjects:’ + $
!USER.IDLMPILIB +’geov:’
+ $
!USER.IDLMPILIB +’david_fanning:’
+ $
!USER.IDLMPILIB +’david_fanning/mpi_plot:’
!USER.IDLMPILIB +’mark_hadfield:’
+ $
!USER.IDLMPILIB +’esrg:’
+ $
!USER.IDLMPILIB +’liam_gumley:’
+ $
!USER.IDLMPILIB +’jhuapls1r:’
+ $
!USER.IDLMPILIB +’craig_markwardt:’ + $
!USER.IDLMPILIB +’tex2idl:’
+
$
; Other procedures, no longer in PATH
;
idlusrdir +’objects:’ + $
;
idlusrdir +’hiphop:’ + $
;
idlusrdir +’gamap:’
;
idlusrdir +’grib:’ + $
;
idlusrdir +’grib/gribidl:’ + $
; 7.3 Build path for system routines manually to prevent obsolete coming before lib
;
Omit all example files
SPATH = idlexedir
idlexedir
idlexedir
idlexedir
+
+
+
+
’lib:’ + $
’lib/hook:’ + $
’lib/utilities:’ + $
’lib/macros:’
; this is only needed for IDLDE!
IF Keyword_Set(USE_OBSOLETE) THEN SPATH = SPATH + idlexedir + ’lib/obsolete:’
; 7.4 Compose !PATH system variable
1.9. THE STARTUP FILE
9
!PATH = !PATH + XPATH + SPATH
; 8. Report status
print,’Welcome ’+!USER.NAME
print
IF NOT QUIET THEN print,’The following personal libraries are included in the search path:’
IF NOT QUIET THEN print,UPATH
IF NOT QUIET THEN print,’The following MPI wide libraries are included in the search path:’
IF NOT QUIET THEN print,XPATH
; 9. Delete local variables
DELVAR, name, initials, user, email, homedir
DELVAR, idlusrdir, idlusrlib, idlmpilib, idlexedir, spath, upath, xpath
DELVAR, curdir, dl, r, use_obsolete
; 11. Call Liam Gumley’s COLORSET routine to ensure
; working colors
COLORSET,decomposed=0, quiet=QUIET
; 12. Goodbye
IF NOT QUIET THEN print,’Startupfile for user ’,!USER.USERID,’ processed.’
Note: The startup file is a batch file (see section 2.7). You can call other procedures from
it (including your own), but you must be aware that some variables may still be undefined at this
stage, e.g. the number of colors available !D.N COLORS. Furthermore, you cannot use multiline
BEGIN END blocks.
10
CHAPTER 1. INTRODUCTION
Chapter 2
IDL Basics
2.1
A motivating example
In order to demonstrate a few of IDL’s graphics capabilities and (more important) IDL concepts,
let us go through a bogus example. You can enter all of these commands at the IDL prompt:
IDL> loadct,0,ncolors=64
; load a color table
This command loads a new colortable into 64 of the available (256 or less) color indices (more
on color tables in section 4.2). The ’;’ character starts a comment. Each comment extends to
the end of the line. Comments are ignored in procedures as well as on the command line. Here,
you don’t have to type them of course, but when you are writing procedures (see section 2.8) you
shouldn’t be too sparse with them.
Procedure and function names are case-insensitive in IDL, however, the filenames for these
procedures must always be lowercase in order to have automatic compilation (see section 2.8)
work. Oh yes! And don’t use special characters like ’.’, ’#’, ’$’, etc. in your procedure names (’ ’
is allowed).
Next, type:
IDL> c=getcolor(/LOAD)
This statement calls David Fanning’s GETCOLOR routine (which is distributed in the course directory
with his permission). GETCOLOR also affects the color table; it defines 16 so-called ’drawing colors’
c color scheme. Again, you will learn more about colors lateron. Here, I
according to the McIdas°
justwant to make sure that we all see the same.
Now let us create some data that we can plot:
IDL> x=findgen(200)*3.6
IDL> y=sin(x/180.*!PI)
; create an x vector from 0..720 with 200 elements
; create a sine curve
The FINDGEN function creates a 1-dimensional array of floating point numbers starting from 0 and
incremented by 1 for each element ([0.,1.,2.,3.,...,199.]). These values are then multiplied with the
constant 3.6. This is one demonstration for IDL’s capabilities in manipulating arrays with one
line.
The y values are calculated from the x values by applying the sine function. X is converted
from degrees to radians by dividing by 180 and multiplying with π which is represented as the
system variable !PI in IDL.
11
12
CHAPTER 2. IDL BASICS
Note: Variables that begin with ’!’ are so-called system variables. These are predefined
variables with global scope. You can define your own system variables with the DEFSYSV procedure
(see the online help for details). There are four system variables about which you will learn more
in chapter 4: !D, !P, !X, and !Y. These define the current graphics device, the current plot
environment, and the current settings for the x and y axes.
Now let us plot the sine curve. Type:
IDL> plot,x,y,color=c.cyan
If everything is set up correctly, you should see a cyan curve on a black background now. Note
that the x axis extends to 800 even though x only reaches 719. You will learn how to control the
axis appearance in section 4.4. Let us mark the y = 0 line:
IDL> plots,[0,800],[0,0]
; overlay the y=0 line
Individual points or simple lines can easily be drawn with the PLOTS command. The square brackets
denote array constants (they are also used for array indices). The two statements:
IDL> a=findgen(3)
IDL> a=[0.,1.,2.]
yield identical results.
Line plots are boring, so let us draw a map of Europe for diversion:
IDL> map_set,0,0,limit=[15,-10,70,45],/continents,
IDL>
position=[0.7,0.55,0.95,0.90],/noerase
$
The ’$’ character at the end of the first line denotes a continuating line. Normally, IDL accepts
1 statement per line. You can use the special characters ’$’ to continue a line and ’&’ to put two
commands on one line. After the second line was submitted with the enter key, you should see a
map of Europe appear in the upper right quarter of the plot window.
The MAP SET statement demonstrates the use of (named) keywords. With LIMIT = value you
can choose a region of the globe, /CONTINENTS asks IDL to plot continent outlines, and POSITION
shows how you can place a plot at a specific position on the graphics window (more on this in
section 4.7). The slash (’/’) in front of a keyword name is equivalent to setting this keyword to 1
(i.e. ’true’). Hence, /CONTINENTS means the same as CONTINENTS=1. Keywords can be placed at
arbitrary positions within the statement, unlike arguments (such as x or y in the PLOT command)
which get their meaning from their position. Thus,
IDL> contour,z,x,y,levels=[1.,10.,100.],c_colors=[1,2,3],/FILL
is equivalent to
IDL> contour,z,/FILL,x,y,c_colors=[1,2,3],levels=[1.,10.,100.]
but not to
IDL> contour,x,y,z,/FILL,levels=[1.,10.,100.],c_colors=[1,2,3]
(In the last example, x, y, and z were exchanged).
So now we have plotted a map, but how can we put our data on it? This question will be
answered in chapter 5. Now, let me show you an example how you can display images in IDL.
IDL> read_jpeg,’~/IDL/course/floyd.jpg’,image
IDL> TVSCL,image[400:749,480:829],top=63
2.2. DATA TYPES
13
These two lines load the example image file floyd.jpg from the course directory and display
the portion with hurricane Floyd in it. Change the file path to your course directory if you have
installed things differently (in Windows you would type ’C:/IDL/COURSE/FLOYD.JPG’).
Now, type ERASE to clear the screen and get ready for a desert stretch which covers the fundamentals of IDL programming. But before, let me show you who you are: I have mentioned the
!USER system variable, which is defined in the MPI-Met startup script. To see what is in there,
type:
IDL> help, !USER, /structure
This is a very powerful method for data inspection and debugging (see section 3).
2.2
Data types
The following table summarizes the available data types in IDL. Also included are the format to
initialize a value in a certain type, and the statements to cast a variable to a certain type and to
create an array of that type (either initialized with zero or filled with consecutive values starting
at zero).
IDL data types
Type
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Name
Undefined
Byte
Integer
Longword Integer
Float
Double Float
Complex Float
String
Structure
Double Complex
Pointer
Object Reference
Unsigned Integer
Unsigned Long
64 bit Integer
Unsigned 64 bit
Value
0B
0
0L
0.
0.D
(0.,0.)
’A’
{a:0.}
(0.D,0.D)
ptr_new()
obj_new()
0U
0UL
0LL
0ULL
Cast
Generate
Index
byte()
fix()
long()
float()
double()
complex()
string()
bindgen()
indgen()
lindgen()
findgen()
dindgen()
cindgen()
sindgen()
dcomplex()
bytarr()
intarr()
lonarr()
fltarr()
dblarr()
complexarr()
strarr()
replicate()a
dcomplexarr()
dcindgen()
uint()
ulong()
long64()
ulong64()
uintarr()
ulonarr()
lon64arr()
ulon64arr()
uindgen()
ulindgen()
l64indgen()
ul64indgen()
Thus, to define a floating point and a double precision variable, you can type
IDL> x=78. & y=79.D
Float variables have about 7 significant digits and range from about 10−37 to 1038 (positive or
negative). Double precision values store 14 significant digits and can hold numbers as large as
10308 .
To create an array of 10 long integer values, all initialized to 0, type
IDL> a=lindgen(10)
a REPLICATE can be applied to other data types as well, but for structures it is the only convenient method to
create arrays
14
CHAPTER 2. IDL BASICS
’Normal’ integer variables can store values from −32768 to 32767 and long integers range from
−2147483648 to 2147483647 (approximately 2 × 109 ).
Tip: Instead of the type specific array creation routines INTARR, FLTARR, etc., you can also
use the more general function MAKE ARRAY() . The INDGEN function also accepts keywords to create
arrays of different data types.
You will learn more about arrays and how to index them in section 2.3.
Normally, IDL handles data types very flexible and you don’t need to care too much whether
you use e.g. integer or long. However, you should be aware of a few rules:
• When you need greater numerical precision, you obviously want to choose double over float.
Be careful when you compare double and float numbers, because this involves a type conversion which often leads to a roundoff error. Example: print,5.e10-5.d10 leads to −1024.
as result.
• Always use floating point numbers in divisions (unless you know what you are doing)! 10/3
yields 3 (an integer!) not 3.333 as you probably expect. This error is particularily common
in computing averages.
• Always use type long for counters and array indices! I have been burned several times using
simple integers in a loop. Your routine might work well for the first 200 times you use it,
but then you apply it to a large data array and you get into trouble because you exceed the
range of a simple integer (it’s only 32767). You need to force a loop variable to type long as
in
for i=0L,N do ...
and you should make sure always to return -1L as default when your function computes array
indices (see section 2.3).
• Reading data from a file (or a string) requires the type to be predefined. FORTRAN integers
are (usually) long integers in IDL, i.e. they take up 4 bytes in a binary file. Even if you read
from ASCII files, it may be important to predefine the data type (e.g. if you want to read
strings).
Note: Expressions are evaluated from left to right, and this is how IDL converts the data
types. Hence, print,10/3+3.3333 yields 6.3333 because the first part is evaluated as integer, and
the expression becomes a floating type expression only afterwards.
2.3
Vectors and Arrays
In the previous section we have seen how to create arrays of various data types. You can pass
up to 8 dimensions as function arguments to the ...arr or ..indgen functions. One-dimensional
arrays are usually called vectors. Here are examples for the creation of a vector, a 2-dimensional
array and a 3-dimensional array:
IDL> a=findgen(24)
IDL> b=findgen(4,6)
IDL> c=findgen(2,2,6)
All three arrays contain the same number of elements (type print, n elements(a) (b), and (c)
to find out). You can convert all arrays from one dimensionality to another with the REFORM
command:
2.3. VECTORS AND ARRAYS
15
IDL> help,a,b,c
IDL> help,a,reform(b,24),reform(c,24)
IDL> help,reform(a,2,2,6),reform(b,2,2,6),c
will show you the difference (more on the HELP procedure in section 3.2).
Array constants are defined with square brackets:
IDL> month=[’JAN’,’FEB’,’MAR’,’APR’,’MAY’,’JUN’, $
IDL>
’JUL’,’AUG’,’SEP’,’OCT’,’NOV’,’DEC’ ]
This defines a string array with the name of the months. Or:
IDL> a=[[0,1,2],[3,4,5],[6,7,8],[9,10,11]]
which is equivalent to
IDL> a=indgen(3,4)
Arrays are stored ’column-first’ in IDL (this is different than in most programming languages!).
It may be easiest to remember if you think of an image scanned by a digital camera: the camera
scans line by line, so the column index varies fastest. In fact, image processing is the very reason
why IDL was written this way. If you type PRINT,A after the last example, you will see that the
array consists of 3 columns and 4 rows.
You can get information about array dimensions at the command line withthe HELP procedure
(see section 3.2). In IDL procedures you can use the SIZE function. This is a very useful tool for
determining the dimensions and data type of any IDL variable. Its output is a vector of variable
length, depending on the number of dimensions. For the example image floyd.jpg which has
been used in section 2.1, SIZE returns [2, 1043, 928, 1, 967904]. The first value denotes the number
of dimensions (since IDL version 5.2 you can also use SIZE(var, /N DIMENSIONS)). The next two
values list the array dimensions themselves (SIZE(var, /DIMENSIONS)). Next follows the variable
type (an image is of type byte; see table in section 2.2), and finally the number of elements stored
in the variable.
Any variable in IDL can be indexed with a (set of) long integer(s). Array indices are written
as square brackets (parantheses are still allowed, but Research Systems recommends that you use
square brackets). Array indices always start with zero. If you index a variable by a negative value,
IDL produces a runtime error.
An array index can be a number or an array for each dimension:
VAR[4,7]
VAR[[1,2],8]
VAR[[1,2],[7,8]]
VAR[[1,2],[7,8],0]
are all valid expressions (for an array with at least dimension 3 × 9). While the combination of a
vector index with a scalar (VAR[[1,2],8]) returns elements var 1,8 and var2,8 , two index vectors
(VAR[[1,2],[7,8]]) yield the elements that are indexed by each pair of values, i.e. var 1,7 and
var2,8 . Read the section on Array Subscripts in the online help for more information on this subject
(A quick reference is available under ’Language Features Quick Reference - Subscripts’).
Note: VAR[0] is identical to VAR if VAR is a scalar or a 1-element array — with one important
exception: Boolean expressions (such as a EQ b) only operate on scalars. You can always make
sure to have a scalar by indexing the first element, i.e. a[0] EQ b[0].
16
CHAPTER 2. IDL BASICS
You can also specify subscript ranges as VAR[i0:i1]. This is especially useful together with
the special value ’*’ which denotes ’all elements’ or ’to the last element’: VAR[*,j,k] returns all
values of the first column which are indexed by j and k in the second and third dimension (thus
var0,j,k , var1,j,k , ...), and VAR[5:*,j,k] does the same starting with the sixth element.
Tip: I wrote a little function named ARREX which can be used to extract sub-arrays with arbitrary
dimensions and strides. This can be found in my tools library.Type USAGE,’ARREX’ to find out how
it works.
IDL automatically removes unnecessary dimensions on several occasions. If you define an array
like a=FLTARR(5,1) and look at it’s type with the HELP procedure (see section 3.2), you will
see A FLOAT = Array[5]. However, leading dimensions are preserved: a=FLTARR(1,5) yields
A FLOAT = Array[1,5]. You can turn ’row’ into ’column’ arrays with the TRANSPOSE procedure.
For vectors you can also use REFORM:
IDL> b1=transpose(a)
IDL> b2=reform(a,1,n_elements(a))
The two statements yield identical results if a is a vector.
A very powerful function in IDL is WHERE. This function returns an index to each element of
an array that fulfills a boolean condition (or -1L if no element meets the condition). Example: To
filter out all data between 400 S and 500 N from a 2-dimensional array you can write
data = data[*, WHERE(lat GE -40. AND lat LE 50.)]
Tip: If there is only a slight chance that you will encounter a situation with no data in the
requested range, you should take measure to avoid a crash due to indexing the data array with a
negative number (remember: WHERE returns -1L if nothing is found and negative array indices are
not allowed). A more robust version of the last example is:
ind = WHERE(lat GE -40. AND lat LE 50.,count)
IF (count gt 0) THEN $
data = data[*, ind] $
ELSE $
MESSAGE,’No data in latitude range!’
**** Addition: WHERE returns a 1-dimensional index vector even for 2- or 3-D arrays. Sometimes you want to convert this vector back into individual array indices. ??? has written a function
to do this ...
2.4
Matrix operations
**** matrix multiplication (##) and transposed multiplication (#)
A# B is equal to B## A.
2.5
Structures
Structures are collections of data with different types. IDL knows two different kinds of structures:
anonymous and named structures. Internally, anonymous structures are structures with a random
name (which is why you can’t concatenate two different anonymous structures even if they have
the same definition; see below).
A structure is created with the syntax var = { [structure name,] tag1:value1, tag2:value2, ...
}. If you omit name you define a so-called ’anonymous structure’.
2.5. STRUCTURES
17
IDL> person = { name:’Hans’, age:35, phone:’040/88443322’ }
This example creates an anonymous structure with 2 string and one integer elements. You can
access individual tag values as
print,person.name,’:’,person.age
or (without having to know the tag name) as
print,person.(0),’:’,person.(2)
The tag names can be retrieved with the TAG NAMES function and the number of tags with N TAGS.
You cannot change the data type of a structure tag once it is defined (although you can redefine
the structure completely if it is anonymous). Once again, you need to be careful especially with
integer variables:
IDL> test = { i:0 }
IDL> test.i = 80000L
IDL> print,test.i
; define a structure with only one integer value
; overwrite its value
demonstrates what I mean. (Note that the two statements I=0 and I=80000L would have worked
as they should since I would then be redefined as a variable of type long).
Tip: You can use my CHKSTRU function to check if a given variable is a structure and whether
it contains a certain tag name. On the command line you can get structure information with
HELP,var,/STRUCTURE (see section 3.2).
Arrays of structures are created via the REPLICATE function:
IDL> class = replicate({ name:’’, age:0 },26)
makes room for 26 students. The first student’s record is accessed via
IDL> class[0]
and the mean student age can be computed as
IDL> mean_age = mean(class.age)
In order to merge two structures together as one array, they must have the same structure
name. This is easily accomplished with named structures:
IDL> a={test,x:5.,title:’sea’}
IDL> b={test,x:2L,title:’lake’}
IDL> help,[a,b]
Note that the x value of b is automatically converted to float because IDL ’knows’ from the first
definition of the structure named ’test’ that x must be float. You cannot combine two structures with different structure names (how should IDL tell that they might contain information of
compatible types?).
Anonymous structures also carry an internal structure name; it is randomly generated. It thus
follows that you cannot combine two anonymous structures as easily even if the definitions seem
identical. Instead of
IDL> a = { x:0., title:’sea’ }
IDL> b = { x:1., title:’lake’ }
IDL> comb = [ a, b ]
18
CHAPTER 2. IDL BASICS
you must type:
IDL>
IDL>
IDL>
IDL>
a = { x:0., title:’sea’ }
b = a
b.x = 1. & b.title=’lake’
comb = [ a, b ]
To expand a structure by adding more tags to it you can use the CREATE STRUCT function (as
the name says, you can also create structures with it of course). We will make use of this in the
netCDF routine NCDF READ in section 6.3. Here is an example:
a = { x0:0., y0:0. }
b = { x1:1., y1:1. }
corner = create_struct(a,b)
(Type HELP,corner,/STRUCTURE to verify that the new structure contains all four tags).
2.6
Formatting numbers as strings – String functions
IDL’s STRING function accepts a FORMAT keyword which is a string identical to the FORTRAN format string. Valid examples are ’(f8.3)’, ’(i12)’, ’(1X,A10)’, ’(i4.4)’. The last example
adds leading zeroes to an integer (convenient for automatic file name generation).
Other useful string functions are STRTRIM and STRCOMPRESS. STRTRIM cuts off leading and/or
trailing blanks (most often you will use it as STRTRIM(arg,2)), whereas STRCOMPRESS eliminates
blanks within a string. Normally, one blank remains between each word, but with the REMOVE ALL
keyword these will be cut as well. All string functions begin with STR so it is easy to find them in
the alphabetical procedure list in the online help.
Tip: Don’t forget to remove leading blanks with STRTRIM if you want to align numbers left or
centered.
In order to place a label on a plot, you can use the XYOUTS procedure which accepts scalars
or arrays for X,Y,OUTSTRING and keywords to align and rotate the string(s). We will encounter
XYOUTS again in section 4.4.
Tip: David Fanning has written a nice routine to calculate the width of a string in a plot:
STR SIZE. This can be handy if you are dealing with automatic annotations. Just check his article
’Calculating string size in IDL’ on his WWW tip page.
People who often need to print greek characters or math symbols on their plots may want to
take a look at the Tex2IDL package, available on the Internet (see section 8.1).
If you want to parse string expressions and cut them into arguments, you might be interested
in the STR SEP function which does just this.
IDL> sentence=’My house is very nice’
IDL> words=STR_SEP(STRCOMPRESS(sentence,’ ’))
splits a sentence into words. The STRCOMPRESS function makes sure that double blanks don’t mess
up your word count.
2.7
Batch Jobs
There are several ways to execute IDL statements: you can enter them at the command line,
run them as a batch job or as a (main) program, or you can collect them in reusable modules
(procedures and functions).
2.7. BATCH JOBS
19
If you are tired of typing the same lines at the command prompt over and over, you can write
these statements into a file and execute this file with
IDL> @filename
If you were clever from the start, you would have opened a JOURNAL file before you executed the
commands:
IDL> journal,’mycommands.pro’
When you have retyped all your commands (hey! we can use the command line history buffer!),
close your journal file by typing JOURNAL without arguments. Then you can rerun these commands
with mycommands.
It is important to note that a a batch job behaves just as if you had typed the commands atthe
command line. E.g. you can issue compile commands (see below) which are not allowed in IDL
programs. On the other hand, a batch file must not contain the word END and cannot contain
multi-line BEGIN END blocks.
To demonstrate this, enter the following loop at the prompt:
IDL>
IDL>
IDL>
IDL>
for i=0,4 do begin
j=i*2
print,i,j
end
Almost certainly not what you want!
Tip: You can use a combination of ’&’ and ’$’ to fool IDL. The last example will work if you
type:
IDL>
IDL>
IDL>
IDL>
for i=0,4 do begin &$
j=i*2 &$
print,i,j &$
end
Or shorter:
IDL> for i=0,4 do begin & j=i*2 & print,i,j & end
Note: The IDL startup file (section 1.9) is nothing else than a batch job which is exectued very
early in the game.
The @ ’command’ is also used to include files verbatim into a procedure or program. In this
case the lines are interpreted as if they were part of the procedure. You can use multi-line BEGIN
END but no run-control commands.
For completeness, I also mention the SAVE RESTORE procedure pair. These can be used to
distribute IDL programs as binaries. Please consult the online help for information on these
procedures.
Tip (from the online help): Under Unix and VMS, IDL can be run entirely in the noninteractive mode by including the name of a file containing batch mode commands in the shell
command used to invoke IDL. When the end of the file is reached, control reverts to the interactive
mode and input is accepted from the keyboard. Call the EXIT procedure from the file to cause IDL
to return to the operating system if you do not want to use IDL in the interactive mode.
20
CHAPTER 2. IDL BASICS
2.8
Programs, subroutines, and functions
An IDL program is simply a file containing a list of statements (one per line) terminated with
the word END. Typically, IDL programs, functions, and procedures have the file extension ’.pro’.
Before a program, procedure or function can be executed, it must be compiled. This can be done by
typing .RUN or .COMPILE at the command line. For procedures and functions the two commands
are identical, i.e. .RUN does not execute the procedure as the name suggests (’Main’ programs
are however executed). To execute a procedure, just type the procedure’s name (followed by the
arguments and keywords you wish to use).
Program or procedure names can be as long as the operating system allows. While case does
not matter inside a program or procedure file, it is important for the filename. On Unix platforms
you should always name your files in all lowercase characters. Please don’t use special characters
like ’.’, ’#’, ’$’, ’&’ in your procedure and filenames (’ ’ is allowed and you can add one ’.’ in front
of ’pro’ in the filename).
Tip: You can abbreviate commands (and keywords) as long as they remain unambigiuous.
Thus, you can type .r for .RUN, but not .c for .COMPILE because this can be confused with
.CONTINUE. Procedure and function names, however, cannot be abbreviated.
Let us use the historic ’Hello world!’ routine as an example how to write IDL programs. Open
a file named hello1.pro with your favorite editor and enter the following three lines:
myname=’Martin’
print,’Hello ’,myname
end
Save the file and type .r hello1 at the IDL prompt. If you want to greet someone else, you will
have to modify the program and replace the assignment to the myname variable.
Let us now turn hello1.pro into a procedure which allows more flexibility. Copy the file as
hello.pro and change it to the following:
pro hello,myname
if (N_Elements(myname) eq 0) then $
myname=’Martin’
print,’Hello ’,myname
return
end
If you now type .r hello, you will only see % Compiled module: HELLO.. Enter hello,’Stefan’
to see the advantage of a procedure. If you supply no argument to hello, it will once again greet
Martin.
Note: A *.pro file can contain several procedures and functions together. In order to take
advantage of the automatic compilation (see next section) you must however have one file for each
routine that you are going to call directly, and the routine that bears the filename must be last in
the file.
Writing a function is just as easy: simply replace PRO by FUNCTION and return a value with the
RETURN statement. As an example, let us write a function that extracts the time of the day from
a date string:
function timeofday,date
if (n_elements(date) eq 0) then $
date = systime()
return,strmid(date,11,5)
end
2.9. AUTOMATIC COMPILATION
21
Try it out with print,timeofday() and print,timeofday(’Mon Jan 31 05:10 1990’).
2.9
Automatic Compilation
(From the online help) When a file is specified by typing only the filename at the IDL prompt,
IDL searches the current directory for filename.pro (where filename is the file specified) and then
for filename.sav. If no file is found in the current directory, IDL searches in the same way in
each directory specified by !PATH. If a file is found, IDL automatically compiles the contents and
executes any functions or procedures that have the same name as the file specified (excluding the
suffix).
In order to have this work properly, you should follow a few rules:
• You must name your file exactly as you name the procedure.
• While case does not matter in the procedure name, it is important to keep filenames all
lowercase (at least in Unix).
• Have one file for each procedure you may ever call directly.
• Always put the routine you are going to call at the end of the file.
• Always put functions at the beginning of the file.
If you are having trouble with IDL not finding the routines you wrote, make sure they are
listed in the !PATH system variable. Please read the online help on the EXPAND PATH procedure to
understand how IDL constructs its search path.
Tip: If you add a ’+’ in front of a directory name in a path string that you process with
EXPAND PATH, IDL will include all subdirectories which contain *.pro or *.sav files. WARNING:
EXPAND PATH cannot be used to get a directory hierarchy of data files!
2.10
Parameter Passing
As we have seen, parameters can be passed into and returned from procedures and functions via
(positional) arguments or (named) keywords. IDL automatically determines whether to pass a
parameter by value (if it is an expression or constant) or by reference (if it is a named variable).
Inside the procedure, you can manipulate all parameter values, but only those which were passed
by reference will be returned to the calling routine. Here are a few examples:
a = findgen(20)
testproc,a
testproc,5.*a
testproc,5.
testproc,a[10]
;
;
;
;
;
create some data
pass by reference
pass by value (expression)
pass by value (constant)
pass by value(!) (expression)
The last example is one possible source of errors: If you pass a portion of an array (by indexing it),
IDL regards it as an expression and passes it by value. This even holds if you pass the complete
array as a[*].
There is one special keyword named EXTRA. This can be regarded as a container that collects
all keywords which are passed to a routine but not used in the routine itself. You can then pass
them on to another subroutine which will take what it needs. Here is an example:
22
CHAPTER 2. IDL BASICS
pro teste1,a=a
print,’A=’,a
return
end
pro teste2,b=b,_EXTRA=e
print,’B,E=’,b,e
teste1,_EXTRA=e
return
end
pro testextra,_EXTRA=e
teste2,_EXTRA=e
return
end
If you call testextra,a=5,b=10, IDL will print B,E=10 { 5 }, A=5. The teste2 procedure ’sees’
the keywords as a=5,b=10. It recognizes b and prints it, but it does not ’know’ about a. Thus, a
is stored in the EXTRA container which is in fact an anonymous structure. This structure is then
passed on to teste1 which once again ’sees’ the keyword as a=5. If you add another keyword to
the call of testextra (e.g. testextra,a=5,b=10,c=15), it will just be ignored, because none of
the procedures recognizes a keyword named c. If you leave out a on the other hand, IDL will
complain: ’Variable is undefined: A’ (you will learn how to prevent this error message in section
3.1).
Note: EXTRA keywords are always passed by value. Since IDL version 5.2, there is also a
mechanism to pass ’anonymous’ keywords by reference. Consult the online help if you really need
this.
2.11
Loops
IDL knows three types of loops: FOR, WHILE, REPEAT UNTIL. A FOR loop can have an integer
(long) or float loop variable that is normally incremented by 1 except if you specify the increment
explicitely. It is important to understand that the data type of the initial value determines the
data type of the loop variable. Thus, if N has a value of 50000L, FOR i=0,N DO ... won’t work.
Luckily, this error is detected by IDL. However, consider the following example:
N=32765
p=0
for i=0,N+5 do begin
if (i gt 32760) then p=1
if p then print,i
endfor
You may try to figure out yourself why this does not work!
The following list summarizes the syntax for FOR, WHILE, and REPEAT UNTIL. Each is listed as
a one-line statement and in ’blocked’ form:
• FOR:
FOR start,end[,increment] DO statement
FOR start,end[,increment] DO BEGIN
2.12. HOW TO MAKE IDL FASTER
23
statement block
ENDFOR
• WHILE:
WHILE condition DO statement
WHILE condition DO BEGIN
statement block
ENDWHILE
• REPEAT UNTIL:
REPEAT statement UNTIL condition
REPEAT BEGIN
statement block
ENDREP UNTIL condition
2.12
How to make IDL faster
The most important difference between IDL and FORTRAN (77 at least) is that IDL is an array
oriented language and an interpreted language (’compilation’ of routines only compresses them into
a more readily usable form but does not produce a binary executable). This has two important
consequences: Loops are costly and loops are (often) unnecessary. Consider the following piece of
code:
a = findgen(20000)
for i=0L,N_Elements(a)-1 do $
if (a[i] gt 5000) then a[i] = 5000
This takes about 0.12 seconds on my Sun workstation (not too much maybe, but it becomes
noticeable if you have to do it 1000 times!).
A better way of achieving the same result is the use of the WHERE function that was introduced
in the last section:
a = findgen(20000)
ind = where(a gt 5000,count)
if (count gt 0) then $
a[ind] = 5000
This takes only 0.014 seconds, a factor of 10 difference! But that’s not all: real gurus know
about the ’<’ and ’>’ operators which limit values to the expression on the right of the operator.
Thus a < 5000 sets every value above 5000 to 5000 and leaves all others unchanged. The code
becomes a one-liner:
a = findgen(20000) < 5000
and executes in a mere 0.004 seconds, another factor 3 gain! (This example together with the code
that produces the timing results can be found in my course library as avoidloop.pro).
If you are in need for efficient computing methods, the comp.lang.idl-pvwave newsgroup is a
good place to ask. Some folks out there seem to have real fun in improving runtime (but don’t
send them your code of several thousand lines!).
Here are a few more tips that I found among the web resources which are listed in section 8.1:
24
CHAPTER 2. IDL BASICS
• Beware of the order in which things are computed! Research Systems give an example for
this: b = a*16./max(a) looks innocent, but it is much slower than b = 16./max(a)*a,
because in the first variant, max(a) has to be evaluated for each array element whereas it is
only computed once in the second example (for a 10000 element array, the time difference is
about a factor of 2).
• Try to replace IF statements in loops by logical expressions. Example:
for i=0L,(N-1) do if b[i] gt 0. then a[i]=a[i]+b[i]
should be replaced by
a = a + b*(b gt 0)
or in this case with
a = a + (b > 0)
.
• Sometimes loops can be avoided at the expense of memory and thus save time only for
smaller arrays (well, ’small’ can still be 10000 elements or so). One example for this is filling
a matrix with identical column vectors: The straightforward approach would be FOR i=0,n-1
DO A[*,i]=V. Better is to convert your vector into an array vector = Replicate(1, n) and
then multiply the two arrays element by element as array = V ## vector. The guru (Stein
Vidar Hagfors Haugan) way is to use REBIN for this:
array = rebin(reform(v,m,1,/overwrite),m,n,/sample).
• A very powerful tool in IDL is the HISTOGRAM function which can be used for much more
than its name suggests. There have been several astonishing examples provided by Stein
Vidar Hagfors Haugan in the idl-pvwave newsgroup.
Finally, a few words on efficient memory usage which may also affect speed:
• Use the temporary function if the lefthand-side variable is used exactly once on the right side
of an expression; this avoids an extra copy of the variable. Example: a = 12 * temporary(a)
+ b.
• Use the NO COPY keyword with functions like PTR NEW if you don’t need to keep an ’external’
instance of your data.
Chapter 3
Debugging
Even the best programmer will introduce a bug or two once a while, and spaghetti-coding scientists
will need debugging all the more. The best method for debugging is, of course, to prevent errors
in the first place. Often, this is accomplished by adhering to a few standard rules like checking the
validity of all arguments and keywords that can be passed into a procedure or function. Furthermore, code maintainance is greatly facilitated if you comment your code and put a header on top
of each procedure which describes what it is for and how it is used. I adapted a procedure I found
in the JHU/APL library that adds a standard header to a program file which you still have to fill
in though. The routine is called ADD TEMPLATE and can be found in my tools library. The header
produced by ADD TEMPLATE can be interpreted by the USAGE routine.
3.1
Argument and Keyword Checking
We have already seen examples for argument and keyword checking in the code snippets presented
above. Most often you will find one of two cases:
1. You must make sure that a procedure argument or keyword exists and has a reasonable
(default) value. This is always accomplished with the N ELEMENTS function which returns 0
for undefined variables. Some care has to be taken that you don’t overwrite the argument
or keyword variable thereby causing unexpected side-effects in the calling procedure. Thus,
a safe standard way of checking an argument would be:
IF (N_ELEMENTS(var) EQ 0) THEN $
tmpvar = 0L
$
; or 0. or ’’, etc.
ELSE $
tmpvar = var
Then you would of course work with tmpvar instead of var.
If you also need to make sure that you have only one element (or a scalar for that matter),
you should change the last statement to tmpvar = var[0].
2. You want to query a boolean keyword and set a flag according to its state. This is the
purpose of the KEYWORD SET function. Example:
psflag = keyword_set(ps)
25
26
CHAPTER 3. DEBUGGING
If you want to negate the value, you can do:
eraseflag = 1 - keyword_set(noerase)
Note: Do not use the NOT operator to negate a keyword. NOT reverses each bit, so NOT 0
becomes -1 and NOT 1 becomes -2.
For more information on this topic, consult David Fanning’s web pages (article Checking for
Keywords).
3.2
The HELP procedure
In case you don’t understand what is going on, HELP is usually a good place to start. HELP has
nothing to do with the online help system but displays diagnostic information on variables, files,
procedures and more. The standard way of calling HELP is:
HELP,var1[,var2,var3,...]
This will display the variable type and for scalars also its value. It even works for expressions,
so you can follow through a complicated formula by successively copying more and more complex
portions of it as argument to HELP.
Tip: If you need a variables type and dimension information within a program, use the SIZE
function (section 2.3).
Other useful keywords to HELP are /FILES, /STRUCTURES, /ROUTINES, and /SOURCE FILES.
The first returns a list of allocated file units, the second expands structures to show their tags.
/ROUTINES displays a list of compiled routines and their arguments, and /SOURCE FILES lists the
file path of all compiled modules. With the OUTPUT keyword you can read the HELP information
into a string array instead of printing it on the display (for an example see section 3.4). See the
online help on HELP for more information.
3.3
Run-control: STOP, .STEP, and .CONTINUE
In case of a program crash, IDL will tell you in which routine it stopped execution and at which
line. It is important to realize that you do not automatically return to the main level. This can be
done with the RETALL command, RETURN returns to the next higher level (if possible). But don’t
type RETALL too fast. The fact that you are still in the routine that probably caused the crash
allows you to diagnose the variable state (variables have local scope in IDL) and it may even allow
you to correct the error on the fly and resume operation afterwards (of course, you still have to
alter the program code to prevent it from crashing again). Example:
pro test
a=10*b
print,a
return
end
will crash because b is undefined. You can now enter b=1 at the command line and type .CONTINUE
and your program will finish gracefully. Alternatively you can use .STEP to proceed line by line or
.SKIP to skip over the next statement(s). Read the section on Executive Commands in the online
help for more information.
3.4. CATCHING ERRORS
27
The STOP procedure sets a breakpoint at which program execution stops just like in case of
an error. Insert STOP anywhere in your program files. You can then examine your variables, take
corrective action, and resume operation afterwards. IDL also provides a more powerful BREAKPOINT
procedure, but for me STOP always worked well enough.
Tip: Setting breakpoints and controlling the variable status is one good reason for using the
integrated development environment IDLDE.
3.4
Catching Errors
There are three mechanisms in IDL to react on runtime errors: ON ERROR, CATCH, and ON IOERROR.
CATCH superseeds ON ERROR, and is itself superseeded by ON IOERROR for input/output errors.
ON ERROR accepts a number from 0 to 3 as argument and only influences the subroutine level
at which the program is halted in case of an error:
0 stop in the routine that caused the error (default)
1 return to the main level
2 return to the calling procedure
3 return to procedure that established ON ERROR
If at all, you will probably use level 2 for well-tested subroutines where the error will be caused
by wrong usage rather than a bug.
The CATCH mechanism may be regarded as a shell in which the sensitive program part is
embedded. In case of an error, the program jumps to the line immediately following the CATCH
statement which must then take corrective action or quit the program. A typical code snippet will
look like this (taken from David Fanning’s example):
PRO something
; Error handling code.
Catch, theError
IF theError NE 0 THEN BEGIN
Catch, /Cancel
Help, /Last_Message, Output=theErrorMessage
FOR j=0,N_Elements(theErrorMessage)-1 DO BEGIN
Print, theErrorMessage[j]
ENDFOR
RETURN
ENDIF
; The code that causes the error.
Print, xxx
END
The first line in this procedure establishes the error handler which will be valid in this procedure and
every procedure that is called from here unless these procedures establish their own error handler.
The error handler is cancelled either by calling CATCH,/CANCEL or upon exit of the procedure. The
error handler begins with IF theError NE 0. Since theError is automatically initialized with 0,
the error handler is skipped the first time the program runs through and IDL jumps to the ’normal’
portion of the procedure. In case of an error, theError will be loaded with a non-zero number
and IDL jumps back to the line following the CATCH statement. This is how the error handler is
executed. As it is done in the example, you should always cancel the error handler first, otherwise
you could create an infinite loop (namely if anything goes wrong within your error handler).
Instead of copying the above section for printing out an error message, you can use David’s
ERROR MESSAGE function which will display a dialog box on a window device and print the message
28
CHAPTER 3. DEBUGGING
in the IDL window if the current device is e.g. a postscript file.
While CATCH reacts on all errors that would otherwise cause an IDL program to stop, ON IOERROR
only handles errors associated with input and output operations (this includes format errors in the
STRING function though). ON IOERROR needs one argument which is the name of a label (similar
to GOTO). Here is an example:
pro ioerror
ON_IOERROR,BadFormatLbl
print,string(!PI,format=’I3’)
return
BadFormatLbl:
print,’tough luck!’
end
; missing parantheses
Tip: When using ON IOERROR for file input/output, you should close the file in your error
handler. Use FREE LUN instead of CLOSE in order to free the file pointer variable.
There is extensive documentation on ’Controlling Errors’ in the online help. Take a look at the
!ERROR STATE system variable (new in IDL 5.1) and the MESSAGE and DIALOG MESSAGE procedures.
3.5
Math Errors
Unlike other programming languages, IDL does not consider math errors as ’fatal’ and continues
with program execution if it encounters for example a division by zero (the ’value’ of 1./0. is a
special IEEE representation named ’Inf’ which leads to a program termination if used as array
index or in another mathematical expression). Normally, IDL accumulates math errors until it
reenters the command line, then prints out a summary. In order to provide better control over
where a math error occurs, IDL has a system variable !EXCEPT which has three possible values:
0 do not report math exceptions at all
1 report math exceptions upon reentering the command line (default)
2 report math exceptions immediately
You can manually check the status of math errors with the CHECK MATH function. This will also
reset the math error status to zero. Usually, you will set !EXCEPT to zero when operating with
CHECK MATH as demonstrated in the following example:
OldExcept = !EXCEPT
!EXCEPT = 0
dum = CHECK_MATH(/PRINT) ; report previous errors
REPEAT BEGIN
READ,num,prompt=’Enter a number: ’
PRINT,’log(’+strtrim(num,2)+’)=’,ALOG10(num)
ENDREP UNTIL CHECK_MATH EQ 0
!EXCEPT = OldExcept
For those who want to make double sure that they don’t calculate garbage results, IDL also
provides a function named INFINITE. This can be used to check the validity of an expression (it
does not prevent the issuing of a math error though).
Chapter 4
Basic Plotting
Congratulations! You have crossed the desert and may now enjoy the colorful oasis of IDL’s
plotting routines. As in real life, the most colorful animals (devices) can be most dangerous. So,
before we enter the oasis, let’s tame them.
4.1
IDL devices
Everything you plot in IDL1 is output to some device. Generally, IDL supports devices with one
of three visual depths: 1 (i.e. black and white), 8 (meaning 256 colors available), and 24 bits per
pixel. Common Unix systems also know 16 and 32 bit visual depth. The former is not supported
by IDL (although it behaves almost like an 8 bit display in IDL), the latter is at heart no deeper
than 24 bit and can usually be treated as such (the extra 8 bits are used for storing an ’opacity’
value and sometimes named ’alpha channel’).
Tip: You can find out about the capabilities of your X Windows terminal with the Unix command xdpyinfo. Information on the current IDL device is returned with HELP,/DEVICE at the
command line.
You can change the current plotting device with the SET PLOT procedure, and you can tailor
the device (or query its capabilities) with the DEVICE procedure. More on this can be found in the
section on postscript (section 7) and in the online help.
The most important device parameters (including its name) are stored in the !D system variable.
In Unix, the screen device is named ’X’, in Windows it is ’WIN’, and for the Macintosh it is
’MAC’. Postscript output is created by the ’PS’ device, and there are others for direct printer
output: ’PRINTER’, ’PCL’, and ’LJ’. Just for completeness I also list the so called ’Z-buffer’
device (named ’Z’) and the ’NULL’ device which sends everything into Nirwana.
Getting different devices to work properly and print the output in the correct size and orientation at the right position can be quite tricky sometimes. In this book, we restrict ourselves to
screen and postscript output which are most common and best supported.
4.2
IDL and colors
To gain a full understanding of color schemes, their implementation on various computer systems
and the intricacies of color printing processes requires much more than a 1-day IDL course. Once
1 We are talking about the so-called Direct Graphics here. The other model, Object Graphics, works differently
but goes beyond this script and its author’s knowledge.
29
30
CHAPTER 4. BASIC PLOTTING
again thanks to David Fanning, life with IDL has become bearable, so I will restrict myself to a
few words about the general concept and then introduce some tools that will help you in your daily
work with IDL. The following section contains some more in-depth information for those who are
interested.
There are two principal color modes (or visual classes) available in IDL: indexed color and direct
color. So far, most Unix systems still operate with 8 bit visual depth and a shared color table
which automatically implies that the visual class is indexed. However, more and more systems
support higher visual depths, so it will become more and more important to write code that can
run on both types of system.
A computer display generates a color pixel by adding certain amounts of red, green, and blue
light together. The amount of red, green, and blue is specified as a triple of 3 bytes (hence, 24 bit).
This is even true for displays with 8 bit or 16 bit visual depth, although these do not allow direct
access to all available combinations of red, green, and blue at the same time. You can display any
color (out of 16.7 million) on these devices, but not more than 256 (or 65536) simultaneously. In the
indexed color mode, each RGB (red-green-blue) triple is loaded into a specified position in the 256
(or 65536) element color table and is then accessed via an index into this table. Hence, you can for
example store a yellow triple ([255,255,0]) at index 0, a red triple ([255,0,0]) at index 1, and a black
([0,0,0]) triple at index 2. PLOT,DATA,COLOR=0 will then plot a yellow line, PLOT,DATA,COLOR=1
will plot a red line, etc.. In the direct color model (i.e. on 24 bit systems) you can access all
available colors simultaneously, thus you specify the RGB triple directly — well, almost directly,
because IDL expects a single value for the COLOR keyword. The COLOR value becomes a long word
constructed as 216 · blue + 28 · green + red: PLOT,DATA,COLOR=’00FFFF’x plots a yellow curve.
Note: In version 5.2 of IDL you actually have to force the color value to be a long integer
(’00FFFF’xL). This bug was fixed in version 5.2.1.
To shorten things here, let me tell you how you can use the same plotting colors on both 8 bit
and 24 bit devices and even access colors by name: First, you need to run Liam Gumley’s SETCOLOR
tool with the option DECOMPOSED=0 in the startup file (this essentially issues (and replaces) the
DEVICE,TRUE=24 command which we inserted into the startup file at the beginning of this book).
Then, within your plotting routine, write the following two lines:
Colors = GETCOLOR(/LOAD)
PLOT,Data,COLOR=Colors.red
This makes use of David Fanning’s GETCOLOR function which defines the 16 McIdas colors
(black, magenta, cyan, yellow, green, red, blue, navy, gold, pink, aqua, orchid, gray, sky, beige,
and white) and returns a structure with the tag names corresponding to the color names. The tag
values are either byte values for the indexed color mode or long integers for direct color (with IDL
versions before 5.2 you needed to add a /TRUE keyword on 24 bit systems so you could not write
truely device-independent code). If you forgot the names of these colors, just call GETCOLOR with
the /NAMES keyword and it will return a string array with the 16 names.
For the display of filled contours or false color images, you probably want a series of colors e.g.
changing from blue to red or picked from the rainbow. This can be done with the LOADCT procedure.
This procedure accepts BOTTOM and NCOLORS as keywords, so you can shrink the complete table of
256 colors and squeeze it into a smaller range. For immediate control over the color values IDL
provides the TVLCT procedure which loads R, G, and B vectors of arbitrary length into the current
color table optionally starting at a specified position. David provides some examples for this on
his web pages and we will see an example in section 5.2. You may also want to check out the IDL
widget functions XPALETTE and XLOADCT (although I couldn’t get them to work properly on a 32
bit true color Linux system).
Note: There is one fundamental difference between 8 bit and 24 bit (true color) visual depth
devices: When you make changes in the color table, they get reflected immediately on 8 bit systems
4.3. MORE ON COLORS
31
whereas they show up on 24 bit systems only after redrawing the window contents.
The correct way to display images depends on the device type and the image class (e.g. GIF
is an 8 bit format whereas JPEG is a true color 24 bit format). This topic will be addressed in
section 5.5.
4.3
More on Colors
For those who always scream for more, let me go into some more detail about IDL’s color handling
in this section. The material of this section is still somewhat unorganized since I only recently had
a chance to try working with a 24 bit system. A wealth of information beyond this section can be
found on David Fanning’s web page and in his book ’IDL Programming Techniques’.
***
***
***
***
device,decomposed keyword
device,get_visual_name=vn and get_visual_depth=vd keywords (IDL 5.2)
color translation
the ’flickering’ of 8 bit displays and the ’netscape’ problem
(netscape -ncols NN) and window,colors=NN or -NN
*** alternative color models (CMYK, HSV, HSB) You can search the internet for
’hue saturation brightness’ and you will find several pages explaining the
details (example: http://www.ricklineback.com/definit.htm or
http://www.zianet.com/jpierce/Panel.html).
[from an email David sent me recently:] A ’true’ True-Color visual class cannot be changed. It
is called a ’static’ or ’non-writable’ color table. That is, the red vectors values go from 0 to 255,
as do the green and blue. There is no notion of loading of values into the color table vectors since
all 16.7 million colors are already available. A Direct-Color visual is writable or dynamic. You can
load new values into the color table (like you can for a Pseudo-Color color table). But the colors
are still expressed as RGB triples rather than as color table indices.
In IDL there is no need to know, really, if you have a True-Color or Direct-Color visual. Color
tables are pretty much handled at the software level, so the fact that a True-Color visual is not
writable doesn’t really cause anyone any problems. The difference is that if you get a Direct-Color
visual set up properly (and please don’t ask me how. I don’t know, and I’ve only seen it set up
properly once, and that by a guy who was a color genus) you have the best of both worlds. You
have 24-bit color *and* your image colors change automatically the way they do in a PsuedoColor
visual class when you load new colors into the color table. The real problem, I think, is that there
is no DirectColor ’standard’, so each vendor implements things a bit differently. It can be a real
nightmare in the field.
4.4
The PLOT command
I usually find the best way to learn about computer issues is trying them out. This is especially
true with IDL’s PLOT command which has more options than I can ever hope to remember. I
prepared a little program called plotdemo.pro which you can find in the course directory. This
program prepares some funky sine curve as data:
x = findgen(73)/18.*!PI
; 720 degrees in 10 deg steps
y = 50.* ( sin(x)*cos(2*x)+1 )
and then successively calls little subroutines which create different versions of the same plot.
32
CHAPTER 4. BASIC PLOTTING
Tip: !PI is a system variable with the value of π in single precision. Use !DPI for double
precision, but be aware that PLOT operates only on single precision variables (double arguments are
automatically converted). There is also a system variable named !DTOR which stands for ’deg to
rad’ and equals !PI/180..
In between each plot, the user is asked to hit the return key. This is accomplished by the two
lines:
ch = ’’
; character variable for keypress
read,ch,prompt=’Press Enter to continue...’
(This is one of the occasions where data type matters. Although read,ch would also work with an
uninitialized variable you would then have to enter a number in order to quit the input request.)
The first example, plot1 is extremely simple: it just calls PLOT with one argument (the y
values):
pro plot1,data
plot,data
return
end
The x values are automatically generated as index into the y array (in this case ranging from 0 to
72). IDL automatically rounds the axis range and (usually) puts nicely formatted numbers as tick
labels. If you have not messed around with the default color tables in your startup file, PLOT will
produce a white curve on a black background (if you produce this plot on the postscript device
this will automatically be reversed, see chapter 7). The individual data points are connected with
a solid line.
The next example, plot2 uses the GETCOLOR function to control the plot color (i.e. the color
of the axes and the curve). Furthermore, we add a title centered on top of the plot and axis labels
for x and y. Finally, we also attempt some formatting of the x axis by explicitely giving it a RANGE
and telling it to divide each major tick interval into two parts (xminor=2) and to extend the major
tick marks across the plot (xticklen=1).
pro plot2,x,y
c = getcolor(/LOAD)
plot,x,y,color=c.gold,title=’My second plot’, $
ytitle=’Y Axis’, $
xtitle=’X Axis’,xrange=[0.,4*!PI],xminor=2,xticklen=1
return
end
Note that the x axis range is not strictly adhered to, but IDL expands 4π to a round number,
in this case 14. You need to set the XSTYLE keyword to 1 in order to force exact axis ranges as
we will see in the next example. By the way: here we pass two arguments to PLOT, x and y — it
works just as you would expect.
Tip: Many axis control keywords to PLOT can also be specified without the preceeding X, Y, or
Z. They then apply to all axes together (e.g. ticklen=1 will produce a grid plot).
plot3 adds more controls to the axis formatting and shows you how to use plot symbols and
lines together. Here is the code, we will go through it below:
pro plot3,x,y
c = getcolor(/LOAD)
plot,x*180/!PI,y,color=c.red,title=’My third plot’, $
4.4. THE PLOT COMMAND
ystyle=2,ytitle=’Y Axis’, $
xtitle=’X Axis [deg]’,xstyle=1,xticks=4,xminor=3,xticklen=-0.02,
xthick=2,ythick=2,charsize=2.,charthick=2,thick=3,psym=-5
return
33
$
end
First of all, note that we convert the x values back to degrees for this plot. This is to show you
that the x and y argument of PLOT can be any expression, not just a vector variable (it must be a
vector, though — use HELP to find out if in doubt).
In this example, we have used two different values of the [XYZ]STYLE keyword. The value for
this keyword can be any combination of the following binary flags (although some of them don’t
make sense together):
1 Force exact axis range
2 Expand axis range (by 5% in each direction)
4 Supress axis entirely
8 Plot axis only on one side
16 Do not automatically set Ymin to zero
Example: You can create a plot with no y axis but exact range by setting YSTYLE to 5.
XTICKS=4 is somewhat misleading: it tells IDL to use 5 (!) tick marks on the x axis. Better to
think of this keyword as defining the number of intervals between tick marks. A negative value of
[XYZ]TICKLEN causes the tick marks to point outside — normally, IDL produces a box-style plot.
The [XYZ]THICK keywords make the axes appear less faint, likewise does THICK=3 cause the curve
to be drawn 3 pixels wide.
Note: It is a little annoying that the line thickness is specified in device coordinates, because
this leads to very faint lines in default postscript output. David Fanning recommends to use a
scaling factor of 2.5 between screen and postscript output, i.e. you can write something like
THICK=n*(1+(!D.NAME EQ ’PS’))
.
CHARSIZE and CHARTHICK are pretty straightforward — except that CHARSIZE is measured relative to the system variable !P.CHARSIZE and [XYZ]CHARSIZE are measured relative to CHARSIZE.
Furthermore IDL automatically decreases the character size by a factor of 0.62 if you put more
than 3 plot panels in a row or column (see section 4.7). These ’features’ often lead to unexpected
results.
PSYM determines which plotting symbol shall be used. You can find a list of values in the online
help. A negative value means ’plot the symbols and connect them with lines’ where the linestyle
can be set via the LINESTYLE keyword. You can control the symbol size with the SYMSIZE keyword.
Tip: I prefer to use my little SYM function to replace the original symbols because I don’t like
the way they are ordered. You can use the SHOWSYM procedure to produce a symbol bar which you
can attach to your monitor for reference (type .r sym then showsym, optionally with the keyword
/PS to produce a postscript file named symbols.ps).
The next example shows how to achieve different colors for the axes and the data (which is the
same mechanism as overlaying several curves on one plot) and it demonstrates even tighter control
over the axis labels.
pro plot4,x,y
c = getcolor(/LOAD)
xtl = lindgen(5)*180
xtls = strtrim(xtl,2)+’!Uo!N’
34
CHAPTER 4. BASIC PLOTTING
tmpx = x*180/!PI
plot,tmpx,y,/NODATA,color=c.white,title=’The next plot’, $
ystyle=2,ytitle=’Y Axis’, $
xtitle=’X Axis’,xstyle=1,xticks=N_Elements(xtl)-1,xtickv=xtl, $
xtickname=xtls,xminor=3, $
xthick=2,ythick=2,charsize=3.,xcharsize=0.6,ycharsize=0.9,charthick=2
oplot,tmpx,y,line=2,color=c.blue,thick=2
oplot,tmpx,y,psym=sym(1),color=c.cyan,symsize=2
return
end
The /NODATA keyword tells PLOT not to plot the data but only to establish a coordinate system
and to draw the axes. The data can then be inserted into the plot with the OPLOT procedure. Here,
we use two calls to OPLOT because we want even the symbols and lines to have different colors.
Tip: You can get a completely empty plot with PLOT, x, y, /NODATA, XSTYLE=5, YSTYLE=5.
This command only sets up the coordinate system with exact axis ranges but produces no output.
We produce the x axis labels with xtl = lindgen(5)*180 which is equivalent to xtl = [ 0L,
180L, 360L, 540L, 720L]. The number of x tickmarks is once again set with XTICKS, and this
time we also specify the tick mark values with XTICKV. The XTICKNAME keyword is not necessary
in this example, but we can use it to add degree symbols to the tick labels (the cryptic string
’!Uo!N’ causes a superscript, prints out an ’o’ and returns to the normal character size; for more
information on character formatting, refer to ’Hershey [fonts]’ in the online help). The same effect
can be achieved with the XTICKFORMAT keyword instead: XTICKFORMAT = ’(i,"!Uo!N")’.
The final example of plotdemo.pro gets really fancy: I will show you how to add a second
y axis to the plot and how to use an independent variable for the coloring of your plot symbols.
Furthermore, you can see how to suppress axis tick mark labels and you can practice what you
learned about colors in the previous sections.
pro plot5,x,y,z
; retrieve current color table for later restore
TVLCT,rold,gold,bold,/GET
; load colortable BLUE/GREEN/RED/YELLOW but leave room
; for drawing colors at the top
loadct,4,NCOLORS=(!D.N_COLORS<255)-18
; load the (McIdas) drawing colors
c = getcolor(/LOAD)
; make sure the top color index is white
TVLCT,[255],[255],[255],(!D.N_COLORS<255)-1
; store "plot" environment for later restore
psave = !P
; exchange background and drawing color
; (so the background will be white)
!P.COLOR=0 & !P.BACKGROUND=(!D.N_COLORS<255)-1
4.4. THE PLOT COMMAND
35
; convert x from radians to deg
tmpx = x*180/!PI
; construct a color vector from the z data
; (BYTSCL squeezes the data range into byte range)
c_color = BYTSCL(z,max=MAX(z),top=(!D.N_COLORS<255)-28) + 10
; Establish coordinates and draw axes -- leave out right y axis
plot,tmpx,y,/NODATA,color=c.black,title=’A fancy plot’, $
ystyle=2+8,ytitle=’’,yminor=1,ytickformat=’(A1)’,yticks=1, $
xtitle=’X Axis’,xstyle=1,xticks=4, $
xtickformat=’(i,"!Uo!N")’,xminor=3, $
xthick=2,ythick=2,charsize=2.0,xcharsize=0.7,ycharsize=0.7,charthick=2
; overlay data as solid black line
oplot,tmpx,y,line=0,color=c.black,thick=2
; draw symbols with color acording to z data
plots,tmpx,y,psym=sym(1),color=c_color,symsize=1.5
; add second y axis for display of weighting curve (z)
; (Don’t forget /SAVE, otherwise the new coordinate transformation
; will not be used!)
axis,yaxis=1,yrange=[0.,MAX(z)],ystyle=2,ytitle=’weight’, $
color=c.pink,/SAVE
; overlay the weighting curve
oplot,tmpx,z,color=c.pink,line=1,thick=2
; hold breath until user admired the plot
ch = ’’
read,ch,prompt=’Press Enter to continue...’
; restore "plot" environment and color table
!P = psave
TVLCT,rold,gold,bold
return
; To suppress y axis entirely, set YSTYLE to 4. You can then
; manually draw a line with:
; PLOTS,[!X.WINDOW[0],!X.WINDOW[0]],[!Y.WINDOW[0],!Y.WINDOW[1]], $
;
/NORM
end
If you are horrified by the expectation to write 4 or 5 line PLOT commands every time you want
to visualize your data, you can be helped. Almost all of the keywords to PLOT can be stored in the
!X, !Y, and !Z system variables or the !P system variable, which means they will be valid for all
subsequent plots (unless they are overwritten by local keywords). So you can write !P.THICK=3 &
36
CHAPTER 4. BASIC PLOTTING
!X.MINOR=2 & PLOT,X,Y instead of PLOT,X,Y,THICK=2,XMINOR=2.
Several people have written a LEGEND routine to add a symbol legend to a plot. If you don’t
like mine, try one of the internet resources listed in section 8.1.
Error bars can be added to a plot with the ERRPLOT procedure or with OPLOTERR. See the online
help for more information. An example for a plot with error bars will be given in section 6.1 on
page 56.
4.5
Non-linear Axes
The most common type of non-linear axes are certainly logarithmic axes. In principle, these can
easily be generated in IDL by setting the /[XYZ]LOG keyword as shown in the following example:
x=findgen(10)-3
plot,x,exp(x),/YLOG
However, there is not too much control over how your tick mark labels are spaced for logarithmic
axes which may not be an issue for working plots, but probably comes up as soon as you want to
publish your results. A simple change in the axis range reduces the acceptable output from the
first example to a miserable graph:
x=findgen(10)/10.-3
plot,x,exp(x),/YLOG
There is way too much room around the curve and you would probably admit that it would be nice
to have tick mark labels also at 2’s and 5’s at least. IDL does not provide these directly (because
it never labels minor tick marks), but with the various keywords to PLOT you learned about in the
previous section, you can surely produce them. I wrote a little helper routine (loglevels.pro)
that returns ’properly’ spaced tick mark values for arbitrary logarithmic axes. You can use it like
this:
X = findgen(101)/10.
Y = X > .1
; (X and Y must be defined)
mind = MIN(Y,MAX=maxd)
Lblv = LOGLEVELS([mind,maxd])
; <=====
PLOT,X,Y,/YLOG,YTICKFORMAT=’(A1)’
AXLABEL,Lblv
You pass LOGLEVELS the desired range of the axis, and it returns a vector containing the label
values (you can fine-tune its behaviour with the /FINE and COARSE keywords, see documentation in
file header). The task is now to properly place these labels on the plot. This can be done with my
AXLABEL procedure which ensures that the labels are placed properly regardless of the current
output device and the character size you choose. If you think about it a little, you will realize
that this is not a trivial task, because to print labels on the y axis, you also need to know the x
position. And while your y values are in DATA coordinates, it is not a good idea to specify the x
position in DATA coordinates as well. If you change your x axis range, you would move your labels
around. Instead you need to specify the x position in a NORMALized coordinate system. I won’t go
into detail here and only briefly define the three types of coordinates you can use in IDL. If you
want to know more, take a look at the source code for AXLABEL and consult the online help.
• The DATA system is the world according to your data. It is established only after a PLOT (or
similar) command and the default for practically all routines that put data on your screen.
4.5. NON-LINEAR AXES
37
• NORMAL is a device-independent linear system where both x and y always extend from 0 to 1
across the graphics window or the (printable) portion of the page. It is always a good idea
to use this coordinate system to place labels on a plot because it ensures that you don’t have
to rewrite your code every time you change your output device or resize your window.
• DEVICE coordinates are simply the number of pixels in x and y direction. The absolute
position and size of an object specified in DEVICE coordinates depends on the resolution
of the device (X terminals usually feature 40 pixels per cm while the postscript device is
equipped with astonishing 1000 pixels per cm; you can retrieve the resolution of the current
device from !D.X PX CM and !D.Y PX CM).
Now let me present you another example of non-linear axes. This code produces what chemists
call an ’Arrhenius’ plot. They use it to plot the temperature dependence of reaction rate constants.
Here is the source code of arrhenius.pro which you can also find in the course directory:
pro arrhenius,t,k,_EXTRA=e
; Create data if nothing was passed
if (n_elements(t) lt 2) then begin
t=findgen(41)*5+100
; create temperatures from 100 to 300 K
k=1.8e-12*exp(-2000./t) ; some rate constant expression
xtickval = t[[0,10,20,30,40]]
endif
if (n_elements(xtickval) eq 0) then $
xtickval = [ t[0], t[N_Elements(t)-1] ]
; Compute inverse temperature
t1=1000./t
; Do the plot
plot,t1,k,/ylog,xstyle=9,xtitle=’1000/T’,xrange=[3.333,10],
xminor=1,ytitle=’k’,position=[0.25,0.2,0.85,0.85], $
ytickformat=’exponent’ ,_EXTRA=e
$
axis,xaxis=1,xticks=4,xtickv=1000./xtickval,
$
xtickname=string(xtickval,format=’(i3)’),xtitle=’T [K]’
return
end
If you look at the PLOT command, you will see mostly options you already know by now. To
recapitulate: XSTYLE=9 draws the x axis on only one side (bottom) and forces an exact range. New
is the POSITION keyword which allows you to place your plot at a specified position in the graphics
window. The POSITION value is a 4-element vector with the entries [x 0 , y0 , x1 , y1 ] and the values
are normal coordinates. You will learn more about positioning of graphs in section 4.7.
The other new keyword is YTICKFORMAT which allows you to specify a (FORTRAN) format
string or pass the name of a function which is then used to format each axis label individually.
For the ARRHENIUS procedure I selected to output the y tickmark labels as exponent strings (e.g.
1x103 ). The EXPONENT function has been written by Stein Vidar Hagfors Haugan.
38
CHAPTER 4. BASIC PLOTTING
After the PLOT command, a second x axis is added on top of the plot which marks some of the
temperatures in the linear scale. You can use the ARRHENIUS procedure as is to display your own
data or you can just consider it as an example.
4.6
Missing Data
To make data analysis more interesting, scientists invented so-called ’missing data’, i.e. they
manipulate their instruments in order to produce gaps in an otherwise continous data stream.
Often, these missing data are coded with special values (usually something like −999 or so). The
IDL PLOT command can deal with missing data elegantly: PLOT,X,Y,MIN VALUE=0. will only plot
the data that are above zero (likewise there is a MAX VALUE keyword of course). The lines connecting
the data points are interrupted when a missing value is encountered. Here is an example:
x = findgen(20)
y = x
y[[4,6,12]] = -999.
PLOT,X,Y,MIN_VALUE=0.,PSYM=-SYM(1)
MIN VALUE and MAX VALUE refer only to the y axis, so what do you do if you have missing x
values? Answer: Use the WHERE function to get the indices of the missing x values and replace the
corresponding y values with the missing value code (well, a copy that is):
tmpy = y
ind = WHERE(x EQ -999.)
; careful with DOUBLE and FLOAT here!
if (ind[0] ge 0) then $
tmpy[ind] = -999.
PLOT,x,tmpy,MIN_VALUE=-998.
Tip: The WHERE function must also be used if you want to compute averages of data that
contains missing values. Here you would compute the index of all valid data points instead:
ind = WHERE(data NE -999.)
if (ind[0] ge 0) then $
average = total(data[ind])/N_Elements(ind) $
else $
average = -999.
; mark average as missing
A more difficult problem arises when the data gaps have not been filled with some special
value but have simply been omitted from the file. Here you have to break the data into segments
yourself and plot each segment individually. To accomplish this, you can use the SHIFT function
which allows you to rotate the array elements (in this case by 1) and then compute the delta
between two consecutive x values (remember: loops should be avoided). Here is a piece of code
that has been used to compare station data with model results:
MAXDELTA = 1.
; maximum allowed gap between x values
PLOT,x,y,/NODATA,YSTYLE=2
deltax = x - shift(x,1)
gapind = WHERE( deltax GT MAXDELTA )
if (gapind[0] lt 0) then begin ; no large gaps
OPLOT,x,y,PSYM=-SYM(1)
endif else begin
; break into segments
gapind = [ 0, gapind, N_Elements(x) ]
4.7. MULTIPLE PANELS ON A PAGE
39
for i=0L,N_Elements(gapind)-2 do $
OPLOT,x[gapind[i]:gapind[i+1]-1],y[gapind[i]:gapind[i+1]-1], $
PSYM=-SYM(1)
endelse
4.7
Multiple panels on a page
The most straightforward way to place several plots in one window or on one page is to use the
!P.MULTI system variable. This is a 5-element long vector with the following meaning for each
index:
1. Number of panels left to plot before the screen is erased
2. Number of columns on the page
3. Number of rows on the page
4. Number of plots stacked in the z direction (only 3-D plots)
5. Flag to fill rows first (0) or columns first (1)
Usually, you simply initialize !P.MULTI as !P.MULTI=[0,ncols,nrows] then you produce your
ncols × nrows plots just as if they were each on one page. To reset IDL to the normal 1-lotper-page mode, type !P.MULTI=0. You can influence the page margins with the !X.OMARGIN and
!Y.OMARGIN system variables (they are in so-called character units — just try it out until you get
satisfactory results) and you can change the spacing between the plots with the !X.MARGIN and
!Y.MARGIN variables (many graphics commands also accept a [XY]MARGIN keyword). To translate
character units into device units, look at the system variables !D.X CH SIZE and !D.Y CH SIZE.
Tip: To clear a page with less than ncols × nrows panels, set !P.MULTI[0] = 0. This will
erase the page with the next plot. If you want to prevent a page to be cleared but nevertheless start
at the top left corner, you can set !P.MULTI=ncols*nrows manually.
Note: To place more than one map on a page, you must use the /ADVANCE keyword to MAP SET.
An alternative way to position a plot in the window is the use of the POSITION keyword or the
!P.POSITION system variable. This is a 4-element vector with [x 0 , y0 , x1 , y1 ] in normal coordinates.
The POSITION value determines the size and position of the plot area itself, i.e. not counting the
tick mark and axis labels. So, POSITION=[0,0,1,1] will place the axis right on the edges of the
window. To place more than one panel on a page, you can supply a /NOERASE keyword to all
plotting commands. To clear a page, call ERASE.
While !P.MULTI is easier to use, it gives you less control over the exact plot position. There
are some tools available to assist you finding the correct values for the POSITION keyword:
• David Fanning wrote an ASPECT function. You can use it like: PLOT, x, y, POSITION =
ASPECT( height/width [,MARGIN=m] ). This function will always center your plot on the
page and it does not honor the !P.MULTI variable.
• Liam Gumley wrote a set of ’Frame tools’ which also have animation capabilities. However,
I have never used them, so I cannot tell how they work.
40
CHAPTER 4. BASIC PLOTTING
• My MULTIPANEL procedure tries to combine the easiness of !P.MULTI with the virtue of normal
coordinates in the POSITION keyword. You can call MULTIPANEL, nplots or MULTIPANEL,
ROWS=r, COLS=c to initialize a multipanel plot (and there are MARGIN and OMARGIN options
to control the size of each panel. The position of the next plot to be made is returned via
the POSITION keyword. With /ADVANCE you move to the next panel, and with /OFF you turn
the multipanel environment off again. All PLOT commands must have the /NOERASE keyword
turned on and use the POSITION keyword with the value returned from MULTIPANEL. Use
USAGE to find out more about MULTIPANEL.
Chapter 5
Map Plots, Images, Contours and
3D
5.1
How to draw a map
In order to produce a map with IDL, you must first establish a map coordinate system which is
done with the MAP SET command. The general syntax of MAP SET is
MAP_SET [,centerlat,centerlon,rotate], [/projection_keyword], [limit=...], $
[other_keywords]
The standard projection is cylindrical, and the map is normally centered on 0,0. To achieve an
undistorted map, use the /ISOTROPIC keyword, and to restrict the map to an area of the globe,
use LIMIT. The LIMIT keyword needs a 4-element vector with [lat 0 , lon0 , lat1 , lon1 ] as value. Be
sure to set the center longitude to a value inside the LIMIT, or you will see all sorts of undesired
results! Normally, the map extends from −180o to 180o . To plot it from 0o to 360o , you need to
type MAP SET, 0, 180, LIMIT=[-90,0,90,360]. Other keywords include CONTINENTS and GRID
which you can use to overlay continent outlines or a grid right away (however, I usually use the
seperate procedures MAP CONTINENTS and MAP GRID for this purpose). For the myriad of projections
available, consult the online help on ’Map projections’.
Note: To place more than one map on a page, you must use the /ADVANCE keyword to MAP SET.
In order to place data on your map, you need to use OPLOT instead of PLOT and the OVERPLOT
keyword with other graphics commands. Here is a little example procedure mapdemo.pro which
also demonstrates the use of MAP CONTINENTS and MAP GRID. As an excercise you may try to find
out the values of the lons and lats vector before they are plotted.
pro mapdemo
; example to plot data on a map
; create a pseudo ship cruise
lons = [210-findgen(5)*6,fltarr(5)+180.,180.-findgen(5)*6]
lats = [40.-4.8*findgen(5),16-findgen(5)*6,(-14.)-findgen(5)*2.5]
c = getcolor(/LOAD)
41
42
CHAPTER 5. MAP PLOTS, IMAGES, CONTOURS AND 3D
; set up the map and plot continents and grid
map_set,0,180,limit=[-70,0,70,360],/ISOTROPIC,color=c.gold
map_continents,/FILL,color=c.green
map_grid,linestyle=1,color=c.blue,label=1, $
latlab=5,lats=0,latdel=15, $
lons=findgen(9)*45., $
lonnames=[’ ’,’45’,’90’,’135’,’ ’,’-135’,’-90’,’-45’,’0’]
; overlay data
OPLOT,lons,lats,color=c.red,psym=-sym(1)
; label soundings
XYOUTS,lons+3,lats-3,strtrim(indgen(15)+1,2),color=c.red,
align=0.,charsize=0.6
$
return
end
The latitude grid lines are placed at longitude 5o , start at the equator and are distributed at
15 intervals. The longitude grid lines are placed every 45o . The LONNAMES keyword (together with
LONS) avoids a conflict between the zero degree longitude and zero degree latitude label at (nearly)
the same place and also hides the label at 180o which would interfere with the ship cruise.
Note: You can generally specify longitudes modulo 360. However, for contour plots and images
you must make sure to specify them monotonically increasing (see below).
Tip: You can use the LONNAMES and LATNAMES keywords to MAP GRID in order to add a degree
symbol (’ !Uo!N’; and optionally an ’E’, ’W’, ’N’, or ’S’ to the labels). However, it may be easier
to draw the map labels with XYOUTS in this case. You can also try my MAP LABELS routine which
will format the labels and return the position vectors to use with XYOUTS.
The following sections tell you how to display contour plots and images. In order to overlay
them with maps, you will generally proceed as follows:
o
• Filled Contour Plots:
map_set,...
CONTOUR,...,/FILL,/OVERPLOT
map_continents,... ; don’t use /FILL unless you only want the oceans
map_grid,...
• Line Contour Plots
map_set,...
map_continents,... ; /FILL looks nice here
map_grid,...
CONTOUR,...,/OVERPLOT
• Images (only works with regular images on cylindrical projection):
map_set,...,/NOBORDER
position = [ !X.window[0],!Y.window[0],!X.window[1],!Y.window[1] ]
TVIMAGE,image,position=position
map_continents,... ; don’t use /FILL unless you only want the oceans
map_grid,...
5.2. CONTOURS
43
Liam Gumley has written some tools to overlay satellite images onto maps of arbitrary projection. You can also adjust your map to the satellite image with the SATELLITE projection keyword
to MAP SET (see section 5.5).
5.2
Contours
IDL’s CONTOUR procedure is quite powerful but also has some ’features’ that can cause a headache
occasionally. Not all data sets are suited to be displayed as a contour plot, e.g. aircraft data
are often so sparse that you will not get any meaningful results unless you massage your data
and extrapolate them. Fortunately, atmospheric models usually generate homogeneous fields, so
contour plots will often be your visualisation of choice.
The following examples can all be found in contourdemo.pro in the course directory. We will
start with simple line contour plots of regularily spaced data. In order to have some reasonable data
to work with, CONTOURDEMO loads some emission data from the ECHAM4 model with chemistry.
File input and output will be described in chapter 6.
pro contour1,data
; simple line contour monochrome
c = getcolor(/LOAD)
range = [ max(data)/1000., max(data) ]
levels = loglevels(range)
contour,data,levels=levels,color=c.red,yrange=[47,0],ystyle=1,
c_label=intarr(32)+1
return
end
$
This is about the minimum requirement for a contour plot. You should always specify the
contour levels directly and not let IDL choose them for you. This is definitively a weakness of IDL
since it requires some overhead if you want to produce nice plots. In this example, we use the
LOGLEVELS function which was introduced in section 4.5 in order to create logarithmically spaced
contour intervals. CONTOUR establishes a coordinate system (like PLOT) and uses the array indices
as x and y values.
The next example is more complete; with a few modifications you should be able to use this
code for your own plots.
pro contour2,data
; colored lines on world map
loadct,27,ncolors=11,bottom=1 ; colortable for contour lines
c_color=bindgen(10)+2
; create color vector
tvlct,[150],[150],[150],12
; grey for continents
tmpdata = data*1.e-15
; we know the scaling here
range = [ 1.e14, 1.e17 ] *1.e-15
levels = loglevels(range,/FINE)
; create latitude and longitude arrays (~T30)
lon = findgen(96)/96.*360.
lat = [ 87.5000, 83.7766, 80.0532, 76.3298, 72.6064, 68.8830, 65.1596, $
61.4362, 57.7128, 53.9894, 50.2660, 46.5426, 42.8192, 39.0958, $
35.3724, 31.6490, 27.9256, 24.2022, 20.4788, 16.7554, 13.0320, $
9.30859, 5.58520, 1.86180 ]
lat = [ lat, -reverse(lat) ]
44
CHAPTER 5. MAP PLOTS, IMAGES, CONTOURS AND 3D
; draw map with continents and grid
map_set,0,180,limit=[-90,0,90,360],title=’CO emissions’, $
position=[0.1,0.2,0.9,0.94],charsize=2
map_continents,/FILL,color=12
map_grid,londel=30,latdel=30
contour,tmpdata,lon,lat,levels=levels,c_color=c_color, $
c_label=[1,0,0,1,0,0,1,0,0,1],/OVERPLOT,charsize=1.5
; print out scale factor
xyouts,0.15,0.23,’* 10!U15!N molec/cm!U2!Ns’,/NORM,charsize=0.8
; add colorbar
colorbar,c_colors=c_color,c_level=levels,format=’(f10.1)’
return
end
The first part of this program deals with the creation of a suitable color table (see section 4.2).
We are going to use 10 colors for the contour lines, so LOADCT is called accordingly. Note that we
start at index 1 in order to leave the background color (!P.BACKGROUND) unchanged. In addition,
we specify a color that is not in the color table for use as continent fill color. This is done with the
TVLCT command. Next, we compute the contour levels and we define the longitudes and latitudes
of the data (often you will read those from a file). Then we set up and draw a map. The contours
are overlaid (note the /OVERPLOT keyword) and every third contour is labeled (C LABEL keyword).
Since we scaled the data for better readability of the labels, we should print out the scaling factor.
Finally, a colorbar is added.
In the final example we create a filled contour plot limited to Europe:
pro contour3,data
; filled contours on world map
nlevels = 30
; number of levels to use
loadct,27,ncolors=nlevels+2,bottom=1 ; load colortable
c_color=bindgen(nlevels)+2
; color vector for contour fills
c = getcolor(/LOAD)
; drawing colors
tmpdata = data*1.e-15
; we know the scaling here
range = [ 1.e14, 1.e17 ] *1.e-15
; levels are assignmed manually! Adjust nlevels if you change this!
levels = [ 0., 1.e-6, (findgen(10)*0.1)[1:*], (findgen(10))[1:*], $
findgen(10)*10.+10. ]
; create latitude and longitude arrays (~T30)
lon = findgen(96)/96.*360.
lat = [ 87.5000, 83.7766, 80.0532, 76.3298, 72.6064, 68.8830, 65.1596, $
61.4362, 57.7128, 53.9894, 50.2660, 46.5426, 42.8192, 39.0958, $
35.3724, 31.6490, 27.9256, 24.2022, 20.4788, 16.7554, 13.0320, $
9.30859, 5.58520, 1.86180 ]
lat = [ lat, -reverse(lat) ]
; shift data so we can display complete map of Europe
dshift = 8
; 8 grid boxes (= 30 deg)
tmpdata = [ tmpdata[n_elements(lon)-dshift:*,*], tmpdata[*,*] ]
lon = [ lon[n_elements(lon)-dshift:*]-360., lon ]
ind = where(lon ge -30. AND lon le 50.)
5.3. BLOCK PLOT
45
tmpdata = tmpdata[ind,*]
lon = lon[ind]
; avoid empty boxes by setting zero values to a small number
tmpdata = temporary(tmpdata) > 1.e-6
; draw map with continents and grid
map_set,0,10,limit=[30,-30,80,50],title=’CO emissions in Europe’,
position=[0.1,0.2,0.9,0.94],charsize=2
; overlay filled contours
contour,tmpdata,lon,lat,levels=levels,c_color=c_color, $
/CELL_FILL,/OVERPLOT
$
; overlay black contour lines for factor 10 intervals
llevels=loglevels(range,/COARSE)
; line levels
c_label=intarr(32)+1
contour,tmpdata,lon,lat,levels=llevels,c_color=replicate(c.black,32), $
c_label=c_label,/OVERPLOT,charsize=1.5
; overlay continent outlines and grid lines
map_continents,thick=2,color=c.white
map_grid,londel=10,latdel=10,color=c.white,linestyle=1,/label
; print out scale factor
xyouts,0.15,0.23,’* 10!U15!N molec/cm!U2!Ns’,/NORM,charsize=0.8
; mark Hamburg
plots,10.,53.3,psym=sym(1),color=c.black
xyouts,11.,52.6,’Hamburg’,color=c.black,charsize=1.6,charthick=1.2
; add colorbar
colorbar,c_colors=c_color,c_level=levels,format=’(f10.1)’
return
end
The program begins with a similar color table definition, only this time we want 30 contour levels
and we specify them manually. We want to draw the map from −30o (i.e. 30o W) to 50o (E), but
the data run from 0 to 360o . Therefore, we have to shift the data and longitude arrays in order
to achieve a monotonically increasing series. IDL always fills contours starting from the lowest
level that is specified. Therefore, in order to avoid blank fields, you must add a value below your
minimum data value as lowest contour level, or you have to make sure that all data values are
above your minimum contour value. Here, we set all zero values to a small number.
As indicated in the previous section, we first set up the map coordinates then draw the contours
and then add the contient outlines and other things. In this example, we also overlay some line
contours on top of the filled contours in order to label them. We also add a colorbar again. As a
goodie, we mark the location of Hamburg with a circle.
5.3
Block plot
With the help of the POLYFILL command, we can display the CO emission data from the last
example in yet another way which avoids any interpolation and is thus better suited for quality
control of input fields and model output. Here is the listing of blockdemo.pro:
46
CHAPTER 5. MAP PLOTS, IMAGES, CONTOURS AND 3D
pro blockdemo,data,limit=limit
; plot CO emission fields
; select file interactively
; NOTE: CO emission fields are stored as ASCII in 8f format
; T30 resolution => 96x48 elements
; set default limit for map projection
if (n_elements(limit) eq 0) then $
limit = [-89.9,1.875,89.9,361.875]
; open file and read data
open_file,’/mf/m/m218003/chemie/FULL/data/*’,ilun
if (ilun le 0) then begin
message,’Cannot open file!’,/CONTINUE
return
endif
data = fltarr(96,48)
readf,ilun,data
free_lun,ilun
mmi = min(data,max=mma)
print,’Data min,max = ’,mmi,mma
; defining the colors
nlevels = 30
; number of levels to use
loadct,27,ncolors=nlevels+2,bottom=1 ; load colortable
c_color=bindgen(nlevels)+2
; color vector for contour fills
c = getcolor(/LOAD)
; drawing colors
tmpdata = data*1.e-15
; we know the scaling here
range = [ 1.e14, 1.e17 ] *1.e-15
; levels are assignmed manually! Adjust nlevels if you change this!
levels = [ 0., 1.e-6, (findgen(10)*0.1)[1:*], (findgen(10))[1:*], $
findgen(10)*10.+10., 1.e31 ]
; create latitude and longitude arrays (~T30)
; edge coordinates!
lon = (findgen(97)+0.5) /96.*360.
latc = [ 87.5000, 83.7766, 80.0532, 76.3298, 72.6064, 68.8830, 65.1596, $
61.4362, 57.7128, 53.9894, 50.2660, 46.5426, 42.8192, 39.0958, $
35.3724, 31.6490, 27.9256, 24.2022, 20.4788, 16.7554, 13.0320, $
9.30859, 5.58520, 1.86180 ]
latc = [ latc, -reverse(latc) ]
lat = 0.5*( shift(latc,1)+latc )
lat = [ 89.9, lat[1:*], -89.9 ]
; set up map
window,xsize=900,ysize=700
clon = (limit[1]+limit[3])/2.
map_set,0,clon,limit=limit,title=’CO emissions’, $
position=[0.1,0.2,0.9,0.94],charsize=2,/NOBORDER
for i=0L,95 do begin
5.4. VECTOR PLOTS
47
for j=0L,47 do begin
; convert edge vector to x and y line vectors
rectangle,[lon[i],lat[j],lon[i+1],lat[j+1]],xvec,yvec
polyfill,xvec,yvec,color=(WHERE(levels gt tmpdata[i,j]))[0]+1
plots,xvec,yvec,color=c.black
endfor
endfor
map_continents,color=c.white
map_grid,londel=30,latdel=30,color=c.white
; print out scale factor
xyouts,0.15,0.16,’* 10!U15!N molec/cm!U2!Ns’,/NORM,charsize=0.8
; add colorbar
colorbar,c_colors=c_color,c_level=levels,format=’(f10.1)’
return
end
The first part of the program is basically identical to the final example in contourdemo.pro: a
data set is loaded and scaled, and colors as well as cutoff levels are defined. Then we create once
again a longitude and a latitude array, however, this time we define the grid edges rather than
the center points. Next, we set up a map as previously with the only difference that we allow the
user to supply a LIMIT keyword and we have to take precaution that the center longitude lies well
within the user selected range. For the display of the data we loop through the array and draw a
filled rectangle for each grid box, the color being computed with the help of the WHERE function
(note that we added an extra level to levels above). With PLOTS we mark the grid box outlines.
I used my RECTANGLE procedure to convert an ’edge’ vector ([x0 , y0 , x1 , y1 ]) to two ’line’ vectors
which are accepted by PLOTS or POLYFILL ([x0 , x0 , x1 , x1 , x0 ] ans [y0 , y1 , y1 , y0 , y0 ]). Finally we
overlay the continents and a map grid, print out the scaling factor and add a colorbar as before.
5.4
Vector Plots
IDL supports some plots of streamline and vector fields with the FLOW3, PLOT FIELD, VEL, and
VELOVECT procedures. Here, I am going to concentrate on a vector plot of wind fields for which
VELOVECT was written. Unfortunately, VELOVECT only supports regularily gridded data, so I had
to make some changes in this routine to make it work with the example file that I had from the
REMO model which uses some irregular grid. The new routine has been named mvelovect.pro
and can be found in the course directory and in my IDL tools section.
The program vectordemo.pro reads in the example data (for file input/output see chapter
6) and then calls VECTOR1 which is listed below. VECTOR1 accepts 4 parameters which are all 2dimensional arrays: u10, v10, lon, lat. You can also use VECTOR1 with regularily spaced data
in which case lon and lat can be vectors. Here is the source code:
pro vector1,u10,v10,lon,lat
; U10, V10, LON, and LAT are all 51x51 arrays read in the main program
; LON and LAT define an irregular grid (from the REMO model)
; define colors
c = getcolor(/LOAD)
48
CHAPTER 5. MAP PLOTS, IMAGES, CONTOURS AND 3D
; set up map
mapmargin = 0.5
limit = [ min(lat)-mapmargin,min(lon)-mapmargin, $
max(lat)+mapmargin,max(lon)+mapmargin ]
clon = (limit[1]+limit[3])/2.
map_set,0,clon,limit=limit,xmargin=3,ymargin=3
; create a sky background
rectangle,[ !x.window[0],!y.window[0],!x.window[1],!y.window[1]], $
xvect,yvect
polyfill,xvect,yvect,/NORM,color=c.sky
map_continents,/FILL,color=c.gold
map_grid,/box_axes
; plot vector origins
oplot,lon,lat,psym=sym(1),symsize=0.6,color=c.red
; overlay vectors
mvelovect,u10,v10,lon,lat,/OVERPLOT,length=2,color=c.black
return
end
In the beginning, we define the drawing colors and set up the regional map using the information
stored in the data. In order to avoid problems with MAP SET, we compute the center longitude so
it is guaranteed that it falls within the range given by LIMIT. Here, we read the position vector
that was created by MAP SET (stored in the !X.WINDOW and !Y.WINDOW system variables, and use
this to fill the background with a nice blue color. We then overlay the continents filled in gold and
add a grid. The MAP GRID routine uses the BOX AXES keyword which is new in IDL 5.2. The OPLOT
command marks the grid locations, and MVELOVECT produces the vector field.
5.5
Images
One of the reasons for IDL’s success are its capabilities in image processing. The very first IDL
applications were analyses of astronomical images. It is very easy to load and display a graphics file
in IDL, but it is important to realize a few things about the nature of images in order to achieve
satisfactory results. As before, I have prepared a few examples; this time they are compiled
as imagedemo.pro in the course directory. The first little program demonstrates how to load a
satellite image of hurricane Floyd (floyd.jpg in the course directory) and how to display it in an
appropriately sized window:
pro image1,image
; load and display an image
READ_JPEG,’floyd.jpg’,image
loadct,1
; colortable blue
print,’Maximum color value in image : ’,max(image)
print,’Maximum color in color table : ’,byte(!D.N_Colors-1)
s = size(image)
; determine image size
5.5. IMAGES
49
print,’
Image dimensions : ’, $
strtrim(s[1],2),’x’,strtrim(s[2],2)
window,0,xsize=s[1],ysize=s[2]
tvscl,image
; scale image colors to fit into color table
end
The READ JPEG procedure is one of several graphics file routines. For historical reasons, some
are procedures while others are functions. The following table lists the most common READ ...
routines which all have a WRITE ... counterpart. For a complete list check the online help on
’READ...’. Almost all of these routines allow for loading and storing of the colortable that is
associated with the image.
File format Routine name
BMP
READ BMP (function)
GIF
READ GIF (procedure)
JPEG
READ JPEG (procedure)
PPM
READ PPM (procedure)
TIFF
READ TIFF (function)
In the next step, a colortable is loaded. Then we print out some information about the image in
order to see how many color values are stored and how many color values we have available on the
display. The SIZE function returns the pixel size of the image. It is a very useful tool for determining
the dimensions of any data element in IDL. Its output is a vector of variable length, depending
on the number of dimensions. For the example image, SIZE returns [2, 1043, 928, 1, 967904]. The
first value denotes the number of dimensions (you can also use SIZE(var, /N DIMENSIONS)). The
next two values list the array dimensions themselves (SIZE(var, /DIMENSIONS)). Next follows the
variable type (an image is of type byte; see table in section 2.2), and finally the number of elements
stored in the variable.
The size information is then used to open a graphics window with the appropriate size (it will
automatically cut off if the image is larger than the screen). TVSCL displays the image and scales
the image values so that they fit into the range of available colors (use TV if you don’t want to
scale).
Now, let’s see whether we can improve on the display quality. Here is the listing of the second
example program which receives the image data via a command line argument:
pro image2,image
; image histogram
; improving image details
; false color image
window,1,xsize=350,ysize=350,xpos=500,ypos=506
tmpim = image[400:749,480:829]
tv,tmpim
; unscaled image
window,2,xsize=400,ysize=300,xpos=50,ypos=400
h = histogram(tmpim)
; intensity frequency distribution
plot,h,xrange=[0,256],xstyle=1
print,’ Min,Max intensity value : ’,min(tmpim),max(tmpim)
peak = ( where(h eq max(h)) )[0]
; scalar requested !
print,’ Most frequent intensity value : ’,peak
ch=’’
read,ch,prompt=’Press Enter to continue ...’
window,3,xsize=350,ysize=350,xpos=500,ypos=506
sclim = bytscl(tmpim,min=96,max=225,top=!D.N_Colors-1)
50
CHAPTER 5. MAP PLOTS, IMAGES, CONTOURS AND 3D
tv,sclim
; optimum scaling
ch=’’
read,ch,prompt=’Press Enter to continue ...’
tvlct,[255],[255],[0],!D.N_Colors-1
; yellow continents
ch=’’
read,ch,prompt=’Press Enter to continue ...’
loadct,0,ncolors=!D.N_Colors-50
; grey scale
loadct,13,bottom=!D.N_Colors-50,ncolors=49
; + rainbow colors
end
First, we open a second graphics window and extract a portion of the image. The new window
is positioned so that the graphics overlays the original display. The extracted image portion is then
displayed without scaling the byte values. Note how the white tones become indistinguishable (the
image appears oversaturated). In order to improve the contrast, we compute and plot a histogram
of pixel (intensity) values. From this we see that most of the pixels fall between 90 and 225, so
we use the BYTSCL function to scale the image accordingly. The scaled image (sclim) is then
displayed in yet another window. You can move the windows around in order to compare the
different results.
Tip: With WSHOW you can bring a window to the front. WSET will set a window as current
graphics window, and WDELETE will delete a window (the current one if you don’t specify a number.
The current window index is stored in !D.WINDOW, and a list of all open windows can be retrieved
by a call to DEVICE,WINDOW STATE=ws.
In the bottom portion of the program, the continents are colored with yellow (this works because
we truncated the intensity range), and finally we use a combination of two different color tables to
highlight the intensive parts with color.
Tip: If you like more interactive control over the image display, you can try out XLOADCT which
loads and manipulates color tables, or you can use the LIVE IMAGE routine. Note however, that the
changes made with XLOADCT do not automatically get reflected in the plot window on 24 bit visual
depth displays. You first have to redraw the image to see the changes.
Before we continue, all windows are closed with
while (!D.WINDOW ge 0) do wdelete
.
The third example shows you how to scale images to fit into a window and how to overlay a
map or a plot on the image data:
pro image3,image
; image size and position
loadct,1,bottom=1,ncolors=!D.N_Colors-18
gamma_ct,0.7
c = getcolor(/LOAD)
scim = bytscl(image[96:*,24:*],top=!D.N_Colors-18,min=65,max=225)
window,xsize=800,ysize=800
; need to reset XSIZE and YSIZE
tvimage,scim,/keep_aspect,position=p ; return position vector
; set up a map in satellite projection to match the image
map_set,0,-74.8,/SATELLITE,SAT_P=[6.15,0., 0.],/NOBORDER,/NOERASE, $
position=p
; "proof" by displaying the continents
5.5. IMAGES
51
map_continents,color=c.yellow
; create some bogus data and overlay
lon=[-80,-80,-80,-90,-100,-110,-120,-140]
lat=[ 40, 30, 20, 15, 10, 10, 15, 28]
oplot,lon,lat,color=c.red,thick=2,psym=-sym(1)
ch = ’’
read,ch,prompt=’Press Enter to continue ...’
; zoom in
erase
scim = scim[370:569,600:799]
tvimage,scim,/keep_aspect,position=p
; return position vector
window,1,xsize=800,ysize=800
scim2 = rebin(scim,800,800,/SAMPLE)
tvimage,scim2,/keep_aspect,position=p
return
end
Here, we first load a colortable as before, but we leave some room for drawing colors which will
be used lateron. We also apply a gamma correction to the color table in order to enhance contrast
(use XLOADCT to get an idea of how things change when setting the gamma value). Next, we rescale
the image intensities as before and we also crop the image so that there is no margin around the
globe. The image is then displayed in a square window using the TVIMAGE procedure written by
David Fanning. TVIMAGE has several advantages over TV or TVSCL; one of them is the possibility to
adapt the image size to the window size or to even specify the image position on the window. Note
that the position vector that is passed to TVIMAGE is undefined, in this case TVIMAGE returns the
position that it calculates.
Tip: The other great advantage of TVIMAGE is that it works equally well on 8 bit and 24 bit
visual depth displays and with the postscript device (see section 7).
We then use the position vector returned by TVIMAGE to set up a map with the so-called satellite
projection. This projection requires an additional keyword which defines the satellite distance and
orientation (SAT P). I tried to guess these parameters. The result is a reasonable overlay of the map
with the satellite image, but it is not perfect (as you can see by comparing the continents provided
in the image with the continents drawn by the MAP CONTINENTS command). To demonstrate the
usefulness of such a procedure, I added an overlay of some bogus flight track. I am sure you can
by now replace this with your own vector data.
Tip: The advantage of the procedure listed above is that it does not distort the original image
but rather tries to adapt the coordinate system to the image. Liam Gumley has written an IMAGEMAP
procedure which follows the opposite approach, so you can morph an image onto your world map.
The example program above concludes with two examples of zooming into the image. If we
simply call TVIMAGE with an image portion that is much smaller than the window size, it will
automatically enlarge it. Internally it uses the CONGRID function for this which interpolates arrays
from one set of dimensions to another. In the second example, we first call REBIN with the /SAMPLE
keyword which preserves the pixel values instead of interpolating them.
Note: REBIN can only be used for resizing an array by integer multiples. To avoid a subsequent
interpolation by TVIMAGE you should set the window size accordingly.
52
5.6
CHAPTER 5. MAP PLOTS, IMAGES, CONTOURS AND 3D
3D Plots
*** IDL routines SURFACE or SHADE SURFACE. *** Example lightdemo.pro also demonstrates
animation.
Chapter 6
Reading and writing of data
6.1
ASCII files
ASCII data files are wide spread throughout various scientific disciplines. Advantages of ASCII files
are that they are easily human readable, interchangeable between various platforms and editable.
Among the disadvantages let me list that they are editable (sometimes you don’t want this!) and
that they are relatively inefficient in terms of storage space and (even more so) in terms of speed.
ASCII files come in all sorts of formats, and it is one of the great strenghts of IDL that all can
be read. Of course it is impossible to list all the myriad possibilities of what an ASCII file might
look like. Yet, once again I would like to present some examples and hope that these illustrate the
mechanisms that IDL provides to deal with them. This section focusses on reading ASCII files.
For writing data you basically have to replace OPENR with OPENW and READF with PRINTF.
In order to open a file in IDL (may it be ASCII or binary), you call the OPENR routine as
OPENR,fileunit,filename. FILEUNIT is a variable that acts as an internal index to a specific file.
You can either assign a number yourself or let IDL choose one by adding the GET LUN keyword to
the OPENR command. FILENAME must be a fully qualified path string, i.e. IDL must be able to find
the file from this information and it must exist. A much more convenient way of opening files is
provided with my OPEN FILE routine: You can call it with a wildcard argument and it will pop up
a dialog box which allows the user to interactively choose the file he or she wants to open. It also
provides robust error handling which is especially important when working with files. To open a
file for writing, use the /WRITE keyword. In order to read data from the file sample1.dat in the
course directory, type:
open_file,’sample1.dat’,ilun
Type HELP,/FILES to see whether this was successful. You should see output like this:
Unit
100
Attributes
Read
Name
sample1.dat
sample1.dat is a very simple file that consists of 4 columns and 10 rows of numbers with no header
or anything else. To read the data from the file, type
data=fltarr(4,10)
readf,ilun,data
free_lun,ilun
53
54
CHAPTER 6. READING AND WRITING OF DATA
We first have to define the data type (see section 2.2) and dimensions. Then we can read the whole
array in one step. Afterwards we close the file and ’free’ the fileunit so that it can be used by
another file.
Note: IDL also knows a CLOSE command which closes the file but reserves the fileunit. I
know of hardly any application where this can be useful, so I recommend you always use FREE LUN.
There is one unfortunate exception, however: in order to close all files at once and free their unit
numbers, you must type CLOSE,/ALL.
Data now contains the data with the columns indexed by the first dimension and the rows
indexed by the second dimension.
The second example file sample2.dat contains two header lines and the numbers are written in
various formats. A comma is used as record seperator, sometimes with blanks, sometimes without.
IDL can handle this without much effort: To skip the two comment lines, type
dums = ’’
for i=0L,1 do readf,ilun,dums
after the OPEN FILE command, then read in the data as before.
Note: IDL ignores commas and blanks and treats them as record seperators. If there are other
characters it will choke. Thus, in order to read e.g. a file created from Microsoft Excel (CSV
format), you first need to replace all ’;’ by ’,’.
As the third example demonstrates, you can use a FORMAT statement together with READF which
gives even more flexibility. Here, I will also demonstrate how to read data from a file when you
don’t know the number of lines it contains. The result is returned in a structure. This is the source
code for ASCII1 which is the first routine in asciidemo.pro:
pro ascii1,result
on_error,2
; return to calling routine
open_file,’sample*.dat’,ilun
; user selects file
if (ilun le 0) then $
message,’Cannot open input file!’
sarr = strarr(1000)
iarr = intarr(1000)
farr = fltarr(1000)
stmp = ’’
itmp = 0L
ftmp = 0.
count = 0L
while (not eof(ilun)) do begin
readf,ilun,stmp,itmp,ftmp,format=’(A12,6I,F12.2)’
sarr[count] = stmp
iarr[count] = itmp
farr[count] = ftmp
count = count+1
if (count eq 1000) then $
message,’Maximum storage limit exceeded!’
endwhile
free_lun,ilun
sarr = temporary(sarr[0:count-1])
iarr = temporary(iarr[0:count-1])
farr = temporary(farr[0:count-1])
6.1. ASCII FILES
55
result={ name:sarr, grade:iarr, score:farr }
return
end
This time OPEN FILE is called with a wildcard filename (however, you should select sample3.dat in
order to have the example work). The following line demonstrates how to check for a file opening
error: FILE OPEN returns a number less than 1 in case the user cancels the file selection or if an error
occurs. Next we declare the arrays that will hold the data. Be generous with the array dimensions,
usually this is of no concern in terms of memory limits. We also define some temporary variables
which are used to store the data as it is read from each individual line in the file.
Note: It is a common error to attempt reading into an indexed array variable like
readf,ilun,sarr[count],iarr[count],farr[count],format=’(A12,6I,F12.2)’
This will not store any data in sarr, iarr, or farr, because the indexed arrays are expressions
not variables and as such passed by value and not by reference (see section 2.10).
We also need a counter variable (be sure to make it of type long!). Then we read through the
file with a WHILE loop, checking for the end-of-file marker with the EOF function. Each line is read
into the temporary variables and then copied to the appropriate array loaction. After we reached
the end of the file, the arrays are truncated so that they only contain the elements that were read,
and the three arrays are stored as one structure which is returned in result. The main program
(ASCIIDEMO then prints out the structure values.
In case you need to read very large files, you can dynamically expand your data array every time
you exceed the maximum number of lines allowed. Although easier to program, it is uneffective
to do this on a line by line basis. The following example shows a more effective way: resizing
the array in chunks. Here we use a small chunk size for demonstration purposes; in real life you
would normally choose values between 500 and 5000. This procedure also demonstrates how you
can use structures to read data lines with mixed formats. The input data should be read from
sample4.dat which is just an extension of sample3.dat with more records.
pro ascii2,result
on_error,2
; return to calling routine
open_file,’sample*.dat’,ilun, $ ; user selects file
title=’!! Choose sample4.dat !!’
if (ilun le 0) then $
message,’Cannot open input file!’
stmp = ’’
itmp = 0L
ftmp = 0.
count = 0L
record = { name:stmp, grade:itmp, score:ftmp }
chunk = replicate(record,3) ; larger number in real life
result = chunk
while (not eof(ilun)) do begin
; expand array if necessary
if (count ge N_Elements(result)-1) then begin
message,’Maximum storage limit of ’+ $
strtrim(N_Elements(result))+’ exceeded!’,/INFO
result = [ result, chunk ]
56
CHAPTER 6. READING AND WRITING OF DATA
endif
; read next line
readf,ilun,record,format=’(A12,6I,F12.2)’
result[count] = record
count = count+1
endwhile
free_lun,ilun
; trim result array
result = temporary(result[0:count-1])
print,strtrim(count,2),’ lines read from file.’
return
end
The final example will provide you with the tools to read even the weirdest of all ASCII files.
The trick is to read in each line as a string variable first, then parse the string according to your
own specifications. The example data will be the file idl usage.dat which shows the number of
IDL users active at the MPI for a period of approximately two weeks prior to the IDL course (let’s
see how these numbers change in the future). This file was generated by a shell script which prints
out the system date and the number of active IDL licenses for each hour during the day. I manually
interspersed some comments to present a greater level of difficulty for the reading procedure. The
following source code will read this file and plot hourly mean statistics. Extra file comments are
automatically printed while they are read.
pro ascii3
on_error,2 ; return to caller
open_file,’idl_usage.dat’,ilun
if (ilun le 0) then $
message,’Cannot open file idl_usage.dat!’
record = { date:’’, hour:0, users:0 }
MAXRECS = 500
data = replicate(record,MAXRECS)
extra_comment = ’’
tmp = ’’
count = 0L
while (not eof(ilun)) do begin
readf,ilun,tmp ; read line into string
if (strtrim(tmp,2) eq ’’) then goto,next_line
if (strmid(tmp,0,1) eq ’#’) then begin
print,tmp
; print comment line
goto,next_line
endif
; now we assume a valid data line
reads,tmp,record,extra_comment,format=’(A10,I3,7X,I2,A)’
data[count] = record
if (strtrim(extra_comment,2) ne ’’) then $
print,record.date,’:’,extra_comment
count = count+1
if (count ge MAXRECS) then $
message,’More than ’+strtrim(MAXRECS,2)+’ lines in the file!’
6.2. BINARY DATA FILES
57
next_line:
endwhile
free_lun,ilun
data = data[0:count-1]
; compute hourly averages
result = fltarr(24)
error = fltarr(24)
for i=0,23 do begin ; even though we only recorded 8-19h
ind = where(data.hour eq i)
if (ind[0] ge 0) then begin
result[i] = mean(data[ind].users)
error[i] = stddev(data[ind].users)
endif
endfor
plot,result,xstyle=1,xrange=[7,20],psym=sym(1),symsize=2, $
yrange=[0,5],title=’IDL users at the MPI Hamburg’, $
xtitle=’Time of day [hours]’
errplot,result-error,result+error
; overlay error bar
return
end
A single data record is once again defined as a structure. We declare the data array with 500
elements and test for exceedance of this limit while reading (an index overflow would cause the
program to stop with the file still being open; for a more robust error handling method see the
CATCH procedure in section 3.4). With READF each line is read into the string variable tmp. The
first character in the string is tested for a special character which denotes a comment line (here
we chose ’#’) and we also skip empty lines. All other lines are regarded as data lines and they are
’interpreted’ with READS which reads data from a string variable just as —tt READF reads from
the file (the FORMAT option declares a 10 character string, a 3 digit integer, 7 arbitrary characters
to skip, a 2 digit integer and a variable length string which can store extra comments on a data
line. These extra comments are printed and forgotten. We test for an empty comment with the
help of the STRTRIM function in order to eliminate spurious blanks.
After we have parsed the complete file and closed it, the hourly means and standard deviations
are computed (before version 5.1 you had to use MOMENTS for this) and we plot the results as
symbols with error bars.
Note: IDL provides a routine named READ ASCII for the purpose of reading ASCII files. You
can define the file structure with the ASCII TEMPLATE function. Personally, I prefer the direct use
of READF though.
6.2
Binary Data files
Contrary to ASCII files, binary data files are not human-readable and they are machine dependent.
If you don’t know how things are stored in a binary file, it is almost impossible to find out. The
great advantage of binary files over ASCII files is the much much shorter time they need to be
written or read. Probably the best of both worlds can be found in such formats as NetCDF or
HDF which I am going to describe in the next section. These are binary formats but they contain
a standard interface and are ’self-explanatory’, so you can find out what is in them even if you
don’t know the person who has created them.
58
CHAPTER 6. READING AND WRITING OF DATA
In order to open a binary file for in- or output, under Unix you don’t have to do anything other
than for ASCII files. In Windows you need to set the /BINARY keyword. Since it doesn’t hurt to set
this keyword on other platforms (it is simply ignored), I recommend that you always use it, if only
to enhance the readability of your code. Binary files that are written from a FORTRAN program
(or that shall be read from a FORTRAN program) need a different keyword: F77 UNFORMATTED.
You can pass both the BINARY and F77 UNFORMATTED keywords to OPEN FILE.
The command for reading in a binary (unformatted) data record is READU. Note that integer
variables are usually stored as 4 byte values in a binary file, hence you need to declare them as type
long in your IDL program. Also, you must be aware that RISC and Intel machines use a different
byte-ordering scheme, so you can’t simply interchange files between the two platforms. Luckily,
IDL provides a /SWAP ENDIAN option for the OPEN command which will automatically convert ’Intel’
values to ’RISC’ and vice versa. The following one-line function will tell you whether your system
is little endian or big endian (by Robert Mallozzi):
function little_endian
return,(BYTE (1, 0, 1))[0]
end
(It can be found as little endian.pro in my tools collection).
The following example demonstrates how to read a binary file which contains a 2-dimensional
array. The array dimensions are stored as two integer values in an extra record. The file has been
generated with a FORTRAN program. This program can be found as read bin.pro in my tools
collection.
pro read_bin,filename,data,xdim=xdim,ydim=ydim,PLOT=DO_PLOT,_EXTRA=e
; read a simple binary (F77) data file that has dimensions stored
; as first 2 values, then the data
xdim = 0L
ydim = 0L
open_file,filename,ilun,/f77_unformatted,_EXTRA=e
if (ilun le 0) then return
readu,ilun,xdim,ydim
data = fltarr(xdim,ydim)
readu,ilun,data
free_lun,ilun
return
end
(The program in the tools collection also supports a DO PLOT option which produces a simple
TVIMAGE display of the data array (see section 5.5).
6.3
NetCDF and HDF files
*** Unfortunately time wasn’t sufficient for me to learn about HDF files so this section will deal
with netCDF only. However, I presume the general ideas presented here are also valid for HDF
files. I have read somewhere that the netCDF standard is more stable compared to HDF which is
6.3. NETCDF AND HDF FILES
59
important if you might have to reuse data files many years from now. Liam Gumley has written
a general HDF reader.
NetCDF stands for ’Network common data format’ and was designed explicitely for data exchange between various platforms. It is a binary file format but it contains a standard structure
of variable definitions and attributes so that you can read any netCDF file even if you don’t know
what could be stored in it. It involves a little more overhead to write and read netCDF files, but
it is definitively worth it in light of the tremenduous advantages.
Once again, I prepared a demonstration routine: ncdfdemo.pro in the course directory. I will
not list the source code for the creation of a netCDF file here, because this is hardly generalizable.
Instead follows a short list of the general steps you have to take for this:
1. Create a new netCDF file (NCDF CREATE)
2. Define the dimensions of all variables that are going to be saved (NCDF DIMDEF); one dimension
may carry the keyword UNLIMITED
3. Define the variables (NCDF VARDEF)
4. (optionally) add variable and global attributes (NCDF ATTPUT)
5. Switch from definition to data mode (NCDF CONTROL,id,/ENDEF)
6. Write the data into the file (NCDF VARPUT); you can specify an offset, en dindex and stride
value if you like
7. Close the file (NCDF CLOSE)
Reading of a netCDF file can be very easy or as complicate as you like depending on how
much information you want to retrieve. I wrote two routines to assist you with this: NCDF READ
and NCDF DETAIL. The first only reads in the variables (i.e. the actual data stored in the file)
whereas the second returns almost all the information that was stored including all attributes.
Both routines return a structure where the tag names correspond to the names of the variables (or
attributes) stored in the file. Here is the code of NCDF READ:
pro NCDF_Read,result,filename=filename
; if no filename is passed we set ’*.nc’ as file mask
if (n_elements(filename) eq 0) then $
filename = ’*.nc’
; for safety, we open the file first with OPEN_FILE
open_file,filename,ilun,/BINARY,filename=truename, $
title=’Open netCDF file’
if (ilun le 0) then $
message,’Cannot open file ’+truename+’!’
free_lun,ilun
; now we know filename exists, so we can use NCDF_OPEN:
; (CATCH would still be a good idea in case the file is
; not a netCDF file or corrupted!)
id = NCDF_OPEN(truename)
; first find out about the file contents
; (number of variables is important to us)
nstru = NCDF_INQUIRE(id)
60
CHAPTER 6. READING AND WRITING OF DATA
; retrieve the variables and their names
; store them in a structure
for i=0L,nstru.nvars-1 do begin
vardesc = NCDF_VARINQ(id, i)
NCDF_VARGET,id, i, data
if (i eq 0) then $
result = create_struct(vardesc.name,data) $
else $
result = create_struct(result,vardesc.name,data)
endfor
NCDF_CLOSE,id
; print result structure
help,result,/STRU
return
end
If you don’t pass a filename, it will assume ’*.nc’ and call the file selection dialog via
OPEN FILE. If all variables were read successfully, the resulting structure is listed with the HELP
command. You can then use the data as in the following examples:
plot,result.temperature,result.ozone
tvscl,result.co_emissions
tvscl,result.(3)
(The third example assumes that the fourth field in the structure is a 2D array).
Chapter 7
Postscript Output
7.1
Creating a postscript plot
In order to produce a postscript plot in IDL you need to change the active plotting device to ’PS’.
You will then not see any output in the graphics window but instead all output is written to a
postscript file. It is important to close the postscript file when your plot is complete, otherwise
you won’t see any output at all (more precisely: the last page of your output will be missing).
For color printing, you need to set color mode with the DEVICE command. Almost certainly you
also want to set BIT PER PIXEL to 8 in this case because there will only be 16 color levels if you
don’t. The filename of the postscript file is also specified with the DEVICE command as well as the
printable area and page margins. Here is a typical sequence:
set_plot,’PS’
; switch to postscript device
device,/COLOR,BITS_PER_PIXEL=8, $ ; color mode
filename=’myplot.ps’,
$ ; ps filename
xsize=6.693,xoffset=0.7874, $ ; paper width
ysize=10.118,yoffset=0.7874,$ ; paper height
/INCHES
; (2cm margin)
; here are your plot commands
PLOTS,[0.,0.,1.,1.,0.],[0.,0.,1.,1.,0.],/NORM
; this draws a frame around the plotting area
device,/CLOSE_FILE
set_plot,’X’
The paper size parameters in this example are set up for the European A4 standard and leave a
2cm margin on each side. In the United States, you can use 6.925 as XSIZE and 9.425 for YSIZE
which also leaves a 2cm margin for letter size paper.
If you want to produce a plot in landscape mode, you need to set the /LANDSCAPE keyword
with the DEVICE command. However, you need to be careful with specifying your page size parameters: X and Y are rotated along with the page, so XOFFSET is now measured bottom-to-top
and YOFFSET is measured from right-to-left! In order to achieve the same 2cm margin as before
you would set XOFFSET=0.7874 as before but YOFFSET = 29.7/2.54-0.7874 for A4 paper size
(replace 29.7/2.54 with 11.0 for letter paper.
To make life easier, I wrote a pair of routines named OPEN DEVICE and CLOSE DEVICE which
accept all the postscript keywords for the DEVICE command but automates some things: you can
61
62
CHAPTER 7. POSTSCRIPT OUTPUT
set a /LANDSCAPE or PORTRAIT keyword and (*** NOT IMPLEMENTED YET !! ***) select the
paper size with /A4 or /LETTER. If you wish to produce a color postscript plot, it suffices to add the
/COLOR keyword; BITS PER PIXEL will automatically be set to 8. OPEN DEVICE can also be used
to open a graphics window; you need to set the /PS keyword to redirect your graphics commands
to the postscript device. I typically have a PS keyword with many of my routines and this is then
just passed on to OPEN DEVICE. If it is not set, nothing happens (i.e. the plot will normally appear
on the graphics window). Example:
pro myplot,data,ps=ps
open_device,ps=ps,filename=’myplot.ps’,/COLOR
plot,data
close_device,/timestamp
return
end
Now you can either call myplot,data and get the plot on the screen or myplot,data,/ps and
create a postscript file. Note that the CLOSE DEVICE routine accepts a TIMESTAMP keyword. This
will automatically print the username and filename together with the creation date in the lower
right corner of the page.
Tip: David Fanning wrote a tool named PS FORM which provides some interactive sizing and
positioning of your plot on the postscript page, and Craig Marckwardt has modified this tool to
allow for various paper formats.
Note: It is generally not possible to create a screen snapshot in IDL. In order to ’copy’ the
contents of a graphics window onto a postscript page, you need to reissue all the graphics commands
that led to the window contents. You can however use David Fanning’s XWINDOW program which
provides a resizeable graphics window with a PRINT menu option.
7.2
Another Note on Colors
If you ar working with an 8 bit visual depth graphics display, you will typically have between 120
and 220 colors available in your IDL session. As soon as you switch to the postscript device (with
the BITS PER PIXEL option set to 8), you will have access to all 256 colors and this is reflected in the
system variable !D.TABLE SIZE (before version 5.2 it would be !D.N COLORS which you had to limit
manually to 256 for true color displays; see section 4.2). As long as you don’t change your color
table and if you don’t use the !D.TABLE SIZE or !D.N COLORS system variables, your postscript
plot will have exactly the same colors as the screen (disregarding the fundamental differences due
to the fact that one image is produced by light whereas the other is composed of toner or ink on
paper or transparency).
***** gray levels on top of color bar: if you don’t reload the color table but use the !D.N COLORS
value in your plotting routine.
IDL’s default plotting color is stored in !P.COLOR which is normally set to !D.N COLORS-1 for
screen output and !P.BACKGROUND has a value of 0 (the first color index). For postscript output,
the two are exchanged, so you normally get a white plot on a black window as default on the
screen but a black plot on a white page for the postscript output. While !P.BACKGROUND is ignored
completely in postscript output, you can set !P.COLOR explicitely, and it will then be used by the
postscript device as well (you have to set !P.COLOR after you change to the postscript device). Of
course you can always use explicit colors via the COLOR keyword of PLOT and others. Once again I
recommend that you use David Fanning’s GETCOLOR program for this purpose.
Chapter 8
Internet resources on IDL
8.1
Web links, FAQ and newsgroup
This section lists various internet resources about IDL. It is derived from links found on my own
web page, Mike Schienle’s FAQ, and David Fanning’s excellent web site. More links can be found on
Research Systems (producer of IDL) web pages at http://www.rsinc.com/related/index.cfm.
I checked the links listed below, but I assume no responsibility for completeness or correctness of
this information. The categorization is based on my personal judgement. This information was
compiled on 30 Aug 1999 .
1. Quick Help — The best Tips&Tricks on the web
• The first place to look if something doesn’t work should always be David Fanning’s excellent web pages: http://www.dfanning.com He offers many programming tips covering
almost all aspects of IDL and often including ready-to-use programs. He is a software
consultant and makes his living with IDL training courses and writing IDL programs
for clients.
• The IDL FAQ list is maintained by Mike Schienle from ’Interactive Visual Software’
and can be found at: http://www.ivsoftware.com:8000/FAQ/default.htm This is a
searchable data base and contains many answers to general questions about IDL as well
as several programming tips.
• Scott Laflin from UCSF provides ’Help for experienced users’ mainly on matrix multiplication and widget programming: http://www.sf.med.va.gov/mrs/IDL/idl docs.htm
• Tips for pretty postscript output can be found on Eric Deutsch’s page from the University of Washington: http://www.astro.washington.edu/deutsch/idl/index.html
• Research Systems (the company who produces IDL) maintains a tech tips page at:
http://www.rsinc.com/services/search.cfm There may not be too many tips, but
you get firsthand information from the people who really know IDL.
2. Program Libraries
• At David Fanning’s web page you find several useful programs: http://www.dfanning.com
• My own web page (still located at Harvard) lists several (but not all) of my IDL tools
as individual routines with a short description:
http://www-as.harvard.edu/people/staff/mgs/idl/idl library.html (Warning: my
63
64
CHAPTER 8. INTERNET RESOURCES ON IDL
COLORBAR routine was derived from David’s COLORBAR routine and still bears the
same name! The same is true for TVIMAGE.) I should probably rewrite several of these
routines now that I know how to really program in IDL!
• A quite comprehensive collection of IDL routines from various libraries can be found at
Loas Alamos: http://nis-www.lanl.gov/∼uk2/idl They provide a search function
and links to several other pages (although the links are not always up-to-date).
• Liam Gumley provides routines in various areas, e.g. Color Handling Tools, Image Tools,
Frame Tools, Satellite Image Mapping Tools, HDF Reader. Liam has also published a
book on ”Practical IDL Programming” in 2001. All at:
http://www.gumley.com/
• Craig Marckwardt has a couple of routines with good documentation on his web page.
Most notably he wrote a fitting procedure (MPFIT) which uses the MINPACK algorithm and is more stable and flexible than IDL’s curvefit procedure:
http://cow.physics.wisc.edu/∼craigm/idl/
• Mike Schienle provides a few routines, mostly useful to ensure cross- plattform compatibility: http://www.ivsoftware.com/IV Code.html
• Eric Deutsch has a searchable database which contains over 3000 routines collected from
several sites: http://www.astro.washington.edu/deutsch/idl/index.html
• Marc Buie maintains another library at Lowell University:
http://www.lowell.edu/users/buie/idl/idl.html He focusses on astronomy and
spectroscopy.
• Mark Hadfield provides more and more object oriented routines on his web page in New
Zealand: http://katipo.niwa.cri.nz/∼hadfield/gust/software/idl/
• The John Hopkins University (JHU) Applied Physics Laboratory hosts probably the IDL
library with the longest history: http://fermi.jhuapl.edu/s1r/idl/idl.html The
library itself is available via ftp, the web page contains a page with one-line descriptions.
• Wayne Landsman’s IDL Astronomy Library World Wide Web home page:
http://idlastro.gsfc.nasa.gov/homepage.html Mostly useful for astronomy routines, each routine has a short one-line description. You’ll get the library in one piece.
• The ESRG library contains among many routines several tools for geodesy:
ftp://eos.crseo.ucsb.edu/pub/idl
• David Windt provides several utility tools and packages for topography analysis and multilayer optical property modeling at: http://www.bell-labs.com/user/windt/idl/
• Dave Foster has a library based on medical imaging routines (but also general tools):
ftp://bial8.ucsd.edu/pub/software/idl/share/ Get the README file.
3. Tutorials
• Perhaps the best link for a beginner’s tutorial is Christophe Morisset’s IDL cookbook
at: http://www.iagusp.usp.br/∼morisset/idl/index.html
• The John Hopkins University (JHU) IDL site:
http://fermi.jhuapl.edu/s1r/idl/idl.html contains a brief description of ’What is
IDL?’ and a quick reference to the IDL Syntax.
• Liam Gumley wrote the ’Underground Guide to IDL’ which is a little sparse and outdated, but still contains some useful information on aligning images with maps and HDF
files: http://cimss.ssec.wisc.edu/∼gumley/
8.2. MY OWN IDL LIBRARY
65
• The Technische Hochschule Darmstadt serves a short but well organized introduction
to IDL at: http://www.tu-darmstadt.de/hrz/pc/prog/grafik/idl-4 1.htm Unfortunately, this page is a little outdated (refers to version 4.1).
• The original manuals for IDL can be downloaded from
ftp://ftp.rsinc.com/pub/idl/info/docs/
• The NCSA serves several IDL manuals online in postscript form, e.g. a math manual: http://consult.ncsa.uiuc.edu/docs/viz/Idl/index.html#psdocs It looks a
little like some older documentation by Research Systems which is no longer in print.
But it gives a nice introduction to IDL’s math routines. Check the online help for
up-tp-date calling sequences and related procedures. Also available is a brief IDL
primer which covers basic plotting, reading and writing of data and simple animations:
http://consult.ncsa.uiuc.edu/docs/viz/Idl/Training/
4. Other Resources
• The IDL newsgroup is very lively and there are several helpful people there. You can
get an answer to almost any question concerning IDL, but PLEASE read the FAQ first
and check out a few of the QUICK HELP sites beforehand. The name of the newsgroup
is: comp.lang.idl-pvwave
• Mike Schienle composed a IDL style guide which may be a little strict but nevertheless
provides useful ideas: http://www.ivsoftware.com/IDL Style.html
• Carsten Dominik has taken the lead in maintaining a mode script for Emacs and IDL.
You can find it at: http://www.strw.leidenuniv.nl/∼dominik/Tools/idlwave/
• People who use a lot of special characters in their plots might want to look at the
TeX2IDL routines at: ftp://coma.berkeley.edu/pub/mcraig/idl/TeXtoIDL/
• Gary Kurshner tells you something about hardware interfacing with IDL (source code
for Windows 3.x only and still under construction)
http://casa.colorado.edu/∼kushner/idl-iii.html
• The Institut Laue Langevin offers a data analysis package based on IDL named LAMP:
http://www.ill.fr/data treat/lamp/front.html
• The Lawrence Livermoore National Laboratory developed ’An Image Analysis Tool’
(AIM) which can be obtained at: http://www.llnl.gov/adiv/projects/aim/
• Eric Korpela provides a routine for memory mapped files (restricted to Unix systems
for now). This extends beyond the ASSOC function and even allows some interprocess
communication between two IDL sessions:
http://albert.ssl.berkeley.edu/∼korpela/mmap/
8.2
My own IDL library
Over the last two years I have compiled a number of routines from which I thought they may
be of general interest. Some of these I would now write completely differently, but that’s my
own learning curve. So far, the web pages describing the library are still hosted at Harvard:
http://www-as.harvard.edu/people/staff/mgs/idl but I already made a few changes again,
so you should always access the routines locally: /afs/dkrz.de/pf/m/m218003/IDL/tools.
Here is a list of some of these routines (the ones I personally use most) in alphabetical order.
Use the USAGE procedure to find out how they work.
66
CHAPTER 8. INTERNET RESOURCES ON IDL
• add template.pro adds a standard header to your own IDL routines (but please fill in the
fields!)
• arrex.pro returns an array subset with variable start, end and stride parameters
• chkstru.pro Check an argument whether it is a structure and (optionally) whether it contains certain tags
• colorbar.pro adds a colorbar to a plot. Handles both ’smooth’ colors and ’discrete’ colors
and allows for special out-of-range colors
• cumtotal.pro computes the cumulative total of a vector
• e h2o.pro computes the water vapor saturation pressure
• extract filename.pro and extract path.pro split a complete file path into directory and
filename (works on Unix and Windows platforms)
• inv index.pro inverts a vector index, i.e. all indices are returned that do not match a WHERE
condition
• legend.pro adds a symbol and line legend to a plot
• loglevels.pro returns reasonably spaced logarithmic levels for a given range of data
• make selection.pro Convert an array of selected values to an index array that identifies the
selected values in a list or data array. Example: if LIST is a list of the letters in alphabetical
order, make selection(list,[’A’,’E’,’F’]) will return [1,5,6]
• mfindfile.pro replaces the original findfile function which had problems on SGI’s (still
doesn’t allow for correct listing of directories with too many files)
• multisort.pro allows hierarchical sorting of data arrays
• open device.pro and close device.pro facilitate changing between screen and postscript
output
• open file.pro provides you with all necessary error handling when opening a file and automatically comes up with a file selection dialog when you pass a name with wildcards
• percentiles.pro returns arbitrary percentiles
• readdata.pro and writedata.pro can be used to read ASCII files with numerical data
• run av.pro compute a running average; special features for maximum allowable intervals in
time series
• str2byte.pro Convert a string into a byte vector of a given length for output in binary data
files
• strdate.pro function that returns a formatted date string with some flexibility
(MM/DD/YYYY [HH:MM], or DD.MM.YYYY [HH;MM], or YYYY/MM/DD [HH;MM])
• sym.pro redefines IDL’s plotting symbols
• undefine.pro undefine a variable within your IDL programs (unlike delvar which operates
only on the command line). This routine is from David Fanning
• usage.pro displays parts of the file header of IDL programs (similar to DOC Library)
• yesno.pro A simple query program to handle boolean choices
8.3. THE EXPLORE TOOL
8.3
67
The EXPLORE tool
EXPLORE is a tool that has been developed for analysis of aircraft data. The most important feature
I had in mind when I started was to mark individual data points or regions of interest and have
these highlighted in all the plots that refer to the same data set. It has gone some way since then.
You can find EXPLORE in my IDL directory /afs/dkrz.de/pf/m/m218003/IDL/explore and there
is documentation available on my IDL web page at Harvard:
http://www-as.harvard.edu/people/staff/mgs/idl
8.4
The Global Atmospheric Model Output Analysis Package (GAMAP)
The GAMAP package has been developed at Harvard to analyze the output of the Harvard CTMs.
They come with a special output format (originating in the late 70s) and it had been a considerable constraint to work around these historical issues in order to gain acceptance for GAMAP. The
package loads individual data records only when it needs them and consists of several routines to
display and manipulate these data. A program named gamap.pro provides a simple text based
interface. GAMAP is documented in a 40 page pdf file which is found together with all the routines
in /afs/dkrz.de/pf/m/m218003/IDL/gamap.
Was this manual useful for you? yes no
Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Download PDF

advertisement