All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nom.tam.fits.TableHDU Maven / Gradle / Ivy

Go to download

Java library for reading and writing FITS files. FITS, the Flexible Image Transport System, is the format commonly used in the archiving and transport of astronomical data.

There is a newer version: 1.21.0
Show newest version
package nom.tam.fits;

import nom.tam.fits.header.GenericKey;
import nom.tam.fits.header.IFitsHeader;

import static nom.tam.fits.header.Standard.NAXISn;
import static nom.tam.fits.header.Standard.TFIELDS;
import static nom.tam.fits.header.Standard.TFORMn;
import static nom.tam.fits.header.Standard.TTYPEn;

/*
 * #%L
 * nom.tam FITS library
 * %%
 * Copyright (C) 2004 - 2024 nom-tam-fits
 * %%
 * This is free and unencumbered software released into the public domain.
 *
 * Anyone is free to copy, modify, publish, use, compile, sell, or
 * distribute this software, either in source code form or as a compiled
 * binary, for any purpose, commercial or non-commercial, and by any
 * means.
 *
 * In jurisdictions that recognize copyright laws, the author or authors
 * of this software dedicate any and all copyright interest in the
 * software to the public domain. We make this dedication for the benefit
 * of the public at large and to the detriment of our heirs and
 * successors. We intend this dedication to be an overt act of
 * relinquishment in perpetuity of all present and future rights to this
 * software under copyright law.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 * #L%
 */

/**
 * Base class for binary and ASCII table implementations.
 *
 * @param  the generic type of table data contained in this HDU instance.
 */
@SuppressWarnings("deprecation")
public abstract class TableHDU extends BasicHDU {

    /**
     * Returns the default name for a columns with the specified index, to use if no column name was explicitly defined
     * 
     * @param  col The zero-based Java index of the column
     * 
     * @return     The default column name to use if no other name was defined.
     * 
     * @since      1.20
     * 
     * @author     Attila Kovacs
     * 
     * @see        #setColumnName(int, String, String)
     */
    public static String getDefaultColumnName(int col) {
        return "Column " + (col + 1);
    }

    /**
     * Create the TableHDU. Note that this will normally only be invoked by subclasses in the FITS package.
     *
     * @deprecated     intended for internal use. Its visibility should be reduced to package level in the future.
     * 
     * @param      hdr the header
     * @param      td  The data for the table.
     */
    protected TableHDU(Header hdr, T td) {
        super(hdr, td);
    }

    /**
     * Add a column to the table without any associated header information.
     *
     * @param  newCol        the new column information. the newCol should be an Object[] where type of all of the
     *                           constituents is identical. The length of data should match the other columns. 
     *                           Note: It is valid for data to be a 2 or higher dimensionality primitive array. In
     *                           this case the column index is the first (in Java speak) index of the array. E.g., if
     *                           called with int[30][20][10], the number of rows in the table should be 30 and this
     *                           column will have elements which are 2-d integer arrays with TDIM = (10,20).
     *
     * @return               the number of columns in the adapted table
     *
     * @throws FitsException if the operation failed
     */
    public int addColumn(Object newCol) throws FitsException {
        int nCols = getNCols();
        myHeader.findCard(TFIELDS).setValue(nCols);
        return nCols;
    }

    /**
     * Add a row to the end of the table. If this is the first row, then this will add appropriate columns for each of
     * the entries. The rows to add must be supplied as column based array of arrays.
     *
     * @return               the number of rows in the adapted table
     *
     * @param  newRows       rows to add to the table
     *
     * @throws FitsException if the operation failed
     */
    public int addRow(Object[] newRows) throws FitsException {
        int row = myData.addRow(newRows);
        myHeader.findCard(NAXISn.n(2)).setValue(getNRows());
        return row;
    }

    /**
     * Returns the list of column description keyword stems that descrive this column in the FITS header.
     * 
     * @return the stems of the keywords that are associated with table columns. Users can supplement this with their
     *             own and call the appropriate deleteColumns fields.
     */
    protected abstract IFitsHeader[] columnKeyStems();

    /**
     * Delete a set of columns from a table.
     *
     * @param      column        The one-indexed start column.
     * @param      len           The number of columns to delete.
     *
     * @throws     FitsException if the operation failed
     * 
     * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
     *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
     *                               HDU and editing the header as necessary to incorporate custom entries. May be
     *                               removed from the API in the future.
     */
    public void deleteColumnsIndexOne(int column, int len) throws FitsException {
        deleteColumnsIndexZero(column - 1, len);
    }

    /**
     * Delete a set of columns from a table.
     *
     * @param      column        The one-indexed start column.
     * @param      len           The number of columns to delete.
     * @param      fields        Stems for the header fields to be removed for the table.
     *
     * @throws     FitsException if the operation failed
     * 
     * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
     *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
     *                               HDU and editing the header as necessary to incorporate custom entries. May be
     *                               removed from the API in the future.
     */
    public void deleteColumnsIndexOne(int column, int len, String[] fields) throws FitsException {
        deleteColumnsIndexZero(column - 1, len, GenericKey.create(fields));
    }

    /**
     * Delete a set of columns from a table.
     *
     * @param      column        The one-indexed start column.
     * @param      len           The number of columns to delete.
     *
     * @throws     FitsException if the operation failed
     * 
     * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
     *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
     *                               HDU and editing the header as necessary to incorporate custom entries. May be
     *                               removed from the API in the future.
     */
    public void deleteColumnsIndexZero(int column, int len) throws FitsException {
        deleteColumnsIndexZero(column, len, columnKeyStems());
    }

    /**
     * Delete a set of columns from a table.
     *
     * @param      column        The zero-indexed start column.
     * @param      len           The number of columns to delete.
     * @param      fields        Stems for the header fields to be removed for the table.
     *
     * @throws     FitsException if the operation failed
     * 
     * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
     *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
     *                               HDU and editing the header as necessary to incorporate custom entries. May be
     *                               removed from the API in the future.
     */
    public void deleteColumnsIndexZero(int column, int len, IFitsHeader[] fields) throws FitsException {

        if (column < 0 || len < 0 || column + len > getNCols()) {
            throw new FitsException("Illegal columns deletion request- Start:" + column + " Len:" + len
                    + " from table with " + getNCols() + " columns");
        }

        if (len == 0) {
            return;
        }

        int ncol = getNCols();
        myData.deleteColumns(column, len);

        // Get rid of the keywords for the deleted columns
        for (int col = column; col < column + len; col++) {
            for (IFitsHeader field : fields) {
                myHeader.deleteKey(field.n(col + 1));
            }
        }

        // Shift the keywords for the columns after the deleted columns
        for (int col = column + len; col < ncol; col++) {
            for (IFitsHeader field : fields) {
                IFitsHeader oldKey = field.n(col + 1);
                IFitsHeader newKey = field.n(col + 1 - len);
                if (myHeader.containsKey(oldKey)) {
                    myHeader.replaceKey(oldKey, newKey);
                }
            }
        }
        // Update the number of fields.
        myHeader.getCard(TFIELDS).setValue(getNCols());

        // Give the data sections a chance to update the header too.
        myData.updateAfterDelete(ncol, myHeader);
    }

    /**
     * Remove all rows from the table starting at some specific index from the table. Inspired by a routine by R. Mathar
     * but re-implemented using the DataTable and changes to AsciiTable so that it can be done easily for both Binary
     * and ASCII tables.
     *
     * @param      row           the (0-based) index of the first row to be deleted.
     *
     * @throws     FitsException if an error occurs.
     * 
     * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
     *                               {@link TableData#deleteRows(int, int)} to edit tables before wrapping them in an
     *                               HDU and editing the header as necessary to incorporate custom entries. May be
     *                               removed from the API in the future.
     */
    public void deleteRows(final int row) throws FitsException {
        deleteRows(row, getNRows() - row);
    }

    /**
     * Remove a number of adjacent rows from the table. This routine was inspired by code by R.Mathar but re-implemented
     * using changes in the ColumnTable class abd AsciiTable so that we can do it for all FITS tables.
     *
     * @param      firstRow      the (0-based) index of the first row to be deleted. This is zero-based indexing:
     *                               0<=firstrow< number of rows.
     * @param      nRow          the total number of rows to be deleted.
     *
     * @throws     FitsException If an error occurs in the deletion.
     * 
     * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
     *                               {@link TableData#deleteRows(int, int)} to edit tables before wrapping them in an
     *                               HDU and editing the header as necessary to incorporate custom entries. May be
     *                               removed from the API in the future.
     */
    public void deleteRows(final int firstRow, int nRow) throws FitsException {

        // Just ignore invalid requests.
        if (nRow <= 0 || firstRow >= getNRows() || firstRow <= 0) {
            return;
        }

        /* correct if more rows are requested than available */
        if (nRow > getNRows() - firstRow) {
            nRow = getNRows() - firstRow;
        }

        myData.deleteRows(firstRow, nRow);
        myHeader.setNaxis(2, getNRows());
    }

    /**
     * Find the 0-based column index corresponding to a particular column name.
     *
     * @return         index of the column
     *
     * @param  colName the name of the column
     */
    public int findColumn(String colName) {
        for (int i = 0; i < getNCols(); i++) {
            String val = myHeader.getStringValue(TTYPEn.n(i + 1));
            if (val != null && val.trim().equals(colName)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 

* Returns the data for a particular column in as an array of elements. See {@link TableData#addColumn(Object)} for * more information about the format of data elements in general. *

* * @param col The 0-based column index. * * @return an array of primitives (for scalar columns), or else an Object[] array, or * possibly null * * @throws FitsException if the table could not be accessed * * @see TableData#getColumn(int) * @see #setColumn(int, Object) * @see #getElement(int, int) * @see #getNCols() */ public Object getColumn(int col) throws FitsException { return myData.getColumn(col); } /** *

* Returns the data for a particular column in as an array of elements. See {@link TableData#addColumn(Object)} for * more information about the format of data elements in general. *

* * @param colName The name or ID of the column as stored by the TTYPEn FITS header * keyword. * * @return an array of primitives (for scalar columns), or else an Object[] array, or * possibly null * * @throws FitsException if the table could not be accessed * * @see TableData#getColumn(int) * @see #setColumn(int, Object) * @see #getElement(int, int) * @see #getNCols() */ public Object getColumn(String colName) throws FitsException { return getColumn(findColumn(colName)); } /** * Get the FITS type of a column in the table. * * @param index The 0-based index of the column. * * @return The FITS type. * * @throws FitsException if an invalid index was requested. */ public String getColumnFormat(int index) throws FitsException { int flds = myHeader.getIntValue(TFIELDS, 0); if (index < 0 || index >= flds) { throw new FitsException("Bad column index " + index + " (only " + flds + " columns)"); } return myHeader.getStringValue(TFORMn.n(index + 1)).trim(); } /** * Convenience method for getting column data. Note that this works only for metadata that returns a string value. * This is equivalent to getStringValue(type+index); * * @return meta data string value * * @param index index of the colum * @param type the key type to get */ public String getColumnMeta(int index, String type) { return myHeader.getStringValue(type + (index + 1)); } /** * Gets the name of a column in the table, as it appears in this HDU's header. It may differ from a more currently * assigned name of the binary table data column after the HDU creation or reading. * * @param index The 0-based column index. * * @return The column name. * * @see BinaryTable.ColumnDesc#name() */ public String getColumnName(int index) { String ttype = myHeader.getStringValue(TTYPEn.n(index + 1)); if (ttype != null) { ttype = ttype.trim(); } return ttype; } /** *

* Returns the data for all columns in as an array. See {@link TableData#addColumn(Object)} for more information * about the column format of each element in the returned array. *

* * @return An array containing the column data for all columns. Each entry in the returned array is * itself an array of primitives (for scalar columns), or else an Object[] * array, or possibly null. * * @throws FitsException if the table could not be accessed * * @see TableData#getColumn(int) * @see #setColumn(int, Object) * @see #getElement(int, int) * @see #getNCols() */ public Object[] getColumns() throws FitsException { Object[] result = new Object[getNCols()]; for (int i = 0; i < result.length; i++) { result[i] = getColumn(i); } return result; } /** * Returns a specific element from this table * * @return a specific element of the table using 0-based indices. * * @param row the row index of the element * @param col the column index of the element * * @throws FitsException if the operation failed * * @see #getElement(int, int) */ public Object getElement(int row, int col) throws FitsException { return myData.getElement(row, col); } /** * Get the number of columns for this table * * @return The number of columns in the table. */ public int getNCols() { return myData.getNCols(); } /** * Get the number of rows for this table * * @return The number of rows in the table. */ public int getNRows() { return myData.getNRows(); } /** * Returns a specific row from this table * * @return a specific row of the table. * * @param row the index of the row to retreive * * @throws FitsException if the operation failed * * @see #setRow(int, Object[]) */ public Object[] getRow(int row) throws FitsException { return myData.getRow(row); } /** * Update a column within a table. The new column should have the same format ast the column being replaced. See * {@link TableData#addColumn(Object)} for more information about the column data format. * * @param col index of the column to replace * @param newCol the replacement column * * @throws FitsException if the operation failed * * @see #getColumn(int) * @see #setColumn(String, Object) * @see TableData#addColumn(Object) */ public void setColumn(int col, Object newCol) throws FitsException { myData.setColumn(col, newCol); } /** * Update a column within a table. The new column should have the same format as the column being replaced. See * {@link TableData#addColumn(Object)} for more information about the column data format. * * @param colName name of the column to replace * @param newCol the replacement column * * @throws FitsException if the operation failed * * @see #getColumn(String) * @see #setColumn(int, Object) * @see TableData#addColumn(Object) */ public void setColumn(String colName, Object newCol) throws FitsException { setColumn(findColumn(colName), newCol); } /** * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to * be organized together. * * @param index The 0-based index of the column * @param key The column key. I.e., the keyword will be key+(index+1) * @param value The value to be placed in the header. * @param comment The comment for the header * @param after Should the header card be after the current column metadata block * (true), or immediately before the TFORM card (false). * * @throws HeaderCardException if the header could not be updated */ public void setColumnMeta(int index, IFitsHeader key, String value, String comment, boolean after) throws HeaderCardException { setCurrentColumn(index, after); myHeader.addLine(new HeaderCard(key.n(index + 1).key(), value, comment)); } /** * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to * be organized together. * * @param index The 0-based index of the column * @param key The column key. I.e., the keyword will be key+(index+1) * @param value The value to be placed in the header. * @param comment The comment for the header * @param after Should the header card be after the current column metadata block * (true), or immediately before the TFORM card (false). * * @throws HeaderCardException if the header could not be updated * * @since 1.16 */ public void setColumnMeta(int index, IFitsHeader key, Number value, String comment, boolean after) throws HeaderCardException { setCurrentColumn(index, after); myHeader.addLine(new HeaderCard(key.n(index + 1).key(), value, comment)); } /** * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to * be organized together. * * @param index The 0-based index of the column * @param key The column key. I.e., the keyword will be key+(index+1) * @param value The value to be placed in the header. * @param comment The comment for the header * @param after Should the header card be after the current column metadata block * (true), or immediately before the TFORM card (false). * * @throws HeaderCardException if the header could not be updated */ public void setColumnMeta(int index, String key, Boolean value, String comment, boolean after) throws HeaderCardException { setCurrentColumn(index, after); myHeader.addLine(new HeaderCard(key + (index + 1), value, comment)); } /** * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to * be organized together. * * @param index The 0-based index of the column * @param key The column key. I.e., the keyword will be key+(index+1) * @param value The value to be placed in the header. * @param comment The comment for the header * @param after Should the header card be after the current column metadata block * (true), or immediately before the TFORM card (false). * * @throws HeaderCardException if the header could not be updated */ public void setColumnMeta(int index, String key, Number value, String comment, boolean after) throws HeaderCardException { setCurrentColumn(index, after); myHeader.addLine(new HeaderCard(key + (index + 1), value, comment)); } /** * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to * be organized together. * * @param index The 0-based index of the column * @param key The column key. I.e., the keyword will be key+(index+1) * @param value The value to be placed in the header. * @param precision The maximum number of decimal places to show after the leading figure. (Trailing * zeroes will be ommitted.) * @param comment The comment for the header * @param after Should the header card be after the current column metadata block * (true), or immediately before the TFORM card (false). * * @throws HeaderCardException if the header could not be updated */ public void setColumnMeta(int index, String key, Number value, int precision, String comment, boolean after) throws HeaderCardException { setCurrentColumn(index, after); myHeader.addLine(new HeaderCard(key + (index + 1), value, precision, comment)); } /** * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to * be organized together. * * @param index The 0-based index of the column * @param key The column key. I.e., the keyword will be key+(index+1) * @param value The value to be placed in the header. * @param comment The comment for the header * * @throws HeaderCardException if the header could not be updated */ public void setColumnMeta(int index, String key, String value, String comment) throws HeaderCardException { setColumnMeta(index, key, value, comment, true); } /** * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to * be organized together. * * @param index The 0-based index of the column * @param key The column key. I.e., the keyword will be key+(index+1) * @param value The value to be placed in the header. * @param comment The comment for the header * @param after Should the header card be after the current column metadata block (true), or * immediately before the TFORM card (false). @throws FitsException if the * operation failed * * @throws HeaderCardException if the header could not be updated * * @deprecated use {@link #setColumnMeta(int, IFitsHeader, String, String, boolean)} */ @Deprecated public void setColumnMeta(int index, String key, String value, String comment, boolean after) throws HeaderCardException { setCurrentColumn(index, after); myHeader.addLine(new HeaderCard(key + (index + 1), value, comment)); } /** * Sets the name / ID of a specific column in this table. Naming columns is generally a good idea so that people can * figure out what sort of data actually appears in specific table columns. * * @param index the column index * @param name the name or ID we want to assing to the column * @param comment Any additional comment we would like to store alongside in the FITS header. * (The comment may be truncated or even ommitted, depending on space * constraints in the FITS header. * * @throws IndexOutOfBoundsException if the table has no column matching the index * @throws HeaderCardException if there was a problem wil adding the associated descriptive FITS header * keywords to this table's header. * * @see #getColumnName(int) * @see #getDefaultColumnName(int) */ public void setColumnName(int index, String name, String comment) throws IndexOutOfBoundsException, HeaderCardException { if (index < 0 || index >= getNCols()) { throw new IndexOutOfBoundsException( "column index " + index + " is out of bounds for table with " + getNCols() + " columns"); } setColumnMeta(index, TTYPEn, name, comment, true); } /** * Set the cursor in the header to point after the metadata for the specified column * * @param col The 0-based index of the column * * @deprecated (for internal use) Will be removed int the future (no longer used). */ public void setCurrentColumn(int col) { setCurrentColumn(col, true); } /** * Set the cursor in the header to point either before the TFORMn value or after the column metadata * * @param col The 0-based index of the column * @param after True if the cursor should be placed after the existing column metadata or false if the cursor * is to be placed before the TFORM value. If no corresponding TFORM is found, the cursor will * be placed at the end of current header. * * @deprecated (for internal use) Will have private access in the future. */ public void setCurrentColumn(int col, boolean after) { if (after) { myHeader.positionAfterIndex(TFORMn, col + 1); } else { myHeader.findCard(TFORMn.n(col + 1)); } } /** * Update a single element within the table. * * @param row the row index * @param col the column index * @param element the replacement element * * @throws FitsException if the operation failed * * @see #getElement(int, int) */ public void setElement(int row, int col, Object element) throws FitsException { myData.setElement(row, col, element); } /** * Update a row within a table. * * @param row row index * @param newRow the replacement row * * @throws FitsException if the operation failed * * @see #getRow(int) */ public void setRow(int row, Object[] newRow) throws FitsException { myData.setRow(row, newRow); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy