FITS Table HDUs
FITS Table HDUs store table data. In a given table column, cells may contain more than a single value. In EasyFITS, a FITS Table HDU is represented by an object of type FitsTableDHU.
The elements of a column of a FITS table HDU are stored in the same memory order as in an ordinary Julia array. As a result, the rows of a column in a FITS table HDU correspond to the last index in the equivalent Julia array. Method permutedims can be used is this convention does not suit you.
Reading a single table column
To read a single column in a FITS table HDU as an array arr, call read as:
arr = read(hdu, col)with hdu the Header Data Unit containing the table and col the column name or number. The names of the columns are given by hdu.column_names and valid column numbers are in the range hdu.columns (see Table HDU Properties for a list of all properties). If col is a string or a symbol, keyword case can be used to specify whether uppercase/lowercase matters (case is false by default).
By default, all rows are read but it is possible to specify which rows to read:
arr = read(hdu, col, rows)where rows can be an integer to read a single row, a unit range of integers to read these rows, or a colon : to read all the rows (the default). Properties hdu.first_row and hdu.last_row can be used to retrieve the first and last row numbers of hdu.
The read method automatically guess the number of dimensions and the type of the elements of the Julia array representing the column of a table. To improve type stability, the read method takes an optional first argument to specify the type of the result, from the least specific Array to Array{T} or Array{T,N}. For instance:
arr = read(Vector{Float32}, hdu, col)
arr = read(Vector{Float32}, hdu, col, rows)are both guaranteed to yield an instance of Vector{Float32} (an exception is thrown if the elements of the column cannot be converted to the given type or if the column cells are not scalar numbers).
In fact, the calls read(hdu,col) and read(hdu,col,rows) are respectively equivalent to read(Array,hdu,col) and read(Array,hdu,col,rows).
The read! method can be called to overwrite the contents of an existing array (it must have contiguous entries) with the cells of a column:
read!(arr, hdu, col)where keyword first may be used to specify the first row to read (the first one, hdu.first_row, by default), the number of rows to read being deduced from the size of arr. Other keywords are anynull and null to deal with undefined values.
Reading several table columns
In the most simple form, reading several table columns is done by one of:
dict = read(hdu, cols)
dict = read(hdu, cols, rows)where, as for reading a single column, hdu is the Header Data Unit containing the table and rows may be specified to select the rows to read but cols is a vector or a tuple of column names/numbers, or a colon : to read all columns. Specify keyword case=true if columns are specified by their (symbolic) names and the case of these names matters.
The result of reading several columns is a dictionary whose keys are the names of the columns and whose values are the cells of the columns. The keys of the dictionary are the names of the table columns unconverted if keyword case=true and converted to upper-case letters otherwise. If this is not suitable, use the keyword rename to specify a function to modify the names of the columns. For example, with rename=identity the names of the columns will be left unchanged whatever the keyword case while with rename=lowercase the names of the columns will be converted to lower-case letters.
In order to retrieve the units of the columns, specify keyword units=String and get a dictionary whose values are 2-tuples of the form (data,units) with data the column cells and units the column units as a string. The default behavior, that is to get a dictionary whose values are simply be the cells of the columns, corresponds to units=nothing.
To have a dictionary when cols is a single column name/number, just specify the type of the expected result as the leading argument. For example:
dict = read(Dict, hdu)
dict = read(Dict, hdu, cols)
dict = read(Dict, hdu, cols, rows)Of course, this also works if the cols argument represents several columns without ambiguities.
The leading type argument may be more specific. For example:
dict = read(Dict{String,Array}, hdu, cols)is the same as with Dict, while:
dict = read(Dict{String,Vector}, hdu, cols, rows)can only be successful if all read columns have 0-dimensional cells.
If the leading argument is more specific than Dict, the units=String keyword is not allowed and retrieving the units is done by specifying that the values are tuples of an array and a string. For example:
dict = read(Dict{String,Tuple{Array,String}}, hdu, cols)Using the leading type argument, it is also possible to retrieve a vector of the table columns (in the same order as specified in cols). For example:
vect = read(Vector, hdu, cols)
vect = read(Vector, hdu, cols, rows)
vect = read(Vector{Array}, hdu, cols, rows)It is also possible to retrieve the units at the same time:
vect = read(Vector, hdu, cols; units=String)
vect = read(Vector, hdu, cols, rows; units=String)
vect = read(Vector{Tuple{Array,String}}, hdu, cols, rows)With the read! method, the contents of an existing dictionary may be replaced by columns from a FITS table:
read!(dict, hdu)
read!(dict, hdu, cols)
read!(dict, hdu, cols, rows)where, as for the read method, keywords case and rename may be supplied. Call the merge! method instead to preserve pre-existing contents:
merge!(dict, hdu)
merge!(dict, hdu, cols)
merge!(dict, hdu, cols, rows)With the push! method, a vector of columns can be augmented with additional columns:
push!(vect, hdu)
push!(vect, hdu, cols)
push!(vect, hdu, cols, rows)Creating a table HDU
To create a new FITS table HDU in the FITS file file, call:
hdu = write(file, FitsTableHDU, cols)with cols defining the columns of the table. Each column definition is a pair name => format where name is the column name while format specifies the type of the column values and, optionally, their units and the size of the column cells. The following definitions are possible:
name => type
name => (type,)
name => (type, units)
name => (type, dims)
name => (type, units, dims)
name => (type, dims, units)where type is either a Julia type (Number or String) or a letter (see table below), dims is an integer or a tuple of integers, and units is a string. By default, dims = (1,) and units = "".
| Type | Letter | Remarks |
|---|---|---|
AbstractString | 'A' | ASCII string |
Bool | 'L' | |
Int8 | 'S' | CFITSIO specific |
UInt8 | 'B' | |
Int16 | 'I' | |
UInt16 | 'U' | CFITSIO specific |
Int32 | 'J' | |
UInt32 | 'V' | CFITSIO specific |
Int64 | 'K' | |
UInt64 | 'W' | CFITSIO specific |
Float32 | 'E' | |
Float64 | 'D' | |
Complex{Float32} | 'C' | |
Complex{Float64} | 'M' | |
FitsBit | 'X' | bits |
The returned object, hdu, can be used to add FITS keywords to the header of the table and, then, to write column data. Typically:
hdu = write(file, FitsTableHDU, cols)
push!(hdu, key1 => val1) # add a first header keyword
push!(hdu, key2 => (val2, com2)) # add a second header keyword with a comment
... # add other header keywords
write(hdu, col1 => arr1) # write a first column
write(hdu, col2 => arr2) # write a second column
... # write other columnswhere key1 => val1, key2 => (val2,com2), etc. specify header cards, while col1 => arr1, col2 => arr2, etc. specify columns names and associated data. Such a table may be created in a single call:
write(file,
[key1 => val1, key2 => (val2, com2), ...],
[col1 => arr1, col2 => arr2, ...])which follows the write(dest, header, data) convention in EasyFITS with dest the destination, header the header, and data the data.
The header may be specified in any forms accepted by the EasyFITS methods. Similarly, the columns may be specified in various forms as explained below.
Writing table columns
To write a single column into the FITS table HDU hdu:
write(hdu, col => arr, ...; first=hdu.first_row, case=false, null=nothing) -> hduwhere col is the column name/number and arr is an array of column values. Column values are converted as needed and are written starting at the row specified by first. The leading dimensions of arr should be the same as those specified by the corresponding TDIMn keyword (with n the column number) and the remaining last dimension, if any, corresponds to the row index of the table.
If col is a column name, keyword case may be used to indicate whether case of letters matters (default is false).
Keyword null may be used to specify the value of undefined elements in arr.
Any number of columns may be specified as subsequent arguments. The same keywords apply to all columns.
Table HDU Properties
The following table lists all properties of a FITS table HDU.
| Property | Description |
|---|---|
nrows | Number of rows |
rows | Index range of rows |
first_row | Index of first row |
last_row | Index of last row |
ncols | Number of columns |
columns | Index range of columns |
first_column | Index of first column |
last_column | Index of last column |
column_name | Column name accessor |
column_names | Column names |
column_number | Column number accessor |
column_units | Column units accessor |
data_size | Table dimensions |
data_ndims | Number of table dimensions |
data_axes | Indices along table dimensions |
extname | Extension name |
hduname | HDU name |
file | Associated FITS file |
num | HDU number |
type | HDU type: FITS_BINARY_TABLE_HDU or FITS_ASCII_TABLE_HDU |
xtension | Extension name: "BINTABLE" or "TABLE" |
To retrieve the units, the number, or the name of column col in the FITS table hdu object, use the properties column_units, column_number, or column_name properties as follows:
hdu.column_units(col; case=false) -> units::String
hdu.column_name(col; case=false) -> name::String
hdu.column_number(col; case=false) -> number::IntKeyword case specifies whether the case of letters does matters when col is a (symbolic) name. The result of hdu.column_units(col) is always a string, possibly empty.