Interactive Data Language Guide PDF
Interactive Data Language Guide PDF
Some definitions
keys
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
As we quit IDL, its help window also disappears, so its useful to call help directly from Unix command
prompt,
>idlhelp
>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.
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 :
i=15
integer -32768 to 32767 2 i=fix(x)
i=15S
j=15L
long -231 to 231-1 4 j=long(x)
j=25631l
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 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
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
$ 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”
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 Function
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.
Linestyles
0 solid line
1 dotted line
2 dashed line
3 dash-dot line
4 dash-dot-dot line
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.
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]
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,
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)
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.
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
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.
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
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 :
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:
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.
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.
IDL> a=[2,4,3,9,8,6]
IDL> print,sort(a)
0 2 1 5 4
3
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> print,uniq(a)
% Compiled module: UNIQ.
4 5
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]
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
IDL> f=a[uniq(a,sort(a))]
IDL> print,f
1 2 3 4 5 6
IDL> a=[1,2,3,4]
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> 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
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
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.
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.
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> d = determ(float(A))
% Compiled module: DETERM.
IDL> print, d
-12.0000
Invert:
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):
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,
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> print,count
5
IDL> print,x
1 2 3 4 5
IDL> print,b(x)
5 7 8 10 11
IDL> print,b(y)
11
pos = strpos(a,b) renvoie la position de la sous chaîne b dans la chaîne a ; si b n’est pas
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.
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.
CDF HDF
HDF-EOS netCDF
Other Formats
If
Procedure definition
Function definition
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
!d subscript
!u superscript
!e superscript (small size)
!i subscript (small size)
!n coming back to normal
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> device,/close ; close the postscript device... Did it create a good file??
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
; 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)
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
; 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)
; 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
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
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
; 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
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)
;-
;;;;;; 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;;;;;
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'
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'
endwhile
modtrandata=modtrandata(*,0:linecount-1) ; truncate array to actual length
; of file.
close,1
eof(unit)
example,
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'
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)
;;;;;; read the data from the file attached to unit 1 ;;;;;;;
;;;;;; into the array modtrandata
readf,1,modtrandata
device,file='modtran.ps'
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
set_plot,'x'
end
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.
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.
IDL> print,an_array[0],an_array[2]
3.00000 6.00000
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.
( 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 -------------------------------------------------------------
RETURN
END
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
;-
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)
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:
Or a simple rainbow
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
Greyscale images
; 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
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
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
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
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
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
;-
;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)'
end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;+
;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
;-
theta=temp*(ref_press/pressure)^(0.286)
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
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)
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!
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.
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)
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.
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
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