Working With Structures


Structures are one of the most useful and powerful concepts in IDL. They can simplify your programming significantly and are the most logical way to deal with large amounts of data or large numbers of variables. Although they may appear strange at first I strongly recommend you take the time to learn how to use them. The best way to learn the full power of structures is by studying other IDL programs and using them whenever you can in your own programs. In Working With FITS we will see how structures can be written out as binary FITS files.

The following analogy originates in the IDL User's Manual. Think of a structure as a house with many separate rooms. Each room can contain something irrespective of what is in the other rooms. For example, in one "room" you might have an identification number (a scalar integer), in another "room" a two-dimensional image, and in a third "room" a header. A "room" is called a field and the "house" is the data structure.

To create a structure called s type

s = {id: 0, image: fltarr(100,100), header: strarr(10)}

To find out about s type

help, s, /structure

or, equivalently,

help, s, /str

Remember in IDL you only need as many letters in a keyword to uniquely identify that keyword. We see that s has three tags: a scalar integer ID, a 100 by 100-element floating point array IMAGE, and a ten-element string array HEADER. To access the ID field type

print, s.id

To set the ID field to a different value type

s.id = 300
help, s, /str

You can see immediately how structures can simplify your programming: Instead of dealing with three separate variables (id, image, and header), everything can be carried around in a single variable, s. Structures can have an unlimited number of fields provided you do not exceed the amount of memory in RAM .

But what if you're dealing with multiple objects (for example, a catalog of stars)? Do you need an individual structure for each one? No, you can generate an array of structures analogous to an array of numbers or an array of strings. Try this:

nstar = 58
starinfo = {number: 0L, xpos: 0.0, ypos: 0.0, mag: 0.0}
starinfo = replicate(starinfo,nstar)
starinfo.number = lindgen(nstar)

The syntax 0L means make zero a long integer (as opposed to a simple integer) and is equivalent to long(0). In the first line we are (arbitrarily) specifying how many stars are in our catalog. In the second line we initialize the data structure starinfo to have four fields: an id number, an x and y position, and a magnitude. The function replicate() then makes nstar copies of starinfo. For example, try typing

print, replicate('Hello!',15)
print, replicate(14.756,3)

To examine the number field in starinfo type

print, starinfo.number

To retrieve the data on one particular star we have to find the index corresponding to that star. Try this:

indx = where(starinfo.number eq 13L,nindx)
if nindx ne 0L then help, starinfo[indx], /str

There is a bit of error catching in the above bit of code that you should try to understand. To determine the number of tags (or fields) in a structure type

print, n_tags(starinfo)

To print the tag names of a structure type

print, tag_names(starinfo)

Let's work with some real data now by using the querygsc() function in the Goddard Library. This function queries the HST Guide Star Catalog (V2.2). Read the documentation on this function and then try the example below.

nearvega = querygsc('HD172167',10.0)
nfound = n_elements(nearvega)
print, "Found "+string(nfound,format='(I0)')+" stars within 10' of Vega."
help, nearvega, /str
print, nearvega.jmag

Another way to define a data structure is to use the IDL function create_struct():

mystruct = create_struct('name', 'bob', 'friend', 'joe', $
  'number', 10.0, 'junk', findgen(15))
help, mystruct, /str

You can print the value of a structure field by identifying it by name or by using its index number:

print, mystruct.name, mystruct.number
print, mystruct.(0), mystruct.(2)

Finally there is a set of structure manipulation routines written by David Schlegel in the idlutils library that are very useful. Consider two structures astruct and bstruct:

astruct = {a: 10.0, b: 'Hey!'}
astruct = replicate(astruct,10)
help, astruct, /str
bstruct = {c: lindgen(25,25), d: 'I need another example.'}
bstruct = replicate(bstruct,10)
help, bstruct, /str

To bring the fields in astruct and bstruct together into a new structure cstruct type

cstruct = struct_addtags(astruct,bstruct)
help, cstruct, /str
print, cstruct.b

Now let's say we want to append 15 more structures to astruct (for example if we added 15 more stars to our catalog):

print, n_elements(astruct)
dstruct = replicate({a: 10.0, b: 'Hey!'},15)
astruct = struct_append(astruct,dstruct)
print, n_elements(astruct)

To print a structure in a nice format type

struct_print, astruct

Finally to trim tags from a structure use struct_trimtags():

newstruct1 = struct_trimtags(bstruct,select='D')
newstruct2 = struct_trimtags(bstruct,except='D')
help, newstruct1, /str
help, newstruct2, /str

See what the keywords select and except do by reading the documentation on struct_trimtags().





Last update 2003 November. Email J. Moustakas with questions or comments.