Sunteți pe pagina 1din 63

Starting IDL,

>> IDLDE for going to IDL development environment (window)


>> idl for command interface

For quitting, type “exit” on the idl prompt or type “Ctrl+d”.

Some definitions

Operators: Items like +,-,*,/ and so on.


Constants: Items like 3, [3,2,5], "A string", AND, OR, and so on.
Variables: A named item used to store a value.
Expression: A constant, variable, or set of constants and/or variables combined by
operators.
Statement: A single IDL statement or a statement block (see below).
Routine: A procedure or a function.

keys

Ctrl-e moves the cursor to the end of the line


Ctrl-a moves the cursor to the start of the line
Ctrl-d shall knock us out of IDL unless we redefine its function through

Define_key, /control,’^D’,/delete_current

This should be put in IDL start up file. If my_start_up file is used, its done.

Help

IDL>? For opening IDL help

As we quit IDL, its help window also disappears, so its useful to call help directly from Unix command
prompt,

>idlhelp

Idl is case insensitive and space insensitive too,

>print, 2*4 or PRINT, 2 * 4 or Print, 2* 4 are all equal. Unix is case sensitive,therefore,
journal, “text_file” and journal, “Text_File” are not equal.

All commands are followed by comma “,”

•To use an OS command, enter $ prior to it (Exceptions: pwd, cd,’/disk…’)


IDL>$ls ;lists content of current directory

Comments semi-colon ; is used as comments character.


Variable Types

In an IDL session, data (i.e. numbers and strings) is stored in what’s known as
variables. There are 3 basic types of IDL variables :

Scalar (a single value)


Array (from 1 to 8 dimensions – a vector is an array with only 1 dimension)
Structure (an aggregate of various data types and other variables)

type range bytes to define to convert

byte 0 to 255 1 b=15B b=byte(x)

i=15
integer -32768 to 32767 2 i=fix(x)
i=15S

unsigned_integer 0 to 65535 2 i=15US i=uint(x)

j=15L
long -231 to 231-1 4 j=long(x)
j=25631l

unsigned long 0 to 232-1 4 k=1554856UL k=ulong(x)

m=-
very long -263 to 263-1 8 m=long64(x)
123456789012345678LL

unsigned very
0 to 264-1 8 m=123654789658ULL m=ulong64(x)
long

y=1.7
+/- 1038, 7 sig.
floating point 4 y=float(x)
figs y=1.5e12

y=1.5d
+/- 10308, 14 sig.
double precision 8 y=double(x)
figs. y=1.5d40

complex 2 floating points 8 z=complex(1.2,0.3) z=complex(x)

complex with
double complex 16 z=dcomplex(1d5,2.3d21) z=dcomplex(x)
double_precision
0-
string (user defined) s='blah' s=string(x)
32767

Special symbols

; is the beginning of a comment.


& allows to put 2 commands on the same line.
$ allows to continue a command on the next line, or (when at the beginning of the line) will
send command to the shell.
@ will include a file containing a list of IDL commands (bach)
# and ## are matrix operators.
^ will allow you to redo a command from the history, asking you a string to match.
! is used for the system variables: IDL> print , !pi

Fundamental mathematical constants

These IDL “internal characters” are identified by the first character being “!”.
!pi is just pi.
!dtor Degree to radians, b=a*!dtor gives b in radians if a is in degrees
!radeg Radians to degree

Entering and reading a variable,

Print, ‘Enter a number:’


Read, a
Readf is used for reading a file.

$ is the continuation character and & allows typing of multiple commands on a single line like
a=sqrt(a) & help a

sqrt(a) shall give squre root of the array a. The symbol “^” is used for power.

Journaling
To keep record of all commands and IDL responses, use Journal.

Journal, “mycode.pro”

All commands entered at IDL prompt are recorded in “mycode.pro”


Journal Ends the journaling
Calling JOURNAL without Arg while journaling is in progress closes the journal file and ends the
logging process.
•Toview, open journal file with any text editor
> emacs text_file
or > nedit text_file
Basics

Numbers with decimal points are called floating point numbers.


A=4.3 defines A as floating point number.
A=’joe’ defines it as a string variable ie ordinary text.
idl> help, a to know the data type of a
The command and the different parameters are always separated by commas (with or without
space around):
IDL> print , 'I do not like to print!'
IDL> print , 512. * 512. / 4.
IDL> plot,x,y
IDL> readf,logical_unit,x1,x2,x3,x4
The affectation of a variable is done by the sign =
The function have its parameters between braces.
IDL> var1 = 5
IDL> var1 = 5. ; no warning if var1 is already defined...
IDL> a = cos(x)
IDL> b = cos(x^2 + y^2) * alog(5*z^(1./3.))
IDL> plot , x , cos(x^2)
Arrays elements are referred using [ ] or ( ) -this is the old fashion-.
IDL> tab[2,6] = 6.

Commands and functions have parameters and keywords. The keywords are named in the
calling sequence:
IDL> plot,x,y,xrange=[10,1000],color=5,/ylog
Here xrange and color are explicitly set to their values.
The ylog keyword is boolean (if = 1, the plot will be in log scale on the Y axe, else linear scale
will be used).
This can be specified by ylog=1, or shortly by /ylog.
Keywords can be abreviate:
IDL> plot , x , y , xrange=[0,200]
IDL> plot , x , y , xr=[0,200]
are equivalent.

randomu() generates random numbers. It needs two arguments, seed and the number of numbers to
produce.Seed is an input number where the numbers begin. If its not given, IDL takes the time from
system clock. To generate 230 numbers distributed randomly between 0 and 1,
Randomu(seed,230)
To get a Gaussian or normal distribution, set normal=1, Randomu(seed,230,normal=1)
Batch Files

Many IDL commands can be written in a text file and executed together. You can create
“test.batchfile.pro” and then to invoke them, we put @ sign in front of file name.
@test.batchfile

original=sin((findgen(200)/35.)^2.5)
original=original+2
time=3*findgen(200)

plot, time, original, xtitle="Time" ytitle="amplitude", $


yrange=[0.5,0.35], xrange=[0,600], ystyle=1, psym=-4

Plot Function

Plot, b Make a plot of b versus its index number.


Plot, a, b makes a plot of b versus a, with a on the horizontal axis and b on the vertical.

Plot, a, b, title='title', xtitle='x', ytitle='y', thick=1, psym=-1, linestyle=0

psym=-4 puts each point on the plot as diamond, psym=1 puts + signs on the plot.
Difference between psym=4 and -4 is that -4 is “line with symbol” and 4 means just symbols.

Symbol Numbers for psym=,


1 plus
2 star
3 single point
4 diamond
5 upright triangle
6 square
7 cross

Linestyles
0 solid line
1 dotted line
2 dashed line
3 dash-dot line
4 dash-dot-dot line

xrange=[a,b] limits the data range from a to b on the x-axis.


,/xlog makes the x-axis logarithmic (at the end)
,/ylog makes the y-axis logarithmic

plot,x,y, xrange=[a,b],color=5,/ylog (for ps files)


plot,x,y,background=255,color=0 (for white background)
(Background sets background color and color sets the line/dot color)

An alternative to using ,/xlog and ,/ylog is plot_oo , plot_oi with plot_ii as default. plot_oo is used if
both x and y axes are logarithmic and plot_oi if only x-axis is logarithmic. With plot_ii, non of the
axes are logarithmic.

Overplotting

Sometimes we want two graphs on the same plot. Use Oplot for this.

Oplot, a, b, linestyle=2 This shall overplot using a dashed-line.

Multiplots

!p.multi is used for multi plots. It tells IDL how many plots to put on a single page. For 2 columns and
3 rows of plots,

!p.multi=[0, 2, 3]

It plots in the following order,


Upper-left, upper-right, middle-left, middle-right, lower-left and lower-right.
At the end type, !p.multi=0 to unset multiplot.

Getting Plot as Postscript File

Use the procedure psopen to open a ps file. As an argument, it takes the name of the file. Size of the
plot can also be specified with default being 8.5x11 inches. To create a 5x4 inch plot,

Psopen, ‘plotfile.ps’, xsize=5,ysize=4,/inches

Close the ps file by typing psclose.

Live_plot
The LIVE_PLOT procedure allows you to create an interactive plotting environment. Once plotted,
you can double click on a section of the plot to display a properties dialog. A set of buttons in the upper
left corner of the image window allows you to print, undo the last operation, redo the last undone
operation, copy, draw a line, draw a rectangle, or add text. Using any of several auxiliary routines, you
can control your LIVE window after it is created.

ARRAYS (TABLEAUX)

Square braces are used to define vectors (1-dimensional arrays):

v1=[1,2,3], v2=[4,5,6], v3=[7,8,9] To add these two vectors, v3=v1+v2, to multiply, v1*v2
n_elements(a) returns the total number of elements in a.

IDL> a = fltarr(5)
IDL> for i=0, 4 do a(i) = 2*i
IDL> print,a
b=[1,2,3,4,5,6] defines b as a six-element array.
c=b^0.5 creates a new array c as sqrt of b.
Print, max(b-c) shall give the max of array b minus array c.
Print, min(b-c) shall give min of array b minus c array.
Print, total(b) prints the sum of all elements in array b.
total(b,1) gives sum of first dimension of b. (for matrices, sum of row in a 1-D array)
total(b,2) gives sum of the second dimension of b. (for matrices, sum of all columns)
abs(a) gives the absolute value of a or modulus of a if a is complex.
real_part(a) gives the real part of complex number a.
imaginary(a) gives the imaginary part of complex number a.
mean(a) gives the mean of array a.
moment(a) gives the mean, variance, skewness and kurtosis (flatness) of a in a 4-element 1D array.

; Define an n-element sample population:


X = [65, 63, 67, 64, 68, 62, 70, 66, 68, 67, 69, 71, 66, 65, 70]
; Compute the mean, variance, skewness and kurtosis:

result = MOMENT(X)

PRINT, 'Mean: ', result[0] & PRINT, 'Variance: ', result[1] & $
PRINT, 'Skewness: ', result[2] & PRINT, 'Kurtosis: ', result[3]

IDL prints:
Mean: 66.7333
Variance: 7.06667
Skewness: -0.0942851
Kurtosis: -1.18258

Z=fltarr(3,7) defines a two-dimensional float array with 3 columns and 7 rows.


A=fltarr(100) defines an array of 100 floating point numbers each of which equals zero.
A=intarr(10) defines an array of 100 integers, each of which equals zero.
A=dblarr(10) creates a double-precision floating point vector or array.
A=lonarr() for long
A=complexarr() for complex array generation
A=dcomplexarr()
a=strarr() defines a string array.

a=indgen(100) defines an array of 100 short integers with value from 0 to 99.
a=lindgen() for array of long integers
a=findgen(100) defines a as an array of 100 floating point numbers in which the values increase
sequentially from 0 to 99.
a=dindgen() creates double-precision array of 64 bit size.

FINDGEN() stands for Floating INDex GENerated.

Use the INDGEN function to set the value for each element of the array
to its one-dimensional subscript (notice that IDL is a row-major language) :
IDL> array = indgen (5, 5)
IDL> help, array

ARRAY INT = Array[5, 5]

IDL> print, array

0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24

The ability to perform operations on only specific elements of an array is another power of the IDL
language and is called subscripting. The square bracket characters “[“ and “]” are used to perform
subscripting in IDL. Since IDL is row-major, the appropriate way to subscript a 2-dimensional array is
with the syntax [column#, row#].

It is also important to keep in mind that indexes for subscripting start at 0 instead of 1. For example, to
print only the value found in the element in the 2nd column and 4th row of the variable “array” execute
the statement :

IDL> print, array [1,3]


16

For a =indgen(100) print, a[0], a[99] Print the first and last elements of a. Elements of an array are
designated by a numerical index. The index begins with zero; the last element of the array has index n-
1, where n is the number of elements in the array. Why doesn't the index run from 1 to 100 instead of
0 to 99? You'll appreciate why. . . later in the course.

print, a[10:20] Prints array a elements from 10 to 20. Such printouts are often handy but it's hard to
identify each array element with its index. To get a printout in column format:

Règles d’adressage des éléments d’un tableau et règles de redimensionnement

Tab ou Tab(*,*) représente la totalité du tableau de valeurs


Tab(50:100,*) est constitué des colonnes 50 à 100 et de toutes les lignes
Tab(50:100,25 :*) est constitué des colonnes 50 à 100 et des lignes à partir de la ligne 25
Tab(50,*) est un vecteur qui n’adresse que la colonne numéro 50
Tab(x,y) est l’élément situé à l’intersection de la colonne x et de la ligne y

Exemples :

T = 2.* Tab définit un nouveau tableau T égal au double du tableau Tab, de même dimension.
T = Tab(30:55,150:200) définit un nouveau tableau T contenant les colonnes 30 à 55 et les lignes
150 à 200 de Tab. Les dimensions de T sont donc 26 x 51. Les éléments de T sont donc
numérotés de 0 à 25 (colonnes) et de 0 à 50 (lignes).
T = Tab(*,10) est un vecteur qui contient la ligne 10 de Tab.
T = Tab(15,23) est un scalaire

for nr=0,99 do print, nr, a[nr] This uses a for loop to cycle through the indices numbered
0 to 99 and print a separate line with two numbers, the index number and the corresponding array
element.

b = sin(a/5.)/exp(a/50.) Defines the new array, b, in which each element is related to the
corresponding element in a by the mathematical expression. Note that when we divide anything
by a number we always express the denominator as a point number. Always do this until
you learn more.

size(a) shall give the dimensions of a in a 5-element array with first showing total number of
dimensions, second showing the size of first dimension and so on.

If no keywords are set, SIZE returns a vector of integer type. The first element is equal to the number
of dimensions of Expression. This value is zero if Expression is scalar or undefined. The next elements
contain the size of each dimension, one element per dimension (none if Expression is scalar or
undefined). After the dimension sizes, the last two elements contain the type code (zero if undefined)
and the number of elements in Expression, respectively. If a keyword is set, SIZE returns the specified
information. 2 means integer, 3 for long, 4 for float etc.

dim = size(Tab) retourne un vecteur dim


ndim = dim(0) donne le nombre de dimensions du tableau
dimx = dim(1) donne la première dimension,
dimy = dim(2)
dimz = dim(3).... etc but last two figures are different. For example,

t=[[1,2,3,4],[1,1,2,3],[4,5,6,7]]

IDL> print,t

1 2 3 4
1 1 2 3
4 5 6 7
IDL> dim=size(t)

IDL> print,dim

2 4 3 2 12

IDL> print,dim(2)

Here 2 shows that t is 2D array, 4 shows the number of columns, 3 shows number of rows, 2 shows
data type as integer and 12 shows the total number of elements in t.
Sort(a) returns the indices of array elements with each index corresponding to relative position of
element in array.
A[sort(a)] gives array a in ascending order.

For arranging in descending order, a[reverse(sort(a))]

IDL> a=[2,4,3,9,8,6]
IDL> print,sort(a)
0 2 1 5 4
3

IDL> print,a[sort(a)] Puts in ascending order


2 3 4 6 8 9

IDL> print,reverse(a) Reverses the order of elements


% Compiled module: REVERSE.
6 8 9 3 4 2

IDL> print,a[reverse(sort(a))] Puts in descending order

9 8 6 4 3 2

IDL> b=[0,1,2,4,5,65]
IDL> print,where(b) Gives indices of non-zero elements
1 2 3 4 5
IDL> c=[0,1,2,4,0,65]

IDL> print,where(c)
1 2 3 5

IDL> print,uniq(c) Gives indices of elements that does not repeat them-
selves. Any number repeating itself is not included.
% Compiled module: UNIQ.
0 1 2 3 4 5
IDL> z=[1,1,2,2,4,5,6] (Second 1 does not repeat itself, third element ‘2’ does
so)
IDL> print,uniq(z)
1 3 4 5 6 (these are indices)

IDL> a=[1,1,1,1,1,5] (First element,1, is repeating, so are other 1s till index


3. The 1 of index 4 is not repeating. The 5th element, which is 5, is also not re-
peating.)

IDL> print,uniq(a)
% Compiled module: UNIQ.
4 5

IDL> v=[1,2,7,8,4,3,3,2,2] (4th element is repeating,5th is not,6th is


th
repeating,7 is non-repeating.)

IDL> print,uniq(v)
0 1 2 3 4 6 8
IDL> print,v[uniq(v)]
1 2 7 8 4 3 2
v[uniq(v)] eliminates the repeating elements of the array. If we want to eliminate even the non-adjacent
repeating elements, we shall then first have to sort() the array and then apply uniq() function.
Function uniq(a, index) has an optional argument, ’index’ which can be used to sort the array.

UNIQ(Array, SORT(Array)) shall first sort array and then apply uniq on it.

; Create an array:
array = [1, 2, 1, 2, 3, 4, 5, 6, 6, 5]

; Variable B holds an array containing the sorted, unique values in


; array:
b = array[UNIQ(array, SORT(array))]
PRINT, b
IDL prints
1 2 3 4 5 6

we can do it step by step, to verify,

IDL> a=[1,2,1,2,3,4,5,6,6,5]

IDL> c=a[sort(a)]

IDL> print,c
1 1 2 2 3 4 5 5 6 6

IDL> e=c[uniq(c)]

IDL> print,e
1 2 3 4 5 6

Repeating the above example,

IDL> f=a[uniq(a,sort(a))]

IDL> print,f
1 2 3 4 5 6

median(a,/even) or median(a,/double) or median(a,/dimension=1) are used to find the


median if the array has even number of elements, to force the median to be of
double type and to do median on a specific dimension of array like only on x-dim or
y-dimension etc.

IDL> a=[1,2,3,4]

IDL> print,median(a) The result is wrong without /even


3.00000

IDL> print,median(a,/even)
2.50000

IDL> print,median(a,/even,/double)
2.5000000

IDL> b=[1,2,3,4,5]
IDL> print,median(b)
3.00000
IDL> print,median(b,/even)
3.00000
IDL> c=[[1,2,3],[4,5,6],[7,8,9]]
IDL> print,c
1 2 3
4 5 6
7 8 9

IDL> print,median(c,dimension=1) row-wise


2.00000 5.00000 8.00000
IDL> print,median(c,dimension=2) column-wise
4.00000 5.00000 6.00000

IDL> c=[[1,2,3,2],[3,4,5,6],[6,7,8,9]]
IDL> print,median(c,/even,dimension=1) row-wise
2.00000 4.50000 7.50000

(The first median is 2 because the array [1,2,3,2] is first arranged in ascending
order [1,2,2,3] and then median is found.)

IDL> print,c
1 2 3 2
3 4 5 6
6 7 8 9
IDL> print,median(c,/even,dimension=2) column-wise
3.00000 4.00000 5.00000 6.00000

Working with arrays


One of the things IDL is able to do is working with arrays very nicely.
First, let's define some arrays:
IDL> vec1 = [1,2,3,4,3,2,3,4,5,5,3]
IDL> vec2 = [8,65,7,54,3,4,6,7,6,5,5]
IDL> tab1 = [ [ 1.5 , 2 , 3 ] , [ 2 , 3 , 4 ] , [ 7 , 9 , 0 ] ]
this latest one is a 2D array.
Arrays are in the [ column , row ] order.
Arrays start at 0!!!
=> the 5th column of tab[N,M] is tab[4,*]
There is a large set of other array-oriented arithmetic functions, such as expand, mean, re-
bin, reverse, smooth, sort, total, transpose, and so forth.

Look at it:
IDL> print,vec1
1 2 3 4 3 2 3 4 5
5 3
IDL> print,tab1
1.50000 2.00000 3.00000
2.00000 3.00000 4.00000
7.00000 9.00000 0.00000
IDL> help,vec1
VEC1 INT = Array[11]
IDL> help,tab1
TAB1 FLOAT = Array[3, 3]

The help command displays information on the type and the size of the variables. You see
that in the tab1 the first element of the array being 1.5, the whole array is in floating point
type.

The size function return information on the size(s) and type of the arrays, and the n_elements
will just return the total number of element in an array:
IDL> print,size(tab1)
2 3 3 4 9
Here 2 is the number of dimension, 3 and 3 are the number of rows and columns, 4 indicates
the type of data (here floating point) and 9 is the total number of elements, also available by:
IDL> print,n_elements(tab1)
9
Print,(size(tab1))[3] shall give the total number of elements in the tab1.
You can perform operations on the arrays WITHOUT using loops:
IDL> vec2 = vec1^2
IDL> print,vec2
1 4 9 16 9 4 9 16 25
25 9
IDL> print,cos(tab1)
0.0707372 -0.416147 -0.989992
-0.416147 -0.989992 -0.653644
0.753902 -0.911130 1.00000
IDL> vec3 = vec2 - vec1
IDL> print,vec3
7 63 4 50 0 2 3 3 1
0 2
IDL> vec4 = [ vec3, 2 , 3]

If you have some images, you can perform operations on them in the same way. Suppose we
have image1, flat1, dark1:
IDL> help,image1,dark1,flat1
IMAGE1 FLOAT = Array[512, 512]
DARK1 FLOAT = Array[512, 512]
FLAT1 FLOAT = Array[512, 512]
IDL> image2 = (image1 - dark1) / (flat1 - dark1)
You may want to create a empty array?
IDL> image = fltarr(1024,1024)
Or a array with something like that: 1.,2.,3.,4.,5.,6.,7.,8,etc... (it's a "floating indexed
generated array"):
IDL> x = findgen(10)
IDL> print,x
0.00000 1.00000 2.00000 3.00000 4.00000 5.00000
6.00000 7.00000 8.00000 9.00000
Oups, it begins with 0., and you wanna 1. to be the first element. Easy:
IDL> x = x+1
IDL> print,x
1.00000 2.00000 3.00000 4.00000 5.00000 6.00000
7.00000 8.00000 9.00000 10.0000

You can extract a part of an array, let say the 4th to the 7th elements of vec1 (the arrays be-
gin with the index = 0):
IDL> print,vec1[3:6]
4 3 2 3
The version 5.0 of IDL recommends to use [ ] instead of ( ) for the arrays.
You can also extract part of an image. The * (star) symbol means all the (remaining) elements
in the considered dimension.
IDL> sub_image = image1[101:400,101:400]
IDL> help,sub_image
SUB_IMAGE FLOAT = Array[300, 300]
IDL> spectr = image1[245,*]
IDL> help,spectr
SPECTR FLOAT = Array[1, 512]
IDL> help,image1[200:*,200:*]
Tip: The spectr here is a 2D array, with only 1 column. If you want to have a 1D vector, you
have to reform it:
IDL> spectr = reform(spectr)
IDL> help,spectr
SPECTR FLOAT = Array[512]
This is not the case for the row vectors, compare:
IDL> help,image1[0,*]
IDL> help,image1[*,0]

If you want to compare 2 arrays, you can always overplot them on the same plot, but you can-
not, for ex., subtract one to the other unless you rebin them:
IDL> x1 = findgen(200)/199.
IDL> y1 = x1^2
IDL> x2 = findgen(3000)/2999.
IDL> y2 = x2^(2.1)
IDL> plot,x1,y1
IDL> oplot,x2,y2
IDL> y2_bis = interpol(y2,x2,x1)
IDL> help,x1,y1,y2,y2_bis
IDL> plot,x1,y1-y2_bis
see also interpolate.

There is a lot of operations on arrays, have a look to the manual. The last one presented here
will be total.:
IDL> proj1 = total(image1,1)
IDL> proj2 = total(image1,2)
IDL> grand_total = total(image1)
Here the proj1 and proj2 are vector resulting of the sum of the image1 on the x and y axis re-
spectively. It can be seen as a projection along a direction. You can normalize it by:
IDL> proj1 = total(image1,1) / (size(image1))[1]
IDL> proj2 = total(image1,2) / (size(image1))[2]
The grand_total is the sum of all the elements of image1. The mean of the array is:
IDL> mean = total(image1) / n_elements(image1)
But can also be obtained by:
IDL> print,moment(image1)
0.500508 0.0832250 -0.00195926 -1.19825
The first element is the mean:
IDL> print,(moment(image1))[0]
0.500508

Here follow the commands operating on arrays:


CONGRID Resample image to any dimensions.
DEFROI Define graphical region-of-interest.
DIGITAL_FILTER Calculate coefficients of a non-recursive digital filter.
DILATE Morphologic dilation operator.
ERODE Morphologic erosion operator.
EXPAND Magnify an image.
EXTRAC Return subarray of input array. Note that array operators (e.g., *
and :) should usually be used instead.
HILBERT Construct a Hilbert transform.
HIST_EQUAL Histogram equalize an image.
HISTOGRAM Compute density function of array.
INTERPOL Linear interpolation for vectors.
INTERPOLATE Return an array of interpolates.
INVERT Compute inverse of a square array.
KRIG2D Interpolate points using kriging.
LABEL_REGION Label regions (blobs) of a bi-level image.
LEEFILT Lee filter for images.
MAX Return the maximum element of an array.
MEDIAN Median function and filter.
MIN Return the minimum element of an array.
POLY_2D Polynomial image warping.
POLYWARP Determine coefficients for polynomial image warping.
RDPIX Interactively read and display image pixel values.
REBIN Resample array by integer multiples.
REFORM Change array dimensions without changing contents.
REVERSE Reverse vectors or arrays.
ROBERTS Roberts edge enhancement.
ROT Rotate array by any amount.
ROTATE Rotate array by multiples of 90 degrees and/or transpose.
SEARCH2D Find "objects" or regions of similar data within an image.
SEARCH3D Find "objects" or regions of similar data within a volume.
SHIFT Shift array elements.
SIZE Return array size and type information.
SMOOTH Smooth with a boxcar average.
SOBEL Sobel edge enhancement.
SORT Sort array contents and return vector of indices.
THIN Obtain the "skeleton" of a bi-level image.
TOTAL Sum array elements.
TRANSPOSE Transpose array.
UNIQ Return subscripts of unique array elements.
WARP_TRI Warp an image using control points.
WHERE Return subscripts of non-zero array elements.
XVAREDIT Widget-based editor for arrays.

Matrix Operations

A matrix is just a step away from 2d array. For multiplication of matrices, an operator # is used.
Thus the matrix product c of two matrices a and b is c=a##b or c=a#b, depending upon whether the
format of matrices is row-major (i.e., specify row then column when identifying an element) or
column-major.

For row-major convention, use c=a##b and for column-major convention c=a#b
Transpose(a) shall give transpose of matrix a.
Determ(float(a)) gives the determinant of a.
Invert(a) shall invert the matrix a.

Row-major format is transpose of column-major format. Matlab+C follow column-major(Ar,c) and


IDL+Fortran use row-major(Ac,r) formats.

IDL’s matrix conventions seems annoying for matrix math but is good for image processing where
images are scanned row-by-row, as in the TV.

Entering matrix elements

a matrix can be constructed from vectors,

IDL> A = [[0, 1, 2],[3, 4, 5] ,[5,6,7]]


For v1=[1,2,3], v2=[4,5,6], v3=[7,8,9],
V=[[v1],[v2],[v3]]

A matrix (a 2-dimensional array) may be defined algorithmically:

IDL> A = dblarr(2, 4)
IDL> for i = 0, 1 do begin $
IDL> for j = 0, 3 do begin $
IDL> a(i, j) = 10 * i + j
IDL> print, A

0.0000000 10.000000
1.0000000 11.000000
2.0000000 12.000000
3.0000000 13.000000

Note that as it is printed, the first index corresponds to the column, and the second index to the row.
Another way to think of it is that the way the data is stored, the first index varies fastest, and the second
varies the slowest. This agrees with the way the data is printed.
The WHERE function can be extremely useful. Play around with it.

IDL> b = [1, 2, 3, 4, 5, 6, 7, 8]
IDL> PRINT, WHERE( b GT 2 AND b le 7)
2 3 4 5 6

Watch out, the results of the WHERE function 2-D arrays are confusing, because they return single-
valued indices, but they work. (Continuing from the previous example:)

IDL> print, WHERE(A GT 10 AND A LT 13)


3 5
A matrix may be constructed explicitly from vectors:
IDL> v1 = [1, 2, 0]
IDL> v2 = [1, 0, 0]
IDL> v3 = [4, 5, 6]
IDL> A = [[v1], [v2], [v3]]
IDL> print, A
1 2 0
1 0 0
4 5 6

Create the transpose:

IDL> Atrans = transpose(A)


IDL> print, Atrans
1 1 4
2 0 5
0 0 6

Take the determinant:

IDL> d = determ(float(A))
% Compiled module: DETERM.
IDL> print, d
-12.0000

Invert:

IDL> Ainv = invert(A)


IDL> print, Ainv
0.00000 1.00000 0.00000
0.500000 -0.500000 0.00000
-0.416667 -0.250000 0.166667

Multiply vectors by matrices:

IDL> v = [1, 2, 3]
IDL> print, A
1 2 0
1 0 0
4 5 6
IDL> print, v
1 2 3
IDL> print, A ## v
5
1
32
IDL> print, v ## A
15 17 18

You can solve a linear system Ax = b for x by Cramer's rule (the cramer function expects float or
double inputs, requiring an explicit type conversion):

IDL> b = float([1, 2, 16])


IDL> A = float(A)
IDL> x = cramer(A, b)
IDL> print, x
2.00000 -0.500000 1.75000

Operators

< and > operators

If a and b are two arrays then the statement c=(a<b) sets the new array c equal to either a or b,
whichever is smaller. Ditto for >, except its whichever is larger.

IDL> b=[4,5,7,8,10,11]

IDL> c=[5,3,2,9,11,10]

IDL> a=b>c
(b and c are compared element-by-element and greater values are put into a)
IDL> print,a

5 5 7 9 11 11

IDL> d=b>5
(b and 5 are compared element-by-element and greater or equal values are put into d)
IDL> print,d

5 5 7 8 10 11

IDL> e=b>10

IDL> print,e

10 10 10 10 10 11

IDL> f=b<c
(b and c are compared element-by-element and smaller values are put into f)
IDL> print,f

4 3 2 8 10 10

For example, to restrict the range of array a from -1 to +1, plot, a<1>(-1)

The < and > symbols will perform a min and max on a table, useful if you have to take the log
of a table where negative values could be:
IDL> print,sin(tab1)
0.997495 0.909297 0.141120
0.909297 0.141120 -0.756802
0.656987 0.412118 0.00000
IDL> print,alog(sin(tab1))
-0.00250815 -0.0950831 -1.95814
-0.0950831 -1.95814 -Inf
-0.420092 -0.886444 -Inf
% Program caused arithmetic error: Floating divide by 0
% Program caused arithmetic error: Floating illegal operand
Here we will substitute all the value lower than 0.0001 by 0.0001:
IDL> print,sin(tab1) > 0.0001
0.997495 0.909297 0.141120
0.909297 0.141120 0.000100000
0.656987 0.412118 0.000100000
Now we can take the log of the table, without errors (but you have to deal with the -9.12... val-
ue.):
IDL> print,alog(sin(tab1) > 0.0001)
-0.00250815 -0.0950831 -1.95814
-0.0950831 -1.95814 -9.21034
-0.420092 -0.886444 -9.21034
We can choose to work on a subset of tab1, where the values are > 0., see next Chapter about the
"where" function.

Relational Operators

The statement c=(a eq 5) sets the array c equal to 1 where the elements of a are equal to 5 and zero
elsewhere. In place of eq, we can write ne, lt or gt.

If a consists of angles that are in the range 0 to 2pi and we want to convert them to -pi to +pi,

c=a – 2*!pi*(a gt !pi)

Where Statement

In array a if we want to find the indices where the elements are greater than 10, then
indices = where(a gt 10,count) and b=a[indices] shall give only those elements that are greater than
10. Here count gives the number of instances when the condition “a gt 10” has been met. “count” is
optional.

IDL> b=[4,5,7,8,10,11]

IDL> x=where(b GT 4,count)

IDL> print,count
5

IDL> print,x
1 2 3 4 5

IDL> print,b(x)
5 7 8 10 11

IDL> y=where(b GT 10,count)


IDL> print,y
5
IDL> print,count
1

IDL> print,b(y)
11

Les chaînes de caractères

a = ‘Voici une chaine’ définit une chaîne de caractères

a = ’’ est une chaîne le longueur nulle

a = b + c effectue la concaténation des deux chaînes a et b

a = strarr(dim) définit un vecteur de chaînes de caractères de dimension dim

len = strlen(a) renvoie la longueur de la chaîne de caractères a

a = strupcase(a) convertit la chaîne a en majuscules

pos = strpos(a,b) renvoie la position de la sous chaîne b dans la chaîne a ; si b n’est pas

une sous chaîne de a, on obtient –1

b = strmid(a, n, len) extrait len caractères de la chaîne a à partir de la position n. Le

premier caractère de a est en position n=0.

Strput,a,b,pos place la chaîne de caractères b à la position pos dans la chaîne a en

écrasant ce qui peut exister en dessous. Le premier caractère de a est en position 0.

a = strtrim(a) élimine tous les caractères blancs inutiles en fin de chaîne

Curve Fitting
The program fit_y.pro reads in a set of 10 y values. It creates 10 x values from 0 to 9 suing the
"findgen" command. It then fits a cubic to the data, and plots the original data as points, and the fitted
function as a curve.

N = 10
y = fltarr(N)
openr, 1, 'ex_y.dat'
readf, 1, y
close, 1
print, 'print y'
print, y
print, 'another way to print y'
for i=0, N-1 do begin
print, y(i)
endfor
plot, psym=1, y
x =findgen(N)
ypoly = poly_fit(x, y, 3) (For degree, we can put deg instead of 3)
print, 'coefficients of third degree fit'
print, ypoly
yapprox = ypoly(0) + ypoly(1)*x + ypoly(2)*x^2 +
ypoly(3)*x^3
print, 'values of fit at corresponding x values' print,
yapprox oplot, yapprox
end

The program fit_xy.pro reads in a set of 10 (x,y) pairs, into a 2 x 10 array. It separates them into two 1-
dimensional arrays, and fits a cubic to it, and plots this as in the preceding example.

; File: fit_xy.pro
N = 10
xy = fltarr(2,N)
openr, 1, 'ex_xy.dat'
readf, 1, xy
close, 1
x = xy(0,*)
y = xy(1,*)
print, 'x'
print, x
print, 'y'
print, y
plot, psym=1, x, y
ypoly = poly_fit(x, y, 3)
yapprox = ypoly(0) + ypoly(1)*x + ypoly(2)*x^2 + ypoly(3)*x^3
print, 'yapprox'
print, yapprox
oplot, x, yapprox
end

Programs
When typing interactively and running in batch mode, each line is executed immediately. A problem
arises with control statements that span lines. Consider the following simple computation of the factori-
al function. As a batch file it would look like:
f = 1
for k=1,6 do begin $
f = k * f & $
print, f & $
end
The commands must be separated by ampersands "&", and the lines must be continued. The entire loop
must essentially be on one line, since each line is executed as soon as it is encountered. Imagine nested
loops with long calculations inside.
As a program it is somewhat simpler:
f = 1
for k=1,6 do begin
f = k * f
print, f
endfor
end

To execute an IDL program, we type .run filename or .r filename at the IDL prompt.

Reading and Writing Data


Here is a list of supported formats

Image Formats
IDL includes routines for reading and writing many standard graphics file formats. These routines and
the type of files they support are listed below.

BMP GEO TIFF Interfile


JPEG NRIF PICT
PNG PPM SRF
TIFF XWD X11 Bitmap
Scientific Formats
There are four scientific data formats supported by IDL:

CDF HDF
HDF-EOS netCDF

Other Formats

ASCII Binary DICOM


DXF WAV XDR

Reading ASCII files

If

Purpose: Conditionally execute a statement.


Syntax:
if expression then statement
if expression then statement1 else statement2
Examples:
if y lt 0 then t=2
if y lt 0For
Notes: then t=2 else t=3
complicated expressions parentheses may be used to make sure expression
if y lt 0 then begin
has thet=2
desired meaning.
txt='Negative'
endif
if y lt 0 then begin
For Loops
t=2
txt='Negative'
Purpose:
endif Repeat a statement a specified number of
else begin times.
Syntax: for variable = init, limit, step do statement
t=3
txt='Non-negative'
Examples:
forendelse
i=0,9 do print,i
Notes: The0.01,
for t=1.0, loop variable has the same data type as the initial value (init above). Make sure
-.01 do plots,x*t,y*t
if ((x
to use gt
forthe -2) and (x lt
correctn,data
ix=0L, 3)) and
10 type ((ythe
for
do begin gt initial
5) andvalue.
(y lt 8)) then t=2 error is: for t=0,1,.1 do ... which
A common
x(j) = xx(ix)
gives an infinite loop since .1 added to an integer variable does nothing. This is easily fixed:
j = j+1
t=0.,1,.1 (note the 0. instead of 0). Another common error is not forcing a loop variable to be
print,ix
a long integer
endfor when the loop can go above 32767. The fix is: for i=0L,...
A for loop may be executed 0 times if the loop variable starts beyond the loop limit.
While Loops

Purpose: Repeat a statement while some condition is true.


Syntax: while expression do statement
Examples:
while x gt 0 do x=x-1
Notes: A while
while statement do
not eof(lun) may be executed 0 or more times depending on the value of the
begin
readf,lun,txt
expression.
print,txt
endwhile
Repeat Loops

Purpose: Repeat a statement until some condition is true.


Syntax: repeat statement until expression
Examples:
repeat x=x-1 until x le 0
Notes: A repeat
repeat beginstatement is always executed at least once.
readf, lun, x
Case x = x-c
endrep until x le 0

Purpose: Selectively execute a statement based on the value of an expression.


Syntax:
case expression of
expression: statement
. . .
expression: statement
else: statement
endcase
Examples:
case animal of
'cat': print,'meow'
'dog': print,'arf arf'
Goto
'bird': print,'tweet tweet'
else: print,'??'
Purpose: endcase
Jump to a specified label in a routine.
Syntax: goto,
caselabel
t>0<2 of
0:
Examples: begin
. . txt
. = 'red'
loop:May only be= used
Notes:
err 0
in routines. Program flow jumps to the specified label. If label
end
. . .
does
1: not occur in
begin the routine a compile error results.
goto, loop
. . txt
. = 'green'
goto,err = 0
err
Common . . .end
2:
err: begin Error ...'
print,'
. . txt
. = 'blue'
Purpose: Shareerrvariables
= 1 between routines or remember values between calls to a routine.
Syntax: common
end name, variable_1, variable_2, . . . variable_n,
endcase
name is the name of the common block. Variables are matched by position so need not
have the same name in each routine.
Examples:
common xkodak_com, x, y, dx, dy, file, count
common
Notes: random_plot_com,
A single seed
routine may use a common to save the value of a variable between calls.
Some examples of where this is useful: to remember default values, to remember a seed
value for the randomu (or randomn) function since the system clock is used if no seed is
given and for fast computers the same seed may be used for several calls.
Several routines may use a common to share status values. In such cases it is useful to
store the common in a separate file and include it in each routine (@filename where @ is in
column 1). This way only a single copy of the common need be maintained.
A good way to name commons is to use the main routine name followed by _com, like xko-
dak_com. This helps prevent the accidental use of the same name for diffrent commons.

Procedure definition

Purpose: Specify a procedure name and parameters.


Syntax: pro name, parameter_1, parameter_2, ... parameter_n
name is the name of the procedure.
Examples:
pro test, a, b, c
pro compute,
Notes: x, y, z,
A procedure flag=flg,
must help=hlp
end with an end statement and may have one or more return
statements inside. If program flow reaches the final end statement a return is implied.
Example calls to the above procedures:
test, 2, 3, out
compute, x, y, z, /flag

Function definition

Purpose: Specify a function name and parameters.


Syntax: function name, parameter_1, parameter_2, ... parameter_n
name is the name of the function.
Examples:
function test, a, b, c
function
Notes: compute,
A function x, y,end
must z, flag=flg, help=hlp
with an end statement and must have one or more return
statements inside. A return statement in a function must include the return value: return,
value.
Example calls to the above procedures:
a = test(2, 3, 5)
t = compute(x, y, z, /flag)
External libraries
The popularity of IDL made it a development language in a lot of domains (Medical imaging,
Meteorology, and Astronomy). It's possible to download some free packages and use it to, for
example, analyze spectra of IUE or images of HST.
In the normal use, IDL doesn't know where the libraries are. You have to add the location
path to the set of path in witch IDL will look for procedures files.
The WWW address where those package are available are in the second part of the refer-
ences .
The Add_path command

To have access of the list of those package (only at IAG, ask your system manager to install
them if needed, a copy of our add_path is here ) , just do:
IDL>add_path,/help
In this example, there are 15 different libraries available. If you have to use both the astro and
the esrg libraries, do:
IDL>add_path,/astro,/esrg,/verbose
/usr/local/rsi/idl_5/lib/hook:/usr/local/rsi/idl_5/lib/obsolete:/usr/lo [...]
Using the /verbose keyword, IDL print all the searching paths, including the new added ones.
The astro package allows you to work with fits files, to transform coordinates, to unred obser-
vational data, etc.
With the esrg library, you can use the tvim and confill procedures to display images.
You can also add a personal path, using the path='my_IDLdirectory' keyword.
All those package are in the directory /usr/local/rsi/contrib/Just have a look at them.
Help in the contrib packages

The procedures accessible with the external packages don't have help pages in the idlhelp
hypertext help tool. Anyway, most of them have a documentation in the header of the proce-
dures files themselves that you can access under idl.
IDL>add_path,/astro
IDL>doc_library,'fits_read'
----- Documentation for /usr/local/rsi/contrib/astro/pro/fits/fits_read.pro -----
*NAME:
FITS_READ
*PURPOSE:
To read a FITS file.
*CATEGORY:
INPUT/OUTPUT
*CALLING SEQUENCE:
FITS_READ, filename_or_fcb, data [,header, group_par]
*INPUTS:
FILENAME_OR_FCB - this parameter can be the FITS Control Block (FCB)
returned by FITS_OPEN or the file name of the FITS file. If
[...]

Init file
There is an init file, which is read at each start of IDL, and which location is in the
IDL_STARTUP environment variable (defined in the .login, or .tcshrc file)
Here is an example of an init file:

defsysv,'!edit_input',100
;
;
defsysv,'!path',!path+':'+expand_path('+~/IDL')
;
; Definition du symbole Angstrom
;
angstrom = STRING(197B)
;
; Definition de true et false
;
defsysv,'!true',1b
defsysv,'!false',0b
;
; pour qu'idl s'occupe du backing store
;
DEVICE, RETAIN=2
;
device,decomposed=0,true_color=24,BYPASS_TRANSLATION=1
;
; Keys definitions
setup_keys
define_key, 'f1', 'print,'
define_key, 'f2', 'plot,'
define_key, 'f4', 'retall',/term

define_key, 'f5', 'help',/term


define_key, 'f6', 'help,/str,'
define_key, 'f7', 'help,/mem',/term

define_key, 'f9', '.r main',/term


;
; Define some colors
;
my_colors
;
;
; Define some constants
;
phyat_cst
;
;
print," VOICI LA LISTE DES PROGRAMMES UTILES..."
$ls *.pro *.sav *.xdr
print," Don't forget @mon_journal"

!d subscript
!u superscript
!e superscript (small size)
!i subscript (small size)
!n coming back to normal

!4 gives greek letters


!3 returns to english

Note that a window (IDL 0) was created. You can create multiple plotting windows using IDL,
and move between them easily. See online help for details on how to modify their default
sizes, title bars, positions, etc.

IDL> window,0 & plot,x,y ; ampserand used to separate commands on the same line

IDL> window,1 & plot,x,y*y ; create new window and make a plot

IDL> wset, 0 & plot,x,x^2 ; go back to the first window and make a new plot

IDL> set_plot,'ps' ;set postscript device

IDL> device, /landscape, filename = 'yourname.plot1.ps' ;e.g. monnier.plot1.ps

IDL> plot,x,y,xtitle='xlabel',ytitle='ylabel',title='Your Title Here'

IDL> device,/close ; close the postscript device... Did it create a good file??

IDL> set_plot,'win' ; for windows machine -- or set_plot,'x' ; for xwindows (linux/solaris)

IDL> print,systime()
Sat Nov 29 19:55:10 2008

IDL> print,factorial(4)
% Compiled module: FACTORIAL.
24.000000

IDL> print,factorial(3)
6.0000000

IDL> print,alog10(100)
2.00000

IDL> print,alog10(10)
1.00000

IDL> print,alog10(1000)
3.00000

IDL> data_template = ascii_template()


IDL> data = read_ascii(template = data_template, header=header) ; you will have to choose
data1.txt again

; NAME:
; ex01_fonctions_usuelles
;
; PURPOSE:
; formation IDL du 20-Mar-2000
; fonctions_usuelles
;
; PROCEDURE:
; SIN, COS, TAN, EXP, ALOG, ALOG10, MOD, ROUND, CEIL, FLOOR
;
; EXAMPLE:
;
;
; MODIFICATION HISTORY:
; 17-Mar-2000 Written H. Dole, Herve.Dole@ias.fr
;-

PRO ex01_fonctions_usuelles

LOADCT_PLOT

; TRIGONOMETRIC FUNCTIONS
;------------------------
x1 = 45. * !DTOR
PRINT, sin(x1), cos(x1), tan(x1)

x2 = 30. * !pi / 180.


PRINT, sin(x2), cos(x2), tan(x2)

x3 = FINDGEN(500)/ 500. * 2. * !pi


plot, x3, sin(x3), title='SIN and COS functions', thick=2
oplot, x3, cos(x3), line=2, thick=2

; EXP AND LOG FUNCTIONS


;----------------------
PRINT, exp(5.), alog(5.), alog10(5.)

x4 = FINDGEN(500)/500. * 10.
PLOT, x4, exp(x4), title='Exponential, linear scale', thick=2
PLOT, x4, exp(x4), /yl, title='Exponential, log scale', thick=2

plot, x4, alog(x4), title='Natural logarithm, and base 10 log, linear scale',
thick=2
oplot, x4, alog10(x4), color=1, thick=2

oplot, x4, alog10(x4) / alog(x4), thick=2, color=2


PRINT, 1./alog(10.)

; POWER FUNCTIONS
;----------------
x5 = (FINDGEN(500) - 250.) / 250. * 2.
plot, x5, x5 ^ 3., thick=2
oplot, x5, x5 ^ 2., color=1, thick=2
oplot, x5, x5 ^ 0.5, color=3, thick=2

; MODULO
;-------
PRINT, 5 MOD 2
PRINT, 151 MOD 50

; ROUND
;------
PRINT, ROUND(5.499), ROUND(5.501)
PRINT, CEIL(5.499), CEIL(5.501)
PRINT, FLOOR(5.499), FLOOR(5.501)
END

;+
; NAME:
; ex02_fonctions_usuelles
;
; PURPOSE:
; formation IDL du 20-Mar-2000
; fonctions_usuelles: stats
;
; PROCEDURE:
; MIN, MAX, MEAN, MOMENT, RANDOMU, DIST, SHIFT
;
; EXAMPLE:
;
;
; MODIFICATION HISTORY:
; 17-Mar-2000 Written H. Dole, Herve.Dole@ias.fr
;-

PRO ex02_fonctions_usuelles

; CREATE X VECTOR
;----------------
x = (FINDGEN(1000) - 500. ) /500. * 10.
PLOT, x, thick=2

; CREATE GAUSSIAN
;----------------
sigma = 2.
gaussian = 2.*exp(-x^2./(2.* sigma^2.))
plot, x, gaussian, thick=2, title='gaussian'

; STATISTICAL FUNCTIONS
;----------------------
PRINT, min(gaussian), max(gaussian), mean(gaussian)

HELP, MOMENT(gaussian)
PRINT, MOMENT(gaussian)

; moment: mean, variance, skewness, kurtosis

; ADD NOISE
;----------
; RAMDOMU: Uniform Distrib
noise = RANDOMU(seed, 1000)
PLOT, noise, thick=2
PLOT, gaussian + noise, thick=2, title='noisy gaussian'

; DIST
;-----
a1 = DIST(500,500)
winidl, a1, ct=5

a2 = SHIFT(DIST(500,500), 250, 250)


winidl, a2, ct=5, ws=2

END

;+
; NAME:
; ex03_matrix
;
; PURPOSE:
; formation IDL du 20-Mar-2000
; fonctions_usuelles: stats
;
; PROCEDURE:
;
;
; EXAMPLE:
;
;
; MODIFICATION HISTORY:
; 17-Mar-2000 Written H. Dole, Herve.Dole@ias.fr
;-

PRO ex03_matrix

; OPEN AN ARRAY: 600*600


;------------------------
RESTORE, !FIRBACK_DATA_DIR + 'map_piav722/map_Marano_10.00.save', /ver
image = map/weightno0
winidl, image>stat(0)<stat(1), ct=5

PRINT, size(image)

; TRANSPOSE
;----------
winidl, transpose(image)>stat(0)<stat(1), ct=5, ws=1

; ROT
;----
winidl, rot(image, 45.)>stat(0)<stat(1), ct=5, ws=1
winidl, rot(image, 90.)>stat(0)<stat(1), ct=5, ws=1
winidl, rot(image, 135.)>stat(0)<stat(1), ct=5, ws=1
winidl, rot(image, 180.)>stat(0)<stat(1), ct=5, ws=1
winidl, rot(image, 225.)>stat(0)<stat(1), ct=5, ws=1
winidl, rot(image, 270.)>stat(0)<stat(1), ct=5, ws=1

; TOTAL
;------
PRINT, total(image)

; TRACE
;------
PRINT, trace(image)
END

;+
; NAME:
; ex04_polyfit
;
; PURPOSE:
; formation IDL du 20-Mar-2000
; fit
;
; PROCEDURE:
;
;
; EXAMPLE:
;
;
; MODIFICATION HISTORY:
; 17-Mar-2000 Written H. Dole, Herve.Dole@ias.fr
;-

PRO ex04_polyfit

LOADCT_PLOT

; X ARRAY
;--------
x = (FINDGEN(1000)-500.)/500. * 15.

; Y ARRAY: ORDER 1
;----------------
n0 = -10.
n1 = 5.

y1 = n0 + n1 * x
PLOT, x, y1, xtitle='x', ytitle='y1', title='y1 as a function of x', psym=3,
thick=2

; ADD NOISE
;-----------
noise1 = (RANDOMU(seed, N_ELEMENTS(x)) -0.5) * 40.
y1noise = y1 + noise1
PLOT, x, y1noise, xtitle='x', ytitle='y1', title='y1 + noise as a function of x',
psym=3, thick=2

; FIT
;----
NDegree = 1

Result1 = POLY_FIT(X, Y1noise, NDegree, Yfit, Yband, Sigma, Corrm )


PRINT, result1
oplot, x, result1(0) + result1(1)*x, color=1, thick=2

; Y ARRAY: ORDER 2
;-----------------
n0 = -10.
n1 = 5.
n2 = 2.
y2 = n0 + n1 * x + n2 * x ^ 2.
PLOT, x, y2, xtitle='x', ytitle='y2', title='y2 as a function of x', psym=3,
thick=2

; ADD NOISE
;-----------
noise2 = (RANDOMU(seed, N_ELEMENTS(x)) -0.5) * 150.
y2noise = y2 + noise2
PLOT, x, y2noise, xtitle='x', ytitle='y2', title='y2 + noise as a function of x',
psym=3, thick=2

; FIT
;----
NDegree = 2

Result2 = POLY_FIT(X, Y2noise, NDegree, Yfit, Yband, Sigma, Corrm )


PRINT, result2
oplot, x, result2(0) + result2(1)*x + result2(2)*x^2., color=1, thick=2

END

Reading a datafile

pro read_plot_modtran

;+
;Reads and plots modtran data from a particular file pldat.dat
;Hugh Pumphrey (a long time ago) modified by John Marsham (11/04/2005)
;-

;;;;;; Set up array to contain the data ;;;;;;;;;;;;;;;


modtrandata=fltarr(14,201)

;;;;;; Open the file, attach it to unit no. 1 ;;;;;;;;;


openr,1,'/nfs/env-fs-04_u35/jmarsham/public_html/Teaching/IDL_course/pldat.dat'

;;;;;; read the data from the file attached to unit 1 ;;;;;;;
;;;;;; into the array modtrandata
readf,1,modtrandata
;;;;IF THE DATA WAS BINARY YOU'D USE READU;;;;;

;;;;;; Close the file ;;;;;;


close,1

;;;;;; Now make the plot ;;;;;;


plot,modtrandata(1,*),modtrandata(11,*), $ ;First col plotted against 11th col
xtitle='Wavelength (microns)',$
ytitle='Radiance (Watts/(cm!U2!N Steradian Micron))'

;;;;;; Don't forget the 'end' statement ;;;;;;


end

Note that we have to know in advance how many rows and columns there are in the file.

Here is an example (modtran_while.pro) It is the modtran plotting program again, but this time we
don't need to know the number of lines in advance. The program reads a line at a time, stopping when it
reaches the end of the file. We put the data into an array which starts off with more lines than we are
likely to need. (Don't make the array big enough for ten million lines, though - you'll fill up the com-
puter's memory!) Once we reach the end of the file, we truncate the data array to the length of the file.
;Set up array with far too many rows to contain the data
modtrandata=fltarr(14,5000)

openr,1,'/nfs/env-fs-04_u35/jmarsham/public_html/Teaching/IDL_course/pldat.dat'

inputline = fltarr(14) ; set up a variable to hold one row of the file


linecount=0 ; variable to count lines

;;;; start while loop to read in the data


while not eof(1) do begin ; eof becomes true when we reach the End Of
; the File.
readf,1,inputline
modtrandata(*,linecount)=inputline
linecount=linecount+1

endwhile
modtrandata=modtrandata(*,0:linecount-1) ; truncate array to actual length
; of file.
close,1

OR (modtran_while2.pro)

openr,1,'/nfs/env-fs-04_u35/jmarsham/public_html/Teaching/IDL_course/pldat.dat'

inputline = fltarr(14) ; set up a variable to hold one row of the file


linecount=0 ; variable to count lines

;;;; start while loop to read in the data


while not eof(1) do begin ; eof becomes true when we reach the End Of
; the File.
readf,1,inputline
if linecount eq 0 then modtrandata=inputline else modtrandata=[[modtrandata],
[inputline]]
linecount=linecount+1

endwhile
modtrandata=modtrandata(*,0:linecount-1) ; truncate array to actual length
; of file.
close,1

eof(unit)

example,

; Open the file test.lis:


OPENR, 1, 'test.lis'
; Define a string variable:
A = ''
; Loop until EOF is found:
WHILE ~ EOF(1) DO BEGIN
; Read a line of text:
READF, 1, A
; Print the line:
PRINT,
ENDWHILE
; Close the file:
CLOSE, 1

Saving your graph.


It's great to have plots on the screen, but you will often need to get them on paper to include in reports
etc. IDL treats the screen as one device and a postscript file (which you can print) as another. You can
switch devices with the set_plot command:
IDL> set_plot,'ps'

will switch to postscript output and

IDL> set_plot,'x'

will switch back to the screen. The device command allows you to do various things to control which
postscript file your output goes to, how big your plot will appear, and so on. If you want a .png, .jpeg
etc file for powerpoint, word, animations etc the easiest thing to do is plot it in a graphics window,
using
IDL> set_plot,'x'

then read it to file using


IDL> filename='~username/blah.png'
IDL> write_png,filename,tvrd()

Alternatively, use
IDL> set_plot, 'z'
IDL> device, set_resolution=[640,680]
IDL> plot, x, y etc...
IDL> write_png, 'filename.png',tvrd()
Here is the program to plot modtran output, with extra lines added so that it will put the plot in a post-
script file called modtran.ps .
;;;;;; Set up array to contain the data ;;;;;;;;;;;;;;;
modtrandata=fltarr(14,201)

;;;;;; Open the file, attach it to unit no. 1 ;;;;;;;;;


openr,1,'/nfs/env-fs-04_u35/jmarsham/public_html/Teaching/IDL_course/pldat.dat'

;;;;;; read the data from the file attached to unit 1 ;;;;;;;
;;;;;; into the array modtrandata
readf,1,modtrandata

;;;;;; Close the file ;;;;;;


close,1

;;;;; switch to postscript output ;;;;;;;


set_plot,'ps'
;;;;; set the name of the output file (if you dont set it, it is
;;;;; called idl.ps)

device,file='modtran.ps'

;;;;;; Now make the plot ;;;;;;

plot,modtrandata(1,*),modtrandata(11,*), $
xtitle='Wavelength / microns',$
ytitle='Radiance in Watts/(cm!U2!N Steradian Micron !4l!3m)'

;;;;;; Close the postscript file (important. The last bit of your plot
;;;;;; wont appear unless you do this

device,/close

;;;;; switch back to X Window system ;;;;;;;

set_plot,'x'

;;;;;; Don't forget the 'end' statement ;;;;;;

end

Note also the use of


device,file='~jmarsham/modtran.eps',/encapsulated

Here the general rule of using ``backslash'' keyword being equivalent to keyword=1 e.g.
\encapsulated
Note the !U or !E which gives you the superscript. !B gives you subscript. !4 gives you Greek and !3
returns you to English. So,

plot,modtrandata(1,*),modtrandata(11,*), $
xtitle='Wavelength (!4l!3m)',$
ytitle='Radiance (W/(cm!U2!N Steradian !4l!3m))'
should give you microns.
And that's it for the first session. You can now make most of the 2-D graphs that you will need. In the
next session we'll look at some more sophisticated programming techniques.

Purpose IDL C FORTRAN


Relational Operators
Equal to eq == .EQ.
Not equal to ne != .NE.
Less than or equal to le .LE.

Less than lt .LT.

Greater than or equal to ge = .GE.

Greater than gt .GT.


Boolean Operators
And and && .AND.
Not not ! .NOT.
Or or || .OR.
Exclusive OR xor

IDL> an_array=[3, 5, 6, 2.5, 100, 27.7]

Note that we have mixed up floats and integers in this expression; IDL will coerce all the
integers to floats if there are any floats at all. If you define an array using integers only then
IDL will leave them as integers.

You can refer to individual elements of the array like this:

IDL> print,an_array[0],an_array[2]
3.00000 6.00000

You can refer to a subset of the array like this:


print,an_array[3:5]
2.50000 100.000 27.7000
IDL> array_2d= [[ 2,3,4],[10,20,30]]; 3 columns , 2 rows

... and refer to parts of it like this:

IDL> print,array_2d[0,1]
10
IDL> print,array_2d[1:2,1]
20 30
IDL> print,array_2d[2,*]
4
30
The IF statement
This is used when you want to do something if a condition is true and something else otherwise. The
statement looks like this:
if condition then statement 1 else statement 2

This will execute statement 1 if the condition is true and statement 2 if the condition is false. (Note that
in these descriptions of what a statement does I use typewriter font to show what you actually type
and italics to indicate where you have to put in your own stuff.) Here is an example if an `if' statement:
if i eq 2 then print,'I is two' else print, 'i is not two'
or
if i eq 2 and j eq 3 then print,'I is two and J is three' else print, 'i and j are
not two and three respectively'

If you want statement 1 and / or statement 2 to consist of more than one statement, then the if construct
looks like this:
if condition then begin
statement 1a
statement 1b
statement 1c
endif else begin
statement 2a
statement 2b
statement 2c
endelse

The statements between a begin and an end are called a block of statements. The begin and end are
analogous to the curly brackets in 'C' or Java except that the end statement has to match the thing that
comes before the begin e.g. an if .... then begin has to be matched with an endif and a else be-
gin with an endelse. Blocks of statements are used within programs, not at the IDL prompt.

The FOR loop


If you have a statement or statements that you want to repeat a number of times, you can use the FOR
statement to do so. It looks like this:
for variable = start_value , stop_value [ , increment ] do statement

( I use [ ] to indicate that increment is optional.) The variable will start at start_value and statement
will be executed over and over again, with increment being added to variable each time, until variable
reaches stop_value. If you miss out increment it is assumed to be 1.
Try these examples at the IDL prompt.
IDL> for j=0,5 do print,j
IDL> for j=0,6,2 do print,j
Just as a warning, the loop variable takes its type from the start value. This is a (short) integer in these
examples. This means that for j=0,40000 do .... will NOT do what you expect, but for
j=long(0),40000 do .... will be OK.
The WHILE loop
If you need a loop for which you don't know in advance how many iterations there will be, you can use
the `while' statement. It works like this:
while condition do statement

Again, if you are using this in a program you can replace statement with a block of statements - the
block must end with an endwhile . You can construct condition in the same way as for an if statement.

wheretomulti
There is a handy routine (wheretomulti.pro) to convert these 1d subscripts to rows, columns etc in a 2D
or 3D array (again from David Fanning). IDL 6.0 also has a new function I think, called array_indices,
which is related to this.
PRO wheretomulti, Array, Indices, Col, Row, Frame
;+
; NAME: wheretomulti.pro
;
; FUNCTION: Convert WHERE output to 2d or 3d indices
;
; USAGE: WhereToMulti, Array, Indices, Col, Row, Frame
;
; INPUT ARGUMENTS:
; Array: the array that was WHERE'd
; Indices: the indices returned by WHERE
;
; OUTPUT ARGUMENTS:
; Col: Indices to first dimension.
; Row: Indices to second dimension.
; Frame: Indices to third dimension. Returned only for 3-d array.
;
; OPTIONAL ARGUMENTS:
;
; KEYWORDS:
;
; REQUIRED MODULES:
;
; SIDE EFFECTS:
;
; ERROR HANDLING:
; If Array is not a vector or matrix, all return values are set to zero
; and a message is written to the screen.
;
; NOTES:
;
; HISTORY:
; 1998 Sept 15 J.L.Saba Developed based on code from David Fanning's
; web site.
;
;- End of prologue -------------------------------------------------------------

;Find size of input array


s = SIZE ( Array )
;Size returns n_dimesnions, size_dimension(1), size_dimension(2) etc
;Size returns 0 dimensions if the variable does not exist.

;Number of columns of array =s[1]


NCol = s[1]

;The keyword MOD is the modulo operator. I MOD J is equal to the


;remainder when I is divided by J.
;Col(i) is column that Indices(i) refers to
Col = Indices MOD NCol
;since the indices count along the columns working up the rows

IF s[0] EQ 2 THEN BEGIN ; 2-d array


Row = Indices / NCol ;Integer/integer=integer - so wed on't get a fractional
row
ENDIF ELSE IF s[0] EQ 3 THEN BEGIN ; 3-d array
NRow = s(2)
Row = ( Indices / NCol ) MOD NRow
Frame = Indices / ( NRow * NCol )
ENDIF ELSE BEGIN ; neither 2d or 3d
Col = 0
Row = 0
Frame = 0
PRINT, 'WhereToMulti called with bad input. Array not a vector or matrix.'
HELP, Array
ENDELSE

RETURN
END

Defining functions and procedures (and scripts)


Our examples so far have been too short to break up into sub-programs. However, any sizeable IDL
project will be easier to deal with if each specific task is put into its own sub-program, which your
main program can call. Sub-programs in IDL come in two flavours: functions and procedures. The
main difference is that functions return a value and procedures don't. (This will be familiar to old FOR-
TRAN hackers like me - C people are used to having only functions.) Procedures are defined like this:
pro procedure_name,arg1,arg2..... ,keyword1=keyword1....
statement
statement
.
.
.
end
and are called like this
procedure_name,argval1,arg2..... ,keyword1=value1....
They finish on the return command, or the end command.
Functions are defined like this:
function function_name,arg1,arg2..... ,keyword1=keyword1....
statement
statement
.
.
.
return, return_value
end

and are called like this:


foo = function_name(argval1,....., keyword1=value1.... )

You don't have to have any positional arguments or any keywords. If your function or procedure is
called `smeg' you should put it on its own in a file called smeg.pro in the same directory from where
you started IDL. As you would expect, all the variables you set up within a procedure or function are
local to that sub-program. If IDL has a problem and stops within a sub-program, you will find that the
variables you can look at or print are those belonging to the sub-program. You can leave the `scope' of
the sub-program and return to the main level by typing
IDL> retall

Here is an example of a function. This calculates - note the use of if and while.

function sinc,x
;+
; This idl function calculates the function sinc(x) = sin(x)/x.
; ( Beware: some authors define sinc(x) = sin(Pi x)/(Pi x) )
; sinc(0)=1, but you cannot calculate this directly as sin(0)/0.
; This routine uses the power series
; sin(x) / x = 1-(x^2)/3! + (x^4)/5! - (x^6)/7! for small values of x
; This function only works for scalars at the moment
; INPUT, x OUTPUT: s
; Written by: Hugh Pumphrey, Edinburgh
;-

if abs(x) gt 0.1 then begin


s=sin(x)/x ; Use obvious formula if |x| > 0.1
endif else begin
j=0
s=x*0+1.0 ;make s double if x is double
term=s ;term same type as s

;; Calculate power series - stop after 20 terms or if term gets


;; very small
while j lt 20 and abs(term) gt 1.e-12 do begin
j=j+2
term=-1.0*term*x*x/(j*(j+1))
s=s+term
endwhile

endelse

return,s

end
To use this, put the text into a file called sinc.pro. If you type
IDL> .run sinc
IDL will inform you that it has compiled the function successfully. If you then type, for example,
IDL> print,sinc(0.05)

then the value of will be printed out.


There are also things called, I think, scripts. I never use them. For example open a file called
script_test.pro, somewhere where IDL can find it. Put
print,'script_test'
for i = 0,10 do print,i
in the file and save it. Type
IDL> @script_test
IDL runs it as if you had cut and pasted it into the IDL command line. As a result
print,'script_test'
for i = 0,10 do begin
print,i
endfor
won't work, because you can't use a for ... endfor statement on a single line.
To summarise, we have learned about IDL's programming features and that we should use array opera-
tions instead of loops where that is possible. In the next lecture we will learn how to display two-di-
mensional data sets and how to make use of colour in IDL

Colours in IDL

So far, everything that we have seen has come out in grey. Now we'll look at how to get things to be in
colour. Before looking at colours in IDL, we'll cover briefly how colours are done on computer
monitors in general. Each pixel on the screen is made up of three colours: red, green and blue, each of
which is represented by one byte and can therefore take on values between 0 (black) and 255 (as bright
as possible). There are therefore 256 cubed = 16777216 possible colours. That's why white was
256*256*256-1 (counting from zero remember) in the surface plotting example.
Some monitors (hopefully all of the ones you will use) have three bytes ( 24 bits ) of video memory for
each pixel - on such a monitor you can make any pixel any one of these 16777216 colours any time you
like. A few older monitors may have only one byte of video memory per pixel, which means that there
are only 256 colours available. You can make a pixel any of the 16777216 possible colours BUT you
can only have 256 of those colours on the screen at any one time. Hopefully you won't encounter one
of these. However as a result of this history, a lot of colour management in IDL is done via tables of
(up to) 256 colours.
I wasn't looking forward to writing this bit of the course at all! However, Jason Lander (Leeds) seems
to have worked out a system that works.
To use a 256 element colour table, such as those built in to IDL:
set_plot,'x'
device,true_color=24,decomposed=0,retain=2 ;NEW LINE
window,0,retain=2
loadct,39
tvlct,r,g,b,/get
plot,r,xtitle='Index',ytitle='Intensity'
oplot,r,color=230
oplot,g,color=150
oplot,b,color=50
oplot,[0,0],[0,0],color=0,psym=3
write_png,'~jmarsham/filename.png',tvrd(true=1),r,g,b
makes it look right on the screen and right in the file.
From the help facility ``The colormap/visual class combination is chosen when IDL first connects with
the X Window server. Note that if you connect with the X server by creating a window or using the
DEVICE keyword to the HELP procedure, the visual class will be set; it then cannot be changed until
IDL is restarted. If you wish to use a visual class other than the default, be sure to set it with a call to
the DEVICE procedure before creating windows or otherwise connecting with the X Window server.'',
so once you've set it that's it.
I think that means that you should set the ``device '' command first and then not change it.

Postscript is easier,
set_plot,'ps'
device,file='~jmarsham/filename.eps',/encapsulated,/color
loadct,39
tvlct,r,g,b,/get
plot,r,xtitle='Index',ytitle='Intensity'
oplot,r,color=230
oplot,g,color=150
oplot,b,color=50
oplot,[0,0],[0,0],color=0,psym=3
device,/close
Why does this work? Jason says:
``TrueColor'' and ``DirectColor'' visuals both represent colours as separate (R,G,B) values.
The latter allows finer control of the exact colours associated with a set of (R,G,B) indices via a second
set of look-up tables but IDL doesn't take advantage of this.
For a modern display, the IDL `X' device will pick one of the TrueColor or DirectColor visuals. Exact-
ly which depends on what the program does first and - I suspect - this doesn't matter in the slightest.
The DEVICE specifications for True and Direct Color will either treat the (R,G,B) values as either:
1. Decomposed (with the device,/decomposed) IDL treats the image as 3 separate blocks of single
byte values: one for each colour, or,
2. Combined (with device,decomposed=0) IDL treats the image as a block of 3-byte values
The former allows the window to behave as a older PseudoColor visual by using just one field.
The ``TV'' and ``TVRD'' commands are designed to take arrays of single bytes and copy them to or from a
window. This worked well for PseudoColor but is a pain for newer displays.
BUT: both ``TV'' and ``TVRD'' accept ``CHANNEL'' and ``TRUE'' flags which tell it how to handle 24-bit
displays.
We found that ``TVRD(TRUE=1)'' seems to grab bitmaps from 24-bit displays. According to the docu-
mentation, this returns a (3,nx,ny) array.
It is possible that ``TVRD(CHANNEL=1)'' would be more reliable (but I haven't got this to work - John).
IDL colourtables
IDL has a selection of about 40 built-in colour schemes. You can load the fifth one of these, for
example, by doing:

IDL> loadct,5

(as we did for colour table 39 above). To return to the default grey scale, do:

IDL> loadct,0 ; greyscale

Or a simple rainbow

IDL> loadct,39 ;rainbow 0=black, 255=white, 220ish=red, 50ish=blue

Most of these built-in schemes have colour 0 as black and colour !D.Table_size as white. It does matter
which colour table you use when plotting data. Many (eg 39 above) doesn't give good contrast in all
areas (e.g. around the greens). This leads your eye and brain to see the red/orange/yellow data as
different and the green data as all the same - misleading! I personally like one I picked up from
someone in Edinburgh (which he stole from somewhere else). See

~jmarsham/IDL/Procedures/Display/load_sst_ct.pro

if you would like to use it (see ``Colour images'' for an example).

Greyscale images

IDL has routines to read in most of the standard image formats:


File type Extension IDL routine
Microsoft Bitmap .bmp read_bmp
Portable Network Graphics .png read_png
JPEG .jpg or .jpeg read_jpeg
Macintosh PICT .??? read_pict
Portable Bit/grey/pixelmap .pbm .pgm .ppm read_ppm
Sun Raster format .??? read_srf
Tagged Image File Format .tiff or .tif read_tiff
X11 Bitmap files .xbm read_x11_bitmap
X Windows Dump (from xwd) ??? read_xwd
1
For greyscale images, most of these require a file name and return a 2-d array of type Byte, but the
syntax is not the same for all of these routines - see the manual for details. As an example, try this:
IDL>
read_jpeg,'~jmarsham/public_html/Teaching/IDL_course/200407101200_MSG1_EVEB70.jpeg'
,meteosat
This has read in a greyscale image from the file met.png and put it in a variable called Meteosat. If we
do
IDL> help,meteosat
we find that Meteosat is a 900 X 900 array of type byte. The basic command in IDL to display an
image is tv. If we do this:
tv,meteosat
then we can see the image, but there are a couple of problems. The image is not the same size as the
window and it looks a bit washed out. We can fix the first problem by shrinking the image and opening
a window of the right size - you can open a 450 X 450 pixel window like this:
IDL> meteosat=rebin(meteosat,450,450)
IDL> window,0,xsize=450,ysize=450,retain=2
This provides us a nice example for writing our own procedure to open a window of the correct size for
an image and then to display the image in it.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro showimage,image,window=window
; A short procedure to display an image in a window the same size as
; the image. The program refuses to display an image which is
; uselessly small. This is important as opening a window 0 pixels wide
; causes IDL to hang up.

; the if not keyword_set() is really useful for setting defaults for keywords
if not keyword_set(window) ne 1 then window=0

siz=size(image)
if(siz(1) gt 4 and siz(2) gt 4 ) then begin

window,window,xsize=siz(1),ysize=siz(2)
tv,image

endif else print,'Image too small'

end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Now we can display our image with:
IDL> showimage,meteosat,win=2
The image is still dark and lacks contrast in some areas though. If it was on the television, you would
turn up the contrast. We can see why if we plot a histogram of the image:

IDL> plot,histogram(meteosat)
We're only using 20-170ish out of 256 colours (i.e. greys). We can use the bytscl function to use the
full range.
IDL> tv,bytscl(meteosat)
and this shows its histogram:
plot,histogram(bytscl(meteosat))
we are now using the full 0-255 range. bytscl will rescale any array to 0-255. Contrast in some areas
can be improved using,
tv,hist_equal(meteosat)
plot,histogram(hist_equal(meteosat))
show's its histogram - note it has been ``flattened''.
IDL has a few built-in functions for image processing. There is a boxcar smoother:
IDL> tv,bytscl(smooth(meteosat,9))
This can be used to reduce noise in an image. The second argument is the size of the box used. If you
set this to 9, then each pixel in the new image is the average of the pixels in a 9 X 9 square in the
original image. Be aware that there are better ways to smooth an image (e.g. median - look it up). There
are two edge-detecting functions, called Roberts and Sobel, presumably after the inventors of the
algorithms used:
IDL> tv,roberts(meteosat)
IDL> tv,sobel(meteosat)
One other handy is
IDL> rdpix,meteosat
left click on the image to read values and right click to finish (note you can view one image and rdpix
another).
That just about covers what you need to know to get started with greyscale images. The next part looks
at displaying colour images.

Colour images

I HAVEN'T UPDATED HUGH'S PART OF THIS - I HAVE NEVER OPERATED ON COLOUR


IMAGES LIKE THIS MYSELF - I HAVE LEFT IT IN FOR REFERENCE THOUGH.
A colour image is really three images, a red one, a green one and a blue one. If you want to do image
processing things to a colour image, smoothing for example, then you have to apply your algorithm to
the three colours separately. As we have seen, images are stored on computers in various file formats.
Just like computer screens, some image formats (tiff, jpeg, ppm, some .png) are 24 bit true colour and
store a red, a green and a blue image. Others (.gif, some .png) store an 8-bit image and a colour table to
say which value in the image should be what colour.
Try
window,0,retain=2
loadct,39
tvlct,r,g,b,/get
tv,bytscl(meteosat)
write_png,'~jmarsham/out_39.png',tvrd(),r,g,b
and
window,0,retain=2
load_sst_ct
tvlct,r,g,b,/get
tv,bytscl(meteosat)
write_png,'~jmarsham/out_sst.png',tvrd(),r,g,b
The different colour tables make a significant difference

Hugh's examples
Here is how to read in and display a pseudocolour png image
IDL> pg=read_png('/home/hcp/wrk/idlcourse/colourpeng.png',r,g,b)
%%IDL> pg=rotate(pg,7) ; wont be needed after upgrade
IDL> tvlct,r,g,b
IDL> showimage,pg,win=2
Remember that on 24-bit displays, you will need to do:
IDL> device,true_color=24,decomposed=0,retain=2
for this to work.
The ppm file format stores 24 bit images. Here is how to read in a ppm file, we use the help command
to see what the resulting array is like:

IDL> read_ppm,'/home/hcp/wrk/idlcourse/ferry.ppm',ferry
IDL> help,ferry
FERRY BYTE = Array[3, 593, 413]
This is an 593 X 413 pixel image containing three 'layers', red, green and blue.
We can do this to see the individual layers:
IDL> loadct,0
IDL> showimage,reform(ferry[2,*,*]),win=2
IDL> showimage,reform(ferry[1,*,*]),win=1
IDL> showimage,reform(ferry[0,*,*]),win=0
Note that the boat in the centre foreground looks dark in the red and green images but light in the blue
image. To display this as a colour image on a 24-bit terminal, you just need to use the /true keyword
with tv:
IDL> tv,ferry,/true

Further example - including plotting different data on same axes and putting text on a figure

This is just a worked example of reading all radiosonde files in a directory (read_all_radiosondes.pro)
and plotting potential tempo and dewpoint on same axes (not sure why you would want to do this!).
Note how one routine gets one job, numbers are not hard-wired in and keywords are used to set de-
faults.
1. read_radiosonde - reads a standard sonde file (and creates interpolated heights)
2. read_all_radiosondes - calls read_radiosonde on each file in a directory
3. temp_to_theta - converts temp to potential temp
4. trmfix - converts to a string and removes whitespace
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro read_all_radiosondes,indir,data,length_files,heights,nv=nv

;+
;Will read all radiosondes in indir
;
;eg
read_all_radiosondes,'~jmarsham/public_html/Teaching/IDL_course/Radiosondes/040720/
',data,length_files,heights
;-
if not keyword_Set (nv) then nv=6

;Findfile(IDL routine) is useful!


files=findfile(indir+'*',count=n_files)

newh=1 ; require interpolated heights for data


nvar=6 ;n variables in sonde file
; NOTE: each sonde file has a different number of lines. We cannot of
; put data arrays of different sizes into one big array, so we just
; make it big
many=200 ; a large number of lines
headers=dblarr(nv,n_files) ; array of headers
data=fltarr(nv,many,n_files); array of data
heights=fltarr(many,n_files); array of heights
length_files=fltarr(n_files); length of each file

for i = 0, n_files-1 do begin


read_radiosonde,indir+files(i),temphead1,temphead2,tempdata,newheights=newh,nvar=
nv
headers(*,i)=temphead1
length_files(i)=(size(tempdata))(2);(size(tempdata))(2)=number of lines
data(*,0:length_files(i)-1,i)=tempdata
heights(0:length_files(i)-1,i)=reform(newh)
endfor

stop
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro read_radiosonde,infile,header1,header2,data,newheights=newheights,nvar=nvar

;+
;pro read_radiosonde,infile,header1,header2,data,newheights=newheights
; Reads a stanadrd radiosonde file (infile) into header1,header2,data.
; Will intrepolate pressuer to newheights if newheights is set
;
;INPUTS: infile = file to be read (standardformat)
; nvar=nvar: number of columns in sonde file - default=6
;
;OUTPUTS header1 = header line 1 (fltarr(6))
; header2 = header line 2 (strarr(6))
; data = fltarr(6,n_lines)
; newheights=newheights: heights of data calculated by interpolating
; pressure (logarithmically).
;
;JOHN MARSHAM 13/4/05
;
;eg read_radiosonde,'/nfs/env-fs-
04_u35/jmarsham/BLASIUS/Radiosondes/040720/03743_20040720_11.dat',hedaer1,header2,d
ata,newheights=1
;-
if not keyword_Set(nvar) then nvar=6

header1=dblarr(nvar) ; need double precision to get date correct!


;0 1 2 3 4 5
;Station code yyymmdd hh ? ? Surface height(m)
header2=strarr(nvar)
; PP HT TT TD DD FF
; 0 1 2 3 4 5
i=0
line=fltarr(nvar)

openr,12,infile
readf,12,header1
readf,12,header2
repeat begin
readf, 12, line
if i eq 0 then data=[line] else data=[[data],[line]];6 by i array of data
i=i+1
endrep until eof(12)
close,12

; Calculate interpolated heights


if keyword_Set(newheights) then begin
ht=reform(data(1,*));original height data (m)
w_ht=where(data(1,*) gt 0,cw_ht);where height is defined
;interpolate newheights using log(pressure)
newheights=interpol(ht(w_ht),(alog(data(0,*)))(w_ht),(alog(data(0,*))))

;TO CHECK THIS WORKS


;w,0
;r_Set
;plot,data(1,*),alog(data(0,*)),psym=1,xrange=[0,20000],yrange=[9,12],$
;xtitle='Height (m)',ytitle='ln(pressure/mb)'
;oplot,newheights,alog(data(0,*)),psym=3
;w,1
;plot,data(1,*),data(0,*),psym=1,xrange=[0,20000],yrange=[0,1.e5],$
;xtitle='Height (m)',ytitle='Pressure (mb)'
;oplot,newheights,data(0,*),psym=3
endif

end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pro plot_sonde_th_td_z,data,sonde,heights,headers
;+
;plot_sonde_th_td_z,data,sonde,heights,headers
;
;Plot theta vs height and dewpoint vs height for data(6
;var,nlines,nfiles)
;on one graph
;sonde defines file number, heights are interpolated heights and
;headers are headers for files(See read_all_radiosondes)
;JOHN MARSHAM 13/4/05
;-

;convert temp to potential temp


theta=temp_to_theta(data(2,*,sonde),data(0,*,sonde),ref_press=100000)

w,0 ; create window


!p.color=0 ;set colour
!p.background=256*256*256l-1 ; set background
w_theta=where(theta gt 0,cw_theta) ; where pot temp defined
w_td=where(data(3,*,sonde) gt -100,cw_td) ; where dew point defined

xmin=280;min theta for plot


xmax=420;
ymin=0;min height for plot
ymax=20000
pos=[0.23,0.15,0.95,0.9];position on page - normalised coordinates

;Plot theta and height force axis range, don't draw axes
plot,theta(w_theta),(heights(*,sonde))(w_theta),position=pos,$
xrange=[xmin,xmax],yrange=[ymin,ymax],xstyle=5,ystyle=5
;draw axes
axis,xaxis=0,xrange=[xmin,xmax],xstyle=1,xtitle='Potential temperature (K)'
axis,yaxis=0,yrange=[ymin,ymax],ystyle=1,ytitle='Height (m)'

;Plot dewpoint data on top


xmin2=200
xmax2=300
plot,(data(3,*,sonde))(w_td),(heights(*,sonde))(w_td),xrange=[xmin2,xmax2],$
yrange=[ymin,ymax],/noerase,position=pos,xstyle=5,ystyle=5,linestyle=2
;draw axis for dew point
axis,xaxis=1,xrange=[xmin2,xmax2],xstyle=1,xtitle='Dew point (K)'

; Write time on top


xyouts,210,18000,trmfix(fix(headers(1,sonde),type=3))+', '+$
trmfix(fix(headers(2,sonde),type=3))+' UTC',charsize=2

end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Loops and how to avoid them


Loops are bad (but are they ``the embodiment of pure evil''?). They slow things down (but, they are not
that bad in some cases; for simple applications speed is not an issue and they can be clear to read). How
to avoid them can be complex (see links above) but there are a few simple rules.
I think here it's just best to go through,
http://www.dfanning.com/code\_tips/slowloops.html
no point me cutting and pasting it all in here!
Use ## (matrix multiply i.e. multiplies the rows of the first array by the columns of the second array)
OR use # (multiplies the columns of the first array by the rows of the second array, i.e. reverse of a
standard matrix multiply) to avoid loops (see example in Other tips and tricks: colorbars and contours
on images).
Write functions to always deal with scalars or vectors e.g.
FUNCTION temp_to_theta,temp,pressure,ref_press=ref_press

;+
;FUNCTION temp_to_theta,temp,pressure,ref_press=ref_press
;JOHN MARSHAM 18/3/2005
;Takes temperature (K or C), and pressure (any, mbar if ref_press not set) '
;returns potential temperature (K or C) adjusted to ref_press'
;If ref_press not set uses 1000 mbar
;-

if n_params() ne 2 then begin


print,'temp_to_theta,temp,pressure,ref_press=ref_press'
print,'Takes temperature (K (or C)), and pressure (hPa) '
print,'returns potential temperature (K (or C)) adjusted to ref_press'
print,'If ref_press not set uses 1000 mbar'
return,-1
endif

if not keyword_set(ref_press) then ref_press = 1000.

; this auto-conversion is slightly dodgy but I don't tend to look at


; temperatures below -123 K !
if max(temp) lt 150 then begin
temp=temp+273.15
degC=1
print,'converting deg C to K - will convert back'
endif else begin
temp=temp
degC=0
print,'Not converting deg C to K - already K'
endelse

theta=temp*(ref_press/pressure)^(0.286)

if degC eq 1 then theta=theta-273.15

return,theta

end
will convert temp to potential temp where temp is a scalar (eg temp=10.) or a vector
(temp=[5.,10.,12.]) eg
IDL> print,temp_to_theta(10.,700.)
converting deg C to K
40.4085
IDL> print,temp_to_theta([10.,20.],700.)
converting deg C to K
40.4085 51.4824
IDL> print,temp_to_theta([10.,20.],[700.,700.])
converting deg C to K
40.4085 51.4824
IDL> print,temp_to_theta([10.,20.],[700.,600.])
converting deg C to K
40.4085 66.1147
For further discussion (`` are they the embodiment of pure evil?'') see
http://www.dfanning.com/tips/forloops.html

HISTOGRAM: The Breathless Horror and Disgust -- by JD Smith


There is something at work in my soul which I do not understand . . . there is a love for
the marvellous, a belief in the marvellous, intertwined in all my projects, which hur-
ries me out of the common pathways of men, even to the wild sea and unvisited regions
I am about to explore. --Mary Shelley, FRANKENSTEIN
[Editor's Note: It would not be putting too fine a point on the subject to say that the following tutori-
al, written by JD Smith, is famous. And justifiably so. It is the only coherent and complete explana-
tion of the Histogram command extant. Read it several times. You will learn more each time you do.
And, maybe, if you read it enough, the secrets of the command will be revealed to you. Stranger
things have happened.]
You've seen it... scattered about old tomes of code like some forgotten incantation drawn from an an-
cient tongue, summoning unspoken forces. Perhaps you felt a deep, visceral uneasiness in the pres-
ence of its occult construction, arcane invocation, and dark power. Though it may turn your stomach,
HISTOGRAM is a monster which, when tamed and brought into your service, can be a powerful ally in
your quest to avoid the dreaded and oft-inefficient IDL for loop. With it you can sort and select, trim
and smooth, index and decimate: almost the full range of array manipulations, including many you
probably didn't think could be done efficiently in IDL.
Although a full account of HISTOGRAM's many uses would occupy a large volume, here I'll try to build
a foundation on which many novel variations can be built.
Remedial Review
A histogram, as we all know (at least those of us who didn't spend Algebra II passing notes and per-
fecting spitball ranging techniques) represents nothing more than a fancy way to count: a series of
numbers in an input vector is divvied up into bins according to their value, and the (fixed) size of the
histogram bin. For each input value which falls into a given bin, a single "drop in the bucket" is
added. Let's start with a simple, familiar example:
IDL> print,histogram(indgen(10),BINSIZE=5)
5 5
Indeed, 5 values each fell in the two bins of size 5. What about:
IDL> print,histogram(indgen(10))
1 1 1 1 1 1
1 1 1 1
Here you see the default is a binsize of 1 -- one drop fell into each bin. You can of course also take
histograms of floating point values:
IDL> print,histogram(randomu(sd,100),BINSIZE=.2,MIN=0.)
20 20 20 18 22
Looks about right. If this were all there was to HISTOGRAM, there wouldn't be much use in a tutorial.
You'll soon see this is far from the case.
We Can Build Him Faster
A surprising point worth mentioning about HISTOGRAM is that it's very fast: much faster than direct
for loops, and usually noticeably faster than equivalent solutions using, e.g. WHERE (where they
exist). Sometimes these savings result from a more efficient algorithm, e.g. avoiding unnecessary re-
peated linear searches through an input vector. But even when the number of operations (e.g. index-
ing) is equivalent, HISTOGRAM can outperform other IDL built-ins -- it's very well optimized.

Another thing to remember: although the for loop is quite slow in IDL, if the number of iterations is
kept small, and the work done per iteration is large, you won't feel the looping penalty. HISTOGRAM is
often very helpful in this respect. A typical rule of thumb: if you're looping over each data element in-
dividually, there's (probably) a faster way to do it.
Bins and Buckets
A slight detour brings us through the littered landscape strewn with various inputs to HISTOGRAM
which work together to specify that all important ingredient: the size of the histogram bin.
MAX
The maximum value of the array to consider. Can change from the input -- see
NBINS.
MIN
The minimum value of the array to consider.
BINSIZE
The size of the bin, which defaults to 1. It's worth noting that the binsize is
constant throughout the histogram.
NBINS
A relative of BINSIZE, NBINS is something of a misnomer. The relation HISTOGRAM
uses to compute the bin size if passed NBINS is:

BINSIZE=(MAX-MIN)/(NBINS-1)

and if NBINS is specified, MAX is changed to be (independent of any value passed as


MAX):

MAX=NBINS*BINSIZE+MIN

As such, it's probably better to avoid NBINS, if you care about the MAX value staying
put. A better relation which would leave MAX as is and give you exactly NBINS bins
between MIN and MAX:

BINSIZE=(MAX-MIN)/NBINS
OMIN|OMAX
These output keywords give you the min and max value used to construct the
histogram. Useful if you don't specify them directly.
Remember that MIN and MAX will default to the minimum and maximum of the array (except for byte
data, which defaults to MIN=0). It's very helpful to use OMIN if you don't specify the minimum, so you
know what the first bin corresponds to.
When Good HISTOGRAM's Go Bad
An important point to keep in mind is that HISTOGRAM creates one bin for each unit bin size between
the minimum and maximum, even if no such data are present in the input! This means that histograms
of sparse arrays can be very wasteful:
IDL> h=histogram(MIN=0,[100000000L])
IDL> print,n_elements(h)
100000001
That's a lot of zeroes, just to tell us we have one data point in the 100,000,000th bin! In some cases,
you can partially mitigate this problem by not specifying MIN directly, using the OMIN output instead:
IDL> h=histogram(OMIN=om,[100000000L])
IDL> print,n_elements(h)
1
IDL> print,om
100000000
But more often for sparsely populated data this won't help:
IDL> h=histogram(OMIN=om,[0L,100000000L])
IDL> print,n_elements(h)
100000001
You must always balance the speed gains of HISTOGRAM against its potentially large memory usage in
the case of very sparse arrays. The sparseness of course depends on the size of your bin (e.g. if I had
made a bin size of 100,000,001 above, there would have only been one bin), but for the typical case
of integers with binsize=1, it's easy to understand the data sparseness as "what fraction of integers, on
average, are present in the data between its min and max?" Below you'll see how to compute this.
Reverse Indices
This little HISTOGRAM jewel, obtained by setting the REVERSE_INDICES keyword, is actually its most
useful and least understood aspect. It tells you, for each bin in the histogram, the actual indices of the
data which fell into that bin. The format of the reverse indices vector is sadly quite obtuse, turning
many away from its use, but in fact it's really quite simple. In a call like:
IDL> data=fix(randomu(101,25)*12)
IDL> h=histogram(data,OMIN=om,REVERSE_INDICES=ri)
The ri vector is actually (and quite disturbingly) two vectors in one, concatenated together. I call
them the i-vector and the o-vector:
=======================================================
The `i' vector The `o' vector
ri = iiiiiiiiiiiiiiiiiiioooooooooooooooooooooooooooooo
|-----------------||----------------------------|
|0 nh||nh+1 nh+total(h)|
=======================================================
The last index of the i-vector, nh, is the number of elements in the histogram. The i-vector is actually
an index into the o-vector portion of the reverse indices list itself: a list which indexes itself! Scary,
yes, but that's just unusual bookkeeping. It's much simpler than all that. The easiest way to think of it
is as follows: each bin of the histogram has a short list of zero or more indices associated with it --
picture each drop in the bucket painted with the index of the data to which it corresponds:
| | | | |6 | | | | | | | |
| |5 | | |10 | | | | | | |3 |
|7 |12 | | |15 | | | | | | |9 |
|11 |20 | |16 |19 | | | | | |8 |17 |
|14 |21 |1 |24 |23 |0 |2 |4 | |18 |13 |22 |
+---+---+---+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6 7 8 9 10 11
The o-vector contains these indices, in order, and the i-vector just shows us where to go to get them.
E.g., to get the indices from the first bin of the histogram, we use:
IDL> print, ri[ri[0]:ri[1]-1]
7 11 14
IDL> print, data[ri[ri[0]:ri[1]-1]]
0 0 0
IDL> print,ri[0],ri[1]-1
13 15
and from the 5th bin:
IDL> print, ri[ri[4]:ri[5]-1]
6 10 15 19 23
IDL> print, data[ri[ri[4]:ri[5]-1]]
4 4 4 4 4
That is, adjacent values in the i-vector part of ri specify the range of elements in the o-vector part of
ri which contain the indices of data present in that bin. In the first example, there were 3 data ele-
ments which fell in the first bin (all, as you'd anticipate, with a value of 0). What if no data fall in a
given bin?
IDL> print,where(h eq 0)
8
IDL> print,ri[8],ri[9]
31 31
In this case, you see that the two adjacent elements of the i-vector are the same: they don't span any
elements of the o-vector. Typically, you need to test for this to avoid a null index range. Something
like this.
IDL> if ri[4] ne ri[5] then print, data[ri[ri[4]:ri[5]-1]] else print,
'No data in bin 4'
IDL> if ri[8] ne ri[9] then print, data[ri[ri[8]:ri[8]-1]] else print,
'No data in bin 8'
4 4 4 4 4
No data in bin 8
Note that the smallest value in the i-vector is nh+1, i.e. the first index of the o-vector, one more than
the number of elements in the histogram. This is just because i and o are glued together like that --
had the i-vector and o-vector been kept separate, the former would have started at 0.

The main point to remember: HISTOGRAM actually has three very useful outputs, not one: the his-
togram itself, h, the reverse index self-index vector i, and the original index vector o. Sometimes
they're useful together, and sometimes only one of the three holds the key to solving a particular prob-
lem.
Flexing your HISTOGRAM Muscle
The best way to learn HISTOGRAM techniques is to dive right into a set of working examples. Don't for-
get to come up for air!

Using the h-vector


Perhaps the most common set of operations in IDL is building, reformatting, dissecting, and applying
lists of indices to arrays of various dimensionality (see, for instance the dimensional juggling tutori-
al). HISTOGRAM is no stranger to these index slinging operations. A simple example taken from the
manual:
Problem: Increment each element of a vector listed in a index vector by 1.
IDL> inds=fix(randomu(sd,8)*3)
IDL> print,inds
2 2 0 1 2 0 1 2
IDL> vec=intarr(3)
IDL> vec=histogram(inds,INPUT=vec,MIN=0)
IDL> print,vec
2 2 4
This works even if individual indices are mentioned several times (in which case the explicit
vec[inds]=vec[inds]+1 does not work). INPUT is a convenience, equivalent to vec=vec+his-
togram(...). You simply can't do this with normal indexing, without a for loop. You needn't just
increment by one either:
Problem: Increment all elements of vec with indices mentioned at least twice by PI.
IDL> vec=vec+(histogram(inds,MIN=0,MAX=n_elements(vec)-1) ge 2)*!PI
Problem: Find the value intersection of two vectors, a.k.a. which values are present in both a and b?
IDL> a=fix(randomu(sd,8)*20)
IDL> b=fix(randomu(sd,8)*20)
IDL> print,a,b
6 7 16 13 15 13 19 7
16 5 8 17 7 7 4 7
IDL> print,where(histogram(a,OMIN=om) gt 0 AND histogram(b,MIN=om) gt
0)+om
7 16
I.e., we look for which buckets contain at least one drop for both vectors, using OMIN to save some
work (since there can be no overlap below the minimum of either array). You could also easily use
this method to find values repeated exactly twice, or present in one but not another (the set differ-
ence).
Problem: Remove some elements, listed in random order, from a vector.
IDL> vec=randomu(sd,10)
IDL> remove=[3,7,2,8]
IDL> keep=where(histogram(remove,MIN=0,MAX=n_elements(vec)-1) eq 0,cnt)
IDL> if cnt ne 0 then vec=vec[keep]
IDL> print,keep
0 1 4 5 6 9
We've used HISTOGRAM and WHERE to simply generate a list of kept indices.

Problem: Find a multi-dimensional histogram of a set of input coordinate tuples (e.g. (x,y,z)).

This general class of problems (solved in 2D by RSI's HIST_2D, and in up to eight dimensions by
HIST_ND) also has other applications. The key trick is to scale all data into integer bins yourself,
e.g.:
IDL> h=(data-min(data))/binsize
and to convert these multi-dimensional scaled "indices" into a single index (exactly analogous to con-
verting a (column, row) index of an array into a single running index). In 3D this looks like:
IDL> h=h0+nbins[0]*(h1+nbins[1]*h2)
IDL> ret=histogram(h,MIN=0,MAX=total_bins-1)
where h0,h1, and h2 are the scaled data "indices" from the first, second and third dimensions, and to-
tal_bins is the total number of bins in your grid (just the product of the bin sizes). You can see how
to generalize to higher dimensions, and how to apply the same technique to do other work with data
sets of more than one dimension.
Problem: Determine how sparse a set of input data is.
IDL> data=fix(randomu(sd,1000)*10000)
IDL> h=histogram(data)
IDL> print,total(h ne 0)/n_elements(h)
0.0953624
I.e., very close to 1 in 10 integers are present. This works even if your data are very clustered and
have a tendency towards repeated values.

Using the o-vector


The o-vector portion of the reverse indices vector is essential for its intended use: gathering together
those elements of the input data vector which fall in an individual bin. With it, you can easily perform
operations on data which have been divided up into bins of any given size. And unlike linear search
methods, you can precompute the histogram with reverse indices, and subsequently perform many
different operations on different data sub-groups using the same histogram, for a substantial speedup.
Problem: Find the individual median in each quartile of a data set.
IDL> data=randomu(sd,100)*100
IDL> h=histogram(data,BINSIZE=25, REVERSE_INDICES=ri)
IDL> med=fltarr(4)
IDL> for j=0L,3L do if ri[j+1] gt ri[j] then $
med[j]=median(data[ri[ri[j]:ri[j+1]-1]])
IDL> print,med
13.3847 39.0525 68.0970 87.5475
This pattern forms the standard usage of the o-vector component of the reverse indices vector: loop
over histogram bins, and, if non-empty, do something to the data which fell into that bin.
The reverse indices don't have to be used to index the original array, much as an index list returned by
SORT doesn't have to be used to sort the vector it was passed:

Editor's Note: Please note that quartiles can only be calculated like this if you data is uniformly dis-
tributed. The proper definition of quartile would suggest that you are going to have four bins and the
same number of points would be in each bin. That is, the median would separate the data set into two
bins of equal number of points. Then, taking the median of those two sub-bins would result in the two
quartiles (25% and 75%). In practice, say you wanted to draw a box and whisker plot, you might do
something like this if you had a non-uniform distribution of points.
data=randomu(sd,100)*100
minVal = min(data)
maxVal = max(data)
medianVal = median(data,/even)

; Find the quartiles.


qtr_25th = Median(data[Where(data LE medianVal, countlowerhalf)])
qtr_75th = Median(data[Where(data GT medianVal, countupperhalf)])
Problem: Total data together according to a separate list of indices, e.g.:
inds=[3 , 1, 0, 4, 2, 3, 3, 2, 4, 0]
data=[.1,.8,.6,.4,.2,.9,.7,.3,.5,.2]
vec[0]=data[2]+data[9]
vec[1]=data[1]
....
This is easy, using the o-vector -- simply use the reverse index of the inds vector as an index to an-
other vector -- data:
IDL> h=histogram(inds,reverse_indices=ri,OMIN=om)
IDL> for j=0L,n_elements(h)-1 do if ri[j+1] gt ri[j] then $
vec[j+om]=total(data[ri[ri[j]:ri[j+1]-1]])
For large histograms, there are even more efficient ways to do this with very short or no loops (e.g.
using a histogram of the histogram). Additonal information on this topic can be found in the article on
array decimation.
Problem: Threshold a vector, setting all elements between 20 and 60, inclusive, to zero.
IDL> data=fix(randomu(sd,100)*100)
IDL> h=histogram(data,OMIN=om,REVERSE_INDICES=ri)
IDL> data[ri[ri[20-om>0]:ri[61-om>0]-1]]=0.
What's this? We've clearly violated the time honored r[i]:r[i+1] convention, and skipped right
through 41 bins worth of o-vector indices in one go. Since the o-vector contains adjacent groups of
indices one right after another, this is perfectly legal. You'll get into trouble if there are no elements
between the limits (i.e. if ri[20-om>0] eq ri[61-om>0]), but you can test for that.

Problem: Throw away data with more than twice the median repeat count rate.
data=fix(randomn(sd,100)*5)
h=histogram(data,REVERSE_INDICES=ri)
keep=where(h le 2*median(h))
num=h[keep]
for n=1,max(num) do begin
wh=where(num ge n,cnt)
if cnt eq 0 then continue
if n_elements(k_inds) eq 0 then k_inds=ri[ri[keep[wh]]+n-1] else $
k_inds=[k_inds,ri[ri[keep[wh]]+n-1]]
endfor
data=data[k_inds]
Here we've chosen to loop over bin count and not directly over the reverse indices, to reduce the size
of the loop (with its costly concatenation). The simpler form using the standard pattern is:
for i=0,n_elements(keep)-1 do begin
k=keep[i]
if ri[k+1] gt ri[k] then $
if n_elements(k_inds) eq 0 then k_inds=ri[ri[k]:ri[k+1]-1] $
else k_inds=[k_inds,ri[ri[k]:ri[k+1]-1]]
endfor
data=data[k_inds]
If you need to preserve the ordering of the kept elements, accumulate a throw-away index list similar-
ly (e.g. bad=where(h ge 2*median(h)), and then use the method from the previous section to gen-
erate an ordered kept-index list from it.

Using the i-vector


The i-vector is the least used portion of HISTOGRAM's output (aside from the trivial case when it's used
to index the o-vector), but it can do some very neat things.

Problem: Construct a vector with values from one vector and a repeat count from another (so called
chunk indexing). E.g., turn:
IDL> d=[4,5,6,8]
IDL> n=[2,1,3,4]
into
new_d=[4,4,5,6,6,6,8,8,8,8]
This is easy with the i-vector:
IDL> h=histogram(total(n,/CUMULATIVE)-
1,/BINSIZE,MIN=0,REVERSE_INDICES=ri)
IDL> i=ri[0:n_elements(h)-1]-ri[0]
IDL> print,d[i]
4 4 5 6 6 6 8 8 8
8
What have we done here? Well, we've taken the cumulative sum of n:
IDL> print,total(n,/CUMULATIVE)-1
1.00000 2.00000 5.00000 9.00000
created a histogram from it, and used the fact that the i-vector contains multiple repeated indices for
all the empty bins:
IDL> print,i
0 0 1 2 2 2
3 3 3 3
Note that this subject is discussed in considerably more depth in a related article on array decimation.
Applying the Current
Don't worry if everything doesn't come together at once. No monster was built in a day. Just keep tin-
kering with the examples, examining the by-products along the way, and soon you'll be terrorizing
unsuspecting villagers the world-round with your creations.

Reading NetCDF

Here is a general sequence of events for opening a netCDF file in idl.


;Open the netcdf file, ncid is an idl string
ncid = NCDF_OPEN('filename')

;get a variable out of the data


NCDF_VARGET, ncid, varid, var_name

;Close the netcdf file


NCDF_CLOSE, ncid
However, by far the simplest method, that will suffice for most peoples needs is the use of 'cdf2idl.pro'
routine. This can be downloaded from
http://www-c4.ucsd.edu/~cids/software/visual.html
Its use is described at,
http://www.nodc.noaa.gov/woce_V2/disk02/netcdf/netcdf_primer.htm
The cdf2idl.pro routine is one of a suite of similar routines available for Fortran, c and matlab which
may also be useful.
Basically it reads a netCDF file and then generates each of the above commands in sequence for each
variable in the netcdf file. It also gets global attributes.
For instance, if you have a netcdf file 'test.nc', you have a command line
cdf2idl,file,outfile='/path/to/outfile',/verbose
You then type @/path/to/outfile (i.e. cdf2idl generates a batch script)

Array concatenation (from David Fanning)

This time quoting from http://www.dfanning.com/tips/array_concatenation.html


a=make_array(4,4,VALUE=1b)
help,a ;A BYTE = Array[4, 4]
b=make_array(4,4,VALUE=2b)
help,b ;B BYTE = Array[4, 4]
help,[a,b] ;<Expression> BYTE = Array[8, 4]
help,[[a],[b]] ;<Expression> BYTE = Array[4, 8]
help,[[[a]],[[b]]] ;<Expression> BYTE = Array[4, 4, 2]

Web Resources

http://homepages.see.leeds.ac.uk/~lecjm/Teaching/IDL_course/Notes/notes/node1.html

www.dfanning.com

http://idlastro.gsfc.nasa.gov/idl_html_help

http://star.pst.qub.ac.uk/idl

http://nstx.pppl.gov/nstx/Software/IDL/idl_intro.html
/idltutorials.html

http://idlastro.gsfc.nasa.gov/idl_html_help/Functional_List_of_IDL_Routines.html

http://groups.google.com/group/comp.lang.idl-pvwave/
/comp.lang.fortran

www.agocg.ac.uk/brief/idl/idl.htm

www.dfanning.com/index.html/documents/tips.html#IDLWAY

www.astro.virginia.edu/class/oconnell/astr511/IDLresources/idl_5.1_html/idl.htm

S-ar putea să vă placă și