GNU Astronomy Utilities



12.4.4 Library demo - reading and writing table columns

Tables are some of the most common inputs to, and outputs of programs. This section contains a small program for reading and writing tables using the constructs described in Table input output (table.h). For easy linking/compilation of this program, along with a first run, see Gnuastro’s BuildProgram. Before running, also set the following file and column names in the first two lines of main. The input and output names may be .txt and .fits tables, gal_table_read and gal_table_write will be able to write to both formats. For plain text tables see Gnuastro text table format. If you do not have any table in text file format to use as your input, you can use the table that is generated in Sufi simulates a detection section.

This example program reads three columns from a table. The first two columns are selected by their name (NAME1 and NAME2) and the third is selected by its number: column 10 (counting from 1). Gnuastro’s column selection is discussed in Selecting table columns. The first and second columns can be any type, but this program will convert them to int32_t and float for its internal usage respectively. However, the third column must be double for this program. So if it is not, the program will abort with an error. Having the columns in memory, it will print them out along with their sum (just a simple application, you can do what ever you want at this stage). Reading the table finishes here.

The rest of the program is a demonstration of writing a table. While parsing the rows, this program will change the first column (to be counters) and multiply the second by 10 (so the output will be different). Then it will define the order of the output columns by setting the next element (to create a List of gal_data_t). Before writing, this function will also set names for the columns (units and comments can be defined in a similar manner). Writing the columns to a file is then done through a simple call to gal_table_write.

The operations that are shown in this example program are not necessary all the time. For example, in many cases, you know the numerical data type of the column before writing your program (see Numeric data types), so type checking and copying to a specific type will not be necessary.

To encourage good coding practices, this script contains a copyright notice with a place holder for your name and your email (as you customize it for your own purpose). Always keep a one-line description and copyright notice like this in all your scripts, such “metadata” is very important to accompany every source file you write. Of course, when you write the source file from scratch and just learn how to use a single function from this manual, only your name/year should appear. The existing name of the original author of this example program is only for cases where you copy-paste this whole file.

/* Reading and writing table columns.
 *
 * This example program reads three columns from a table. Having the
 * columns in memory, it will print them out along with their sum. The
 * rest of the program is a demonstration of writing a table.
 *
 * Copyright (C) 2024      Your Name <your@@email.address>
 * Copyright (C) 2020-2024 Mohammad Akhlaghi <mohammad@@akhlaghi.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>

#include <gnuastro/table.h>

int
main(void)
{
  /* File names and column names (which may also be numbers). */
  char *c1_name="NAME1", *c2_name="NAME2", *c3_name="10";
  char *inname="input.fits", *hdu="1", *outname="out.fits";

  /* Internal parameters. */
  float *array2=NULL;
  double *array3=NULL;
  int32_t *array1=NULL;
  size_t i, counter=0;
  gal_data_t *c1=NULL;
  gal_data_t *c2=NULL;
  gal_data_t tmp, *col, *columns;
  gal_list_str_t *column_ids=NULL;

  /* Define the columns to read. */
  gal_list_str_add(&column_ids, c1_name, 0);
  gal_list_str_add(&column_ids, c2_name, 0);
  gal_list_str_add(&column_ids, c3_name, 0);

  /* The columns were added in reverse, so correct it. */
  gal_list_str_reverse(&column_ids);

  /* Read the desired columns. */
  columns = gal_table_read(inname, hdu, NULL, column_ids,
                           GAL_TABLE_SEARCH_NAME, 0, 1, -1, 1, NULL);

  /* Go over the columns, we will assume that you do not know their type
   * a-priori, so we will check  */
  counter=1;
  for(col=columns; col!=NULL; col=col->next)
    switch(counter++)
      {
      case 1:              /* First column: we want it as int32_t. */
        c1=gal_data_copy_to_new_type(col, GAL_TYPE_INT32);
        array1 = c1->array;
        break;

      case 2:              /* Second column: we want it as float.  */
        c2=gal_data_copy_to_new_type(col, GAL_TYPE_FLOAT32);
        array2 = c2->array;
        break;

      case 3:              /* Third column: it MUST be double.     */
        if(col->type!=GAL_TYPE_FLOAT64)
          {
            fprintf(stderr, "Column %s must be float64 type, it is "
                    "%s", c3_name, gal_type_name(col->type, 1));
            exit(EXIT_FAILURE);
          }
        array3 = col->array;
        break;

      default:
        exit(EXIT_FAILURE);
      }

  /* As an example application we will just print them out. In the
   * meantime (just for a simple demonstration), change the first
   * array value to the counter and multiply the second by 10. */
  for(i=0;i<c1->size;++i)
    {
      printf("%zu: %d + %f + %f = %f\n", i+1, array1[i], array2[i],
             array3[i], array1[i]+array2[i]+array3[i]);
      array1[i]  = i+1;
      array2[i] *= 10;
    }

  /* Link the first two columns as a list. */
  c1->next = c2;
  c2->next = NULL;

  /* Set names for the columns and write them out. */
  c1->name = "COUNTER";
  c2->name = "VALUE";
  gal_table_write(c1, NULL, NULL, GAL_TABLE_FORMAT_BFITS, outname,
                  "MY-COLUMNS", 0, 0);

  /* The names were not allocated, so to avoid cleaning-up problems,
   * we will set them to NULL. */
  c1->name = c2->name = NULL;

  /* Clean up and return.  */
  gal_data_free(c1);
  gal_data_free(c2);
  gal_list_data_free(columns);
  gal_list_str_free(column_ids, 0); /* strings were not allocated. */
  return EXIT_SUCCESS;
}