
nom.tam.fits.TableHDU Maven / Gradle / Ivy
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 TTYPE
n 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