3 How To…

 3.1 …Obtain and Install AST
 3.2 …Structure an AST Program
 3.3 …Build an AST Program
 3.4 …Read a WCS Calibration from a Dataset
 3.5 …Validate WCS Information
 3.6 …Display AST Data
 3.7 …Convert Between Pixel and World Coordinates
 3.8 …Test if a WCS is a Celestial Coordinate System
 3.9 …Test if a WCS is a Spectral Coordinate System
 3.10 …Format Coordinates for Display
 3.11 …Display Coordinates as they are Transformed
 3.12 …Read Coordinates Entered by a User
 3.13 …Create a New WCS Calibration
 3.14 …Modify a WCS Calibration
 3.15 …Write a Modified WCS Calibration to a Dataset
 3.16 …Display a Graphical Coordinate Grid
 3.17 …Switch to Plot a Different Celestial Coordinate Grid
 3.18 …Give a User Control Over the Appearance of a Plot

For those of you with a plane to catch, this section provides some instant templates and recipes for performing the most commonly-required operations using AST, but without going into detail. The examples given (sort of) follow on from each other, so you should be able to construct a variety of programs by piecing them together. Note that some of them appear longer than they actually are, because we have included plenty of comments and a few options that you probably won’t need.

If any of this material has you completely baffled, then you may want to read the introduction to AST programming concepts in §4 first. Otherwise, references to more detailed reading are given after each example, just in case they don’t quite do what you want.

3.1 …Obtain and Install AST

The AST library is available both as a stand-alone package and also as part of the Starlink Software Collection4. If your site has the Starlink Software Collection installed then AST should already be available.

If not, you can download the AST library by itself from http://www.starlink.ac.uk/ast/.

3.2 …Structure an AST Program

An AST program normally has the following structure:

  *  Include the interface to the AST library.
        INCLUDE ’AST_PAR’
  
  *  Declare an integer status variable.
        INTEGER STATUS
        <maybe other declarations>
  
  *  Initialise the status to zero.
        STATUS = 0
        <maybe some Fortran statements>
  
  *  Enclose the parts which use AST between AST_BEGIN and AST_END calls.
        CALL AST_BEGIN( STATUS )
        <Fortran statements which use AST>
        CALL AST_END( STATUS )
  
        <maybe more Fortran statements>
        END

The use of AST_BEGIN and AST_END is optional, but has the effect of tidying up after you have finished using AST, so is normally recommended. For more details of this, see §4.10. For details of how to access the AST_PAR include file, see §22.1.

3.3 …Build an AST Program

To build a simple AST program that doesn’t use graphics, use:

  f77 program.f -L/star/lib -I/star/include ‘ast_link‘ -o program

On Linux systems you should usually use g77 -fno-second-underscore in place of f77 - see “Software development on Linux” in SUN/212.

To build a program which uses PGPLOT for graphics, use:

  f77 program.f -L/star/lib ‘ast_link -pgplot‘ -o program

again using g77 -fno-second-underscore in place of f77 on Linux systems.

For more details about accessing AST include files, see §22.1. For more details about linking programs, see §22.2 and the description of the “ast_link” command in Appendix E.

3.4 …Read a WCS Calibration from a Dataset

Precisely how you extract world coordinate system (WCS) information from a dataset obviously depends on what type of dataset it is. Usually, however, you should be able to obtain a set of FITS header cards which contain the WCS information (and probably much more besides). Suppose that CARDS is an array of character strings containing a complete set of FITS header cards and NCARD is the number of cards. Then proceed as follows:

        INTEGER FITSCHAN, ICARD, NCARD, WCSINFO
        CHARACTER * ( 80 ) CARDS( NCARD )
  
        ...
  
  *  Create a FitsChan and fill it with FITS header cards.
        FITSCHAN = AST_FITSCHAN( AST_NULL, AST_NULL, ’ ’, STATUS )
        DO 1 ICARD = 1, NCARD
           CALL AST_PUTFITS( FITSCHAN, CARDS( ICARD ), .FALSE., STATUS )
   1    CONTINUE
  
  *  Rewind the FitsChan and read WCS information from it.
        CALL AST_CLEAR( FITSCHAN, ’Card’, STATUS )
        WCSINFO = AST_READ( FITSCHAN, STATUS )

The result should be a pointer, WCSINFO, to a FrameSet which contains the WCS information. This pointer can now be used to perform many useful tasks, some of which are illustrated in the following recipes.

Some datasets which do not easily yield FITS header cards may require a different approach, possibly involving use of a Channel or XmlChan15) rather than a FitsChan. In the case of the Starlink NDF data format, for example, all the above may be replaced by a single call to the routine NDF_GTWCS—see SUN/33. The whole process can probably be encapsulated in a similar way for most other data systems, whether they use FITS header cards or not.

For more details about reading WCS information from datasets, see §17.3 and §17.4. For a more general description of FitsChans and their use with FITS header cards, see §16 and §17. For more details about FrameSets, see §13 and §14.

3.5 …Validate WCS Information

Once you have read WCS information from a dataset, as in §3.4, you may wish to check that you have been successful. The following will detect and classify the things that might possibly go wrong:

        IF ( STATUS .NE. 0 ) THEN
           <an error occurred (a message will have been issued)>
        ELSE IF ( WCSINFO .EQ. AST__NULL ) THEN
           <there was no WCS information present>
        ELSE IF ( AST_GETC( WCSINFO, ’Class’, STATUS ) .NE. ’FrameSet’ ) THEN
           <something unexpected was read (i.e. not a FrameSet)>
        ELSE
           <WCS information was read OK>
        END IF

For more information about detecting errors in AST routines, see §4.13. For details of how to validate input data read by AST, see §15.6 and §17.4.

3.6 …Display AST Data

If you have a pointer to any AST Object, you can display the data stored in that Object in textual form as follows:

        CALL AST_SHOW( WCSINFO, STATUS )

Here, we have used a pointer to the FrameSet which we read earlier (§3.4). The result is written to the program’s standard output stream. This can be very useful during debugging.

For more details about using AST_SHOW, see §4.4. For information about interpreting the output, also see §15.8.

3.7 …Convert Between Pixel and World Coordinates

You may use a pointer to a FrameSet, such as we read in §3.4, to transform a set of points between the pixel coordinates of an image and the associated world coordinates. If you are working in two dimensions, proceed as follows:

        INTEGER N
        DOUBLE PRECISION XPIXEL( N ), YPIXEL( N )
        DOUBLE PRECISION XWORLD( N ), YWORLD( N )
  
        ...
  
        CALL AST_TRAN2( WCSINFO, N, XPIXEL, YPIXEL, .TRUE.,
       :                            XWORLD, YWORLD, STATUS )

Here, N is the number of points to be transformed, XPIXEL and YPIXEL hold the pixel coordinates, and XWORLD and YWORLD receive the returned world coordinates.5 To transform in the opposite direction, interchange the two pairs of arrays (so that the world coordinates are given as input) and change the fifth argument of AST_TRAN2 to .FALSE..

To transform points in one dimension, use AST_TRAN1. In any other number of dimensions (or if the number of dimensions is initially unknown), use AST_TRANN. These routines are described in Appendix B.

For more information about transforming coordinates, see §4.8 and §13.6. For details of how to handle missing coordinates, see §5.9.

3.8 …Test if a WCS is a Celestial Coordinate System

The world coordinate system (WCS) currently associated with an image may often be a celestial coordinate system, but this need not necessarily be the case. For instance, instead of right ascension and declination, an image might have a WCS with axes representing wavelength and slit position, or maybe just plain old pixels.

If you have obtained a WCS calibration for an image, as in §3.4, in the form of a pointer WCSINFO to a FrameSet, then you may determine if the current coordinate system is a celestial one or not, as follows:

        INTEGER FRAME
        LOGICAL ISSKY
  
        ...
  
  *  Obtain a pointer to the current Frame and determine if it is a
  *  SkyFrame.
        FRAME = AST_GETFRAME( WCSINFO, AST__CURRENT, STATUS )
        ISSKY = AST_ISASKYFRAME( FRAME, STATUS )
        CALL AST_ANNUL( FRAME, STATUS )

This will set ISSKY to .TRUE. if the WCS is a celestial coordinate system, and to .FALSE. otherwise.

3.9 …Test if a WCS is a Spectral Coordinate System

Testing for a spectral coordinate system is basically the same as testing for a celestial coordinate system (see the previous section). The one difference is that you use the AST_ISASPECFRAME routine in place of the AST_ISASKYFRAME routine.

3.10 …Format Coordinates for Display

Once you have converted pixel coordinates into world coordinates (§3.7), you may want to format them as text before displaying them. Typically, this would convert from (say) radians into something more comprehensible. Using the FrameSet pointer WCSINFO obtained in §3.4 and a pair of world coordinates XW and YW (e.g. see §3.7), you could proceed as follows:

        CHARACTER * ( 20 ) XTEXT, YTEXT
        DOUBLE PRECISION XW, YW
  
        ...
  
        XTEXT = AST_FORMAT( WCSINFO, 1, XW, STATUS )
        YTEXT = AST_FORMAT( WCSINFO, 2, YW, STATUS )
  
        WRITE ( *, 199 ) XTEXT, YTEXT
   199  FORMAT( ’Position = ’, A, ’, ’, A )

Here, the second argument to AST_FORMAT is the axis number.

With celestial coordinates, this will usually result in sexagesimal notation, such as “12:34:56.7”. However, the same method may be applied to any type of coordinates and appropriate formatting will be employed.

For more information about formatting coordinate values and how to control the style of formatting used, see §7.6 and §8.6. If necessary, also see §7.7 for details of how to “normalise” a set of coordinates so that they lie within the standard range (e.g. 0 to 24 hours for right ascension and ± 90 for declination).

3.11 …Display Coordinates as they are Transformed

In addition to formatting coordinates as part of a program’s output, you may also want to examine coordinate values while debugging your program. To save time, you can “eavesdrop” on the coordinate values being processed every time they are transformed. For example, when using the FrameSet pointer WCSINFO obtained in §3.4 to transform coordinates (§3.7), you could inspect the coordinate values as follows:

        CALL AST_SET( WCSINFO, ’Report=1’, STATUS )
        CALL AST_TRAN2( WCSINFO, N, XPIXEL, YPIXEL, .TRUE.,
       :                            XWORLD, YWORLD, STATUS )

By setting the FrameSet’s Report attribute to 1, coordinate transformations are automatically displayed on the program’s standard output stream, appropriately formatted, for example:

  (42.1087, 20.2717) --> (2:06:03.0, 34:22:39)
  (43.0197, 21.1705) --> (2:08:20.6, 35:31:24)
  (43.9295, 22.0716) --> (2:10:38.1, 36:40:09)
  (44.8382, 22.9753) --> (2:12:55.6, 37:48:55)
  (45.7459, 23.8814) --> (2:15:13.1, 38:57:40)
  (46.6528, 24.7901) --> (2:17:30.6, 40:06:25)
  (47.5589, 25.7013) --> (2:19:48.1, 41:15:11)
  (48.4644, 26.6149) --> (2:22:05.6, 42:23:56)
  (49.3695, 27.5311) --> (2:24:23.1, 43:32:41)
  (50.2742, 28.4499) --> (2:26:40.6, 44:41:27)

For a complete description of the Report attribute, see its entry in Appendix C. For further details of how to set and enquire attribute values, see §4.6 and §4.5.

3.12 …Read Coordinates Entered by a User

In addition to writing out coordinate values generated by your program (§3.10), you may also need to accept coordinates entered by a user, or perhaps read from a file. In this case, you will probably want to allow “free-format” input, so that the user has some flexibility in the format that can be used. You will probably also want to detect any typing errors.

Let’s assume that you want to read a number of lines of text, each containing the world coordinates of a single point, and to split each line into individual numerical coordinate values. Using the FrameSet pointer WCSINFO obtained earlier (§3.4), you could proceed as follows:

        CHARACTER TEXT * ( 80 )
        DOUBLE PRECISION COORD( 10 )
        INTEGER IAXIS, N, NAXES, T
  
        ...
  
  *  Obtain the number of coordinate axes (if not already known).
        NAXES = AST_GETI( WCSINFO, ’Naxes’, STATUS )
  
  *  Loop to read each line of input text, in this case from the
  *  standard input channel (your programming environment will probably
  *  provide a better way of reading text than this). Set the index T to
  *  the start of each line read.
   2    CONTINUE
        READ( *, ’(A)’, END=99 ) TEXT
        T = 1
  
  *  Attempt to read a coordinate for each axis.
        DO 3 IAXIS = 1, NAXES
           N = AST_UNFORMAT( WCSINFO, IAXIS, TEXT( T : ), COORD( IAXIS ),
       :                     STATUS )
  
  *  If nothing was read and this is not the first axis and the end of
  *  the text has not been reached, try stepping over a separator and
  *  reading again.
           IF ( ( N .EQ. 0 ) .AND. ( IAXIS .GT. 1 ) .AND.
       :        ( T .LT. LEN( STRING ) ) ) THEN
              T = T + 1
              N = AST_UNFORMAT( WCSINFO, IAXIS, TEXT( T : ),
                                COORD( IAXIS ), STATUS )
           END IF
  
  *  Quit if nothing was read, otherwise move on to the next coordinate.
           IF ( N .EQ. 0 ) GO TO 4
           T = T + N
   3    CONTINUE
   4    CONTINUE
  
  *  Test for the possible errors that may occur...
  
  *  Error detected by AST (a message will have been issued).
        IF ( STATUS .NE. 0 ) THEN
           GO TO 99
  
  *  Error in input data at character TEXT( T + N : T + N ).
        ELSE IF ( ( T .LT. LEN( STRING ) ) .OR. ( N .EQ. 0 ) ) THEN
           <handle the error, or report your own message here>
           GO TO 99
  
        ELSE
           <coordinates were read OK>
        END IF
  
  *  Return to read the next input line.
        GO TO 2
   99   CONTINUE

This algorithm has the advantage of accepting free-format input in whatever style is appropriate for the world coordinates in use (under the control of the FrameSet whose pointer you provide). For example, wavelength values might be read as floating point numbers (e.g. “1.047” or “4787”), whereas celestial positions could be given in sexagesimal format (e.g. “12:34:56” or “12 34.5”) and would be converted into radians. Individual coordinate values may be separated by white space and/or any non-ambiguous separator character, such as a comma.

For more information on reading coordinate values using the AST_UNFORMAT function, see §7.8. For details of how sexagesimal formats are handled, and the forms of input that may be used for for celestial coordinates, see §8.7.

3.13 …Create a New WCS Calibration

This section describes how to add a WCS calibration to a data set which you are creating from scratch, rather than modifying an existing data set.

In most common cases, the simplest way to create a new WCS calibration from scratch is probably to create a set of strings describing the required calibration in terms of the keywords used by the FITS WCS standard, and then convert these strings into an AST FrameSet describing the calibration. This FrameSet can then be used for many other purposes, or simply stored in the data set.

The full FITS-WCS standard is quite involved, currently running to four separate papers, but the basic kernel is quite simple, involving the following keywords (all of which end with an integer axis index, indicated below by < i >):

CRPIX<i>

hold the pixel coordinates at a reference point
CRVAL<i>

hold the corresponding WCS coordinates at the reference point
CTYPE<i>

name the quantity represented by the WCS axes, together with the projection algorithm used to convert the scaled and rotated pixel coordinates to WCS coordinates.
CD<i>_<j>

a set of keywords which specify the elements of a matrix. This matrix scales pixel offsets from the reference point into the offsets required as input by the projection algorithm specified by the CTYPE keywords. This matrix specifies the scale and rotation of the image. If there is no rotation the off-diagonal elements of the matrix (e.g. CD1_2 and CD2_1) can be omitted.

As an example consider the common case of a simple 2D image of the sky in which north is parallel to the second pixel axis and east parallel to the (negative) first pixel axis. The image scale is 1.2 arc-seconds per pixel on both axes, and the image is presumed to have been obtained with a tangent plane projection. Furthermore, it is known that pixel coordinates (100.5,98.4) correspond to an RA of 11:00:10 and a Dec. of -23:26:02. A suitable set of FITS-WCS header cards could be:

  CTYPE1  = ’RA---TAN’       / Axis 1 represents RA with a tan projection
  CTYPE2  = ’DEC--TAN’       / Axis 2 represents Dec with a tan projection
  CRPIX1  = 100.5            / Pixel coordinates of reference point
  CRPIX2  = 98.4             / Pixel coordinates of reference point
  CRVAL1  = 165.04167        / Degrees equivalent of "11:00:10" hours
  CRVAL2  = -23.433889       / Decimal equivalent of "-23:26:02" degrees
  CD1_1   = -0.0003333333    / Decimal degrees equivalent of -1.2 arc-seconds
  CD2_2   = 0.0003333333     / Decimal degrees equivalent of 1.2 arc-seconds

Notes:

Once you have created these FITS-WCS header card strings, you should store them in a FitsChan and then read the corresponding FrameSet from the FitsChan. How to do this is described in §3.4.

Having created the WCS calibration, you may want to store it in a data file. How to do this is described in §3.15).6

If the required WCS calibration cannot be described as a set of FITS-WCS headers, then a different approach is necessary. In this case, you should first create a Frame describing pixel coordinates, and store this Frame in a new FrameSet. You should then create a new Frame describing the world coordinate system. This Frame may be a specific subclass of Frame such as a SkyFrame for celestial coordinates, a SpecFrame for spectral coordinates, a Timeframe for time coordinates, or a CmpFrame for a combination of different coordinates. You also need to create a suitable Mapping which transforms pixel coordinates into world coordinates. AST provides many different types of Mappings, all of which can be combined together in arbitrary fashions to create more complicated Mappings. The WCS Frame should then be added into the FrameSet, using the Mapping to connect the WCS Frame with the pixel Frame.

3.14 …Modify a WCS Calibration

The usual reason for wishing to modify the WCS calibration associated with a dataset is that the data have been geometrically transformed in some way (here, we will assume a 2-dimensional image dataset). This causes the image features (stars, galaxies, etc.) to move with respect to the grid of pixels which they occupy, so that any coordinate systems previously associated with the image become invalid.

To correct for this, it is necessary to set up a Mapping which expresses the positions of image features in the new data grid in terms of their positions in the old grid. In both cases, the grid coordinates we use will have the first pixel centred at (1,1) with each pixel being a unit square.

AST allows you to correct for any type of geometrical transformation in this way, so long as a suitable Mapping to describe it can be constructed. For purposes of illustration, we will assume here that the new image coordinates XNEW and YNEW can be expressed in terms of the old coordinates XOLD and YOLD as follows:

        DOUBLE PRECISION XNEW, XOLD, YNEW, YOLD
        DOUBLE PRECISION M( 4 ), Z( 2 )
  
        ...
  
        XNEW = XOLD * M( 1 ) + YOLD * M( 2 ) + Z( 1 )
        YNEW = XOLD * M( 3 ) + YOLD * M( 4 ) + Z( 2 )

where M is a 2×2 transformation matrix and Z represents a shift of origin. This is therefore a general linear coordinate transformation which can represent displacement, rotation, magnification and shear.

In AST, it can be represented by concatenating two Mappings. The first is a MatrixMap, which implements the matrix multiplication. The second is a WinMap, which linearly transforms one coordinate window on to another, but will be used here simply to implement the shift of origin (alternatively, a ShiftMap could have been used in place of a WinMap). These Mappings may be constructed and concatenated as follows:

        DOUBLE PRECISION INA( 2 ), INB( 2 ), OUTA( 2 ), OUTB( 2 )
        INTEGER MATRIXMAP, WINMAP
  
        ...
  
  *  Set up the corners of a unit square.
        DATA INA / 2 * 0.0D0 /
        DATA INB / 2 * 1.0D0 /
  
  *  The MatrixMap may be constructed directly from the matrix M.
        MATRIXMAP = AST_MATRIXMAP( 2, 2, 0, M, ’ ’, STATUS )
  
  *  For the WinMap, we take the coordinates of the corners of a unit
  *  square (window) and then shift them by the required amounts.
        OUTA( 1 ) = INA( 1 ) + Z( 1 )
        OUTA( 2 ) = INA( 2 ) + Z( 2 )
        OUTB( 1 ) = INB( 1 ) + Z( 1 )
        OUTB( 2 ) = INB( 2 ) + Z( 2 )
  
  *  The WinMap will then implement this shift.
        WINMAP = AST_WINMAP( 2, INA, INB, OUTA, OUTB, ’ ’, STATUS )
  
  *  Join the two Mappings together, so that they are applied one after
  *  the other.
        NEWMAP = AST_CMPMAP( MATRIXMAP, WINMAP, 1, ’ ’, STATUS )

You might, of course, create any other form of Mapping depending on the type of geometrical transformation involved. For an overview of the Mappings provided by AST, see §2.2, and for a description of the capabilities of each class of Mapping, see its entry in Appendix D. For an overview of how individual Mappings may be combined, see §2.36 gives more details).

Assuming you have obtained a WCS calibration for your original image in the form of a pointer to a FrameSet, WCSINFO1 (§3.4), the Mapping created above may be used to produce a calibration for the new image as follows:

        INTEGER WCSINFO1, WCSINFO2
  
        ...
  
  *  If necessary, make a copy of the WCS calibration, since we are
  *  about to alter it.
        WCSINFO2 = AST_COPY( WCSINFO1, STATUS )
  
  *  Re-map the base Frame so that it refers to the new data grid
  *  instead of the old one.
        CALL AST_REMAPFRAME( WCSINFO2, AST__BASE, NEWMAP, STATUS )

This will produce a pointer, WCSINFO2, to a new FrameSet in which all the coordinate systems associated with the original image are modified so that they are correctly registered with your new image instead.

For more information about re-mapping the Frames within a FrameSet, see §14.4. Also see §14.5 for a similar example to the above, applicable to the case of reducing the size of an image by binning.

3.15 …Write a Modified WCS Calibration to a Dataset

If you have modified the WCS calibration associated with a dataset, such as in the example above (§3.14), then you will need to write the modified version out along with any new data.

In the same way as when reading a WCS calibration (§3.4), how you do this will depend on your data system, but we will assume that you wish to generate a set of FITS header cards that can be stored with the data. You should usually make preparations for doing this when you first read the WCS calibration from your input dataset by modifying the example given in §3.4 as follows:

        INTEGER FITSCHAN1, WCSINFO1
        CHARACTER * ( 20 ) ENCODE
  
        ...
  
  *  Create an input FitsChan and fill it with FITS header cards. Note,
  *  if you have all the header cards in a single string, use AST_PUTCARDS in
  *  place of AST_PUTFITS.
        FITSCHAN1 = AST_FITSCHAN( AST_NULL, AST_NULL, ’ ’, STATUS )
        DO 1 ICARD = 1, NCARD
           CALL AST_PUTFITS( FITSCHAN1, CARDS( ICARD ), .FALSE., STATUS )
   1    CONTINUE
  
  *  Note which encoding has been used for the WCS information.
        ENCODE = AST_GETC( FITSCHAN1, ’Encoding’, STATUS );
  
  *  Rewind the input FitsChan and read the WCS information from it.
        CALL AST_CLEAR( FITSCHAN1, ’Card’, STATUS )
        WCSINFO1 = AST_READ( FITSCHAN1, STATUS )

Note how we have added an enquiry to determine how the WCS information is encoded in the input FITS cards, storing the resulting string in the ENCODE variable. This must be done before actually reading the WCS calibration.

Once you have produced a modified WCS calibration for the output dataset (e.g. §3.14), in the form of a FrameSet identified by the pointer WCSINFO2, you can produce a new FitsChan containing the output FITS header cards as follows:

        INTEGER FITSCHAN2, JUNK, WCSINFO2
  
        ...
  
  *  Make a copy of the input FitsChan, AFTER the WCS information has
  *  been read from it. This will propagate all the input FITS header
  *  cards, apart from those describing the WCS calibration.
        FITSCHAN2 = AST_COPY( FITSCHAN1, STATUS )
  
  *  If necessary, make modifications to the cards in FITSCHAN2
  *  (e.g. you might need to change NAXIS1, NAXIS2, etc., to account for
  *  a change in image size). You probably only need to do this if your
  *  data system does not provide these facilities itself.
        <details not shown - see below>
  
  *  Alternatively, if your data system handles the propagation of FITS
  *  header cards to the output dataset for you, then simply create an
  *  empty FitsChan to contain the output WCS information alone.
  *     FITSCHAN2 = AST_FITSCHAN( AST_NULL, AST_NULL, ’ ’, STATUS )
  
  *  Rewind the new FitsChan (if necessary) and attempt to write the
  *  output WCS information to it using the same encoding method as the
  *  input dataset.
        CALL AST_SET( FITSCHAN2, ’Card=1, Encoding=’ // ENCODE, STATUS )
        IF ( AST_WRITE( FITSCHAN2, WCSINFO2, STATUS ) .EQ. 0 ) THEN
  
  *  If this didn’t work (the WCS FrameSet has become too complex), then
  *  use the native AST encoding instead.
           CALL AST_SETC( FITSCHAN2, ’Encoding’, ’NATIVE’, STATUS );
           JUNK = AST_WRITE( FITSCHAN2, WCSINFO2, STATUS );
        END IF

For details of how to modify the contents of the output FitsChan in other ways, such as by adding, over-writing or deleting header cards, see §16.4, §16.9, §16.8 and §16.13.

Once you have assembled the output FITS cards, you may retrieve them from the FitsChan that contains them as follows:

        CHARACTER * ( 80 ) CARD
  
        ...
  
        CALL AST_CLEAR( FITSCHAN2, ’Card’, STATUS )
   5    CONTINUE
        IF ( AST_FINDFITS( FITSCHAN2, ’%f’, CARD, .TRUE., STATUS ) ) THEN
           WRITE ( *, ’(A)’ ) CARD
           GO TO 5
        END IF

Here, we have simply written each card to the standard output unit, but you would obviously replace this with a subroutine call to store the cards in your output dataset.

For data systems that do not use FITS header cards, a different approach may be needed, possibly involving use of a Channel or XmlChan15) rather than a FitsChan. In the case of the Starlink NDF data format, for example, all of the above may be replaced by a single call to the routine NDF_PTWCS—see SUN/33. The whole process can probably be encapsulated in a similar way for most other data systems, whether they use FITS header cards or not.

For an overview of how to propagate WCS information through data processing steps, see §17.6. For more information about writing WCS information to FitsChans, see §16.5 and §17.7. For information about the options for encoding WCS information in FITS header cards, see §16.1, §17.1, and the description of the Encoding attribute in Appendix C. For a complete understanding of FitsChans and their use with FITS header cards, you should read §16 and §17.

3.16 …Display a Graphical Coordinate Grid

A common requirement when displaying image data is to plot an associated coordinate grid (e.g. Figure 9) over the displayed image.


pdfpict
Figure 9: An example of a displayed image with a coordinate grid plotted over it.


The use of AST in such circumstances is independent of the underlying graphics system, so starting up the graphics system, setting up a coordinate system, displaying the image, and closing down afterwards can all be done using the graphics routines you would normally use.

However, displaying an image at a precise location can be a little fiddly with some graphics systems, and obviously the grid drawn by AST will not be accurately registered with the image unless this is done correctly. In the following template, we therefore illustrate both steps, basing the image display on the PGPLOT graphics package.7 Plotting a coordinate grid with AST then becomes a relatively minor part of what is almost a complete graphics program.

Once again, we assume that a pointer, WCSINFO, to a suitable FrameSet associated with the image has already been obtained (§3.4).

        DOUBLE PRECISION BBOX( 4 )
        INTEGER NX, NY, PGBEG, PLOT
        REAL DATA( NX, NY ), GBOX( 4 ), HI, LO, SCALE, TR( 6 )
        REAL X1, X2, XLEFT, XRIGHT, Y1, Y2, YBOTTOM, YTOP
  
        ...
  
  *  Access the image data, which we assume will be stored in the real
  *  2-dimensional array DATA with dimension sizes NX and NY. Also
  *  derive limits for scaling it, which we assign to the variables HI
  *  and LO.
        <this stage depends on your data system, so is not shown>
  
  *  Open PGPLOT using the device given by environment variable
  *  PGPLOT_DEV and check for success.
        IF ( PGBEG( 0, ’ ’, 1, 1 ) .EQ. 1 ) THEN
  
  *  Clear the screen and ensure equal scales on both axes.
           CALL PGPAGE
           CALL PGWNAD( 0.0, 1.0, 0.0, 1.0 )
  
  *  Obtain the extent of the plotting area (not strictly necessary for
  *  PGPLOT, but possibly for other graphics systems). From this, derive
  *  the display scale in graphics units per pixel so that the image
  *  will fit within the display area.
           CALL PGQWIN( X1, X2, Y1, Y2 )
           SCALE = MIN( ( X2 - X1 ) / NX, ( Y2 - Y1 ) / NY )
  
  *  Calculate the extent of the area in graphics units that the image
  *  will occupy, so as to centre it within the display area.
           XLEFT   = 0.5 * ( X1 + X2 - NX * SCALE )
           XRIGHT  = 0.5 * ( X1 + X2 + NX * SCALE )
           YBOTTOM = 0.5 * ( Y1 + Y2 - NY * SCALE )
           YTOP    = 0.5 * ( Y1 + Y2 + NY * SCALE )
  
  *  Set up a PGPLOT coordinate transformation matrix and display the
  *  image data as a grey scale map (these details are specific to
  *  PGPLOT).
           TR( 1 ) = XLEFT - 0.5 * SCALE
           TR( 2 ) = SCALE
           TR( 3 ) = 0.0
           TR( 4 ) = YBOTTOM - 0.5 * SCALE
           TR( 5 ) = 0.0
           TR( 6 ) = SCALE
           CALL PGGRAY( DATA, NX, NY, 1, NX, 1, NY, HI, LO, TR )
  
  *  BEGINNING OF AST BIT
  *  ====================
  *  Store the locations of the bottom left and top right corners of the
  *  region used to display the image, in graphics coordinates.
           GBOX( 1 ) = XLEFT
           GBOX( 2 ) = YBOTTOM
           GBOX( 3 ) = XRIGHT
           GBOX( 4 ) = YTOP
  
  *  Similarly, store the locations of the image’s bottom left and top
  *  right corners, in pixel coordinates -- with the first pixel centred
  *  at (1,1).
           BBOX( 1 ) = 0.5D0
           BBOX( 2 ) = 0.5D0
           BBOX( 3 ) = NX + 0.5D0
           BBOX( 4 ) = NY + 0.5D0
  
  *  Create a Plot, based on the FrameSet associated with the
  *  image. This attaches the Plot to the graphics surface so that it
  *  matches the displayed image. Specify that a complete set of grid
  *  lines should be drawn (rather than just coordinate axes).
           PLOT = AST_PLOT( WCSINFO, GBOX, BBOX, ’Grid=1’, STATUS )
  
  *  Optionally, we can now set other Plot attributes to control the
  *  appearance of the grid. The values assigned here use the
  *  colour/font indices defined by the underlying graphics system.
           CALL AST_SET( PLOT, ’Colour(grid)=2, Font(textlab)=3’, STATUS )
  
  *  Use the Plot to draw the coordinate grid.
           CALL AST_GRID( PLOT, STATUS )
  
           <maybe some more AST graphics here>
  
  *  Annul the Plot when finished (or use the AST_BEGIN/AST_END
  *  technique shown earlier).
           CALL AST_ANNUL( PLOT, STATUS )
  
  *  END OF AST BIT
  *  ==============
  
  *  Close down the graphics system.
           CALL PGEND
        END IF

Note that once you have set up a Plot which is aligned with a displayed image, you may also use it to generate further graphical output of your own, specified in the image’s world coordinate system (such as markers to represent astronomical objects, annotation, etc.). There is also a range of Plot attributes which gives control over most aspects of the output’s appearance. For details of the facilities available, see §21 and the description of the Plot class in Appendix D.

For details of how to build a graphics program which uses PGPLOT, see §3.3 and the description of the ast_link command in Appendix E.

3.17 …Switch to Plot a Different Celestial Coordinate Grid

Once you have set up a Plot to draw a coordinate grid (§3.16), it is a simple matter to change things so that the grid represents a different celestial coordinate system. For example, after creating the Plot with AST_PLOT, you could use:

        CALL AST_SET( PLOT, ’System=Galactic’, STATUS )

or:

        CALL AST_SET( PLOT, ’System=FK5, Equinox=J2010’, STATUS )

and any axes and/or grid drawn subsequently would represent the new celestial coordinate system you specified. Note, however, that this will only work if the original grid represented celestial coordinates of some kind (see §3.8 for how to determine if this is the case8). If it did not, you will get an error message.

For more information about the celestial coordinate systems available, see the descriptions of the System, Equinox and Epoch attributes in Appendix C.

3.18 …Give a User Control Over the Appearance of a Plot

The idea of using a Plot’s attributes to control the appearance of the graphical output it produces (§3.16 and §3.17) can easily be extended to allow the user of a program complete control over such matters.

For instance, if the file “plot.config” contains a series of plotting options in the form of Plot attribute assignments (see below for an example), then we could create a Plot and implement these assignments before producing the graphical output as follows:

        CHARACTER LINE( 120 )
        INTEGER BASE
  
        ...
  
  *  Create a Plot and define the default appearance of the graphical
  *  output it will produce.
        PLOT = AST_PLOT( WCSINFO, GBOX, PBOX,
       :                 ’Grid=1, Colour(grid)=2, Font(textlab)=3’,
       :                 STATUS )
  
  *  Obtain the value of any Plot attributes we want to preserve.
        BASE = AST_GETI( PLOT, ’Base’, STATUS )
  
  *  Open the plot configuration file, if it exists.
        OPEN ( 1, FILE = ’plot.config’, STATUS = ’OLD’, ERR = 8 )
  
  *  Read each line of text and use it to set new Plot attribute
  *  values. Close the file when done.
   6    CONTINUE
           READ ( 1, ’(A)’, END = 7 ) LINE
           CALL AST_SET( PLOT, LINE, STATUS )
        GO TO 6
   7    CLOSE ( 1 )
   8    CONTINUE
  
  *  Restore any attribute values we are preserving.
        CALL AST_SETI( PLOT, ’Base’, BASE, STATUS )
  
  *  Produce the graphical output (e.g.).
        CALL AST_GRID( PLOT, STATUS )

Notice that we take care that the Plot’s Base attribute is preserved so that the user cannot change it. This is because graphical output will not be produced successfully if the base Frame does not describe the plotting surface to which we attached the Plot when we created it.

The arrangement shown above allows the contents of the “plot.config” file to control most aspects of the graphical output produced (including the coordinate system used; the colour, line style, thickness and font used for each component; the positioning of axes and tick marks; the precision, format and positioning of labels; etc.) via assignments of the form:

  System=Galactic, Equinox = 2001
  Border = 1, Colour( border ) = 1
  Colour( grid ) = 2
  DrawAxes = 1
  Colour( axes ) = 3
  Digits = 8
  Labelling = Interior

For a more sophisticated interface, you could obviously perform pre-processing on this input—for example, to translate words like “red”, “green” and “blue” into colour indices, to permit comments and blank lines, etc.

For a full list of the attributes that may be used to control the appearance of graphical output, see the description of the Plot class in Appendix D. For a complete description of each individual attribute (e.g. those above), see the attribute’s entry in Appendix C.

4The Starlink Software Collection can be downloaded from http://www.starlink.ac.uk/Download/.

5By pixel coordinates, we mean a coordinate system in which the first pixel in the image is centred on (1,1) and each pixel is a unit square. Note that the world coordinates will not necessarily be celestial coordinates, but if they are, then they will be in radians.

6If you are writing the WCS calibration to a FITS file you obviously have the choice of storing the FITS-WCS cards directly.

7An interface is provided with AST that allows it to use PGPLOT (SUN/15) for its graphics, although interfaces to other graphics systems may also be written.

8Note that the methods applied to a FrameSet may be used equally well with a Plot.