gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master de296c99: Table: column arithmetic can now use


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master de296c99: Table: column arithmetic can now use newly added columns
Date: Sat, 25 Jun 2022 22:16:47 -0400 (EDT)

branch: master
commit de296c99e646fa688161285301d1a7dfaaaf930f
Author: Mohammad Akhlaghi <mohammad@akhlaghi.org>
Commit: Mohammad Akhlaghi <mohammad@akhlaghi.org>

    Table: column arithmetic can now use newly added columns
    
    Until now, column arithmetic could only use columns of the main input, not
    any of the columns that were added with '--catcolumnfile'! This was
    annoying when you wanted to do some operations based on mixing two sets of
    columns.
    
    With this commit, arithmetic can now work on the final set of columns. To
    do this, it was necessary to make some modifications to the core structure
    for keeping arithmetic information.
    
    In the process, I also corrected the way that a suffix is added to columns
    after '--catcolumnfile': until now a suffix would always be added! But now,
    a suffix is only added if the same name already exists in the table.
    
    This fixes bug #62674.
---
 NEWS                   |   7 +++
 bin/table/arithmetic.c | 156 ++++++++++++++++++++++++++++++++++++++++++-------
 bin/table/arithmetic.h |   6 +-
 bin/table/main.h       |   6 +-
 bin/table/table.c      |  23 +++++---
 bin/table/ui.c         |  77 ++++++++++++++----------
 doc/gnuastro.texi      |  22 +++++--
 7 files changed, 228 insertions(+), 69 deletions(-)

diff --git a/NEWS b/NEWS
index b306c303..97437a58 100644
--- a/NEWS
+++ b/NEWS
@@ -101,6 +101,12 @@ See the end of the file for license conditions.
      functionality was proposed by Elham Saremi.
 
   Table:
+   --catcolumnfile: the '-N' suffix (where 'N' is a counter for the files
+     with concatenated, or appended, column) is only added if a column with
+     a identical column name (not case sensitive) existed in the
+     table. Until now, this suffix would be added to all the newly
+     concatenated columns (recall that the suffix addition can be disabled
+     in general with the '--catcolumnrawname' option).
    --rowrange: new name for the old '--rowlimit'. This option takes the
      range of desired rows based on their position (for example
      '--rowrange=2,5' will only print rows 2, 3, 4 and 5 of the table). But
@@ -142,6 +148,7 @@ See the end of the file for license conditions.
               called. Reported by Sepideh Eskandarlou.
   bug #62662: Table crashes when column arithmetic is applied after adding
               rows from another file (with '--catrowfile').
+  bug #62674: Column arithmetic can't use columns from --catcolumnfile.
 
 
 
diff --git a/bin/table/arithmetic.c b/bin/table/arithmetic.c
index 4e88c841..f5c38ed3 100644
--- a/bin/table/arithmetic.c
+++ b/bin/table/arithmetic.c
@@ -61,7 +61,9 @@ arithmetic_add_new_to_end(struct arithmetic_token **list)
   node->name_def=NULL;
   node->name_use=NULL;
   node->constant=NULL;
+  node->id_at_usage=NULL;
   node->index=GAL_BLANK_SIZE_T;
+  node->num_at_usage=GAL_BLANK_SIZE_T;
   node->operator=GAL_ARITHMETIC_OP_INVALID;
 
   /* If the list already has elements, go to the last node in the list and
@@ -216,15 +218,72 @@ arithmetic_set_operator(struct tableparams *p, char 
*string,
 
 
 
+/* When a column identifier (name or number) is identified, we need to make
+   sure if that the identifier belongs to the first input or not. */
+static void
+arithmetic_init_addcol(char *token, struct arithmetic_token *node,
+                       gal_list_str_t **colstoread, size_t *totcalled,
+                       gal_data_t *colinfo, size_t numcols)
+{
+  char *id;
+  int inmaininput=0;
+  size_t i, num=GAL_BLANK_SIZE_T;
+
+  /* This needs to be defined after 'num'. */
+  void *numptr=&num;
+
+  /* Set the identifier. */
+  id = ( (token[0]=='$' && isdigit(token[1]))
+         ? &token[1]       /* Column num. (starting with '$'). */
+         : token );        /* Column name, just add it.        */
+
+  /* See if the column identifier is a number, then 'num' will not be a
+     blank value. */
+  if( gal_type_from_string(&numptr, id, GAL_TYPE_SIZE_T) )
+    num=GAL_BLANK_SIZE_T;
+
+  /* See if the column exists in the main input catalog. */
+  if(num==GAL_BLANK_SIZE_T)     /* ID is a string. */
+    {
+      for(i=0;i<numcols;++i)
+        if( !strcasecmp(id, colinfo[i].name) )
+          { inmaininput=1; break; }
+    }
+  else                          /* ID is a number. */
+    if(num<=numcols) inmaininput=1;
+
+  /* If the given ID is in the main input, then add it to the list of
+     columns to read ('colstoread') from the main input. Otherwise, keep
+     the ID for usage at the time of arithmetic (can happen when
+     '--catcolumnfile' is used).*/
+  if(inmaininput)
+    {
+      gal_list_str_add(colstoread, id, 1);
+      node->index=*totcalled;
+      *totcalled+=1;
+    }
+  else
+    {
+      gal_checkset_allocate_copy(id, &node->id_at_usage); /* Future usage. */
+      node->num_at_usage=num;   /* Avoid converting to a number again! */
+      node->index=GAL_BLANK_SIZE_T; /* Crash if not used properly! */
+    }
+}
+
+
+
+
+
 /* Initialize each column from an arithmetic operation. */
 void
 arithmetic_init(struct tableparams *p, struct arithmetic_token **arith,
-                gal_list_str_t **toread, size_t *totcalled, char *expression)
+                gal_list_str_t **colstoread, size_t *totcalled,
+                char *expression, gal_data_t *colinfo, size_t numcols)
 {
   void *num;
   size_t one=1;
   uint8_t ntype;
-  char *str, *delimiter=" \t";
+  char *delimiter=" \t";
   struct arithmetic_token *atmp, *node=NULL;
   char *token=NULL, *lasttoken=NULL, *saveptr;
 
@@ -268,14 +327,8 @@ arithmetic_init(struct tableparams *p, struct 
arithmetic_token **arith,
               /* If it wasn't found to be a pre-defined name, then its a
                  column operand (column number or name). */
               if(node->name_use==NULL)
-                {
-                  str = ( (token[0]=='$' && isdigit(token[1]))
-                          ? &token[1]   /* Column number (starting with '$'). 
*/
-                          : token );    /* Column name, just add it.          
*/
-                  gal_list_str_add(toread, str, 1);
-                  node->index=*totcalled;
-                  *totcalled+=1;
-                }
+                arithmetic_init_addcol(token, node, colstoread,
+                                       totcalled, colinfo, numcols);
             }
         }
 
@@ -285,8 +338,8 @@ arithmetic_init(struct tableparams *p, struct 
arithmetic_token **arith,
 
   /* A small sanity check: the last added token must be an operator. */
   if( node==NULL || node->operator==GAL_ARITHMETIC_OP_INVALID )
-    error(EXIT_FAILURE, 0, "last token in arithmetic column ('%s') is not a "
-          "recognized operator", lasttoken);
+    error(EXIT_FAILURE, 0, "last token in arithmetic column ('%s') "
+          "is not a recognized operator", lasttoken);
 }
 
 
@@ -296,7 +349,7 @@ arithmetic_init(struct tableparams *p, struct 
arithmetic_token **arith,
 /* Set the final index of each package of columns (possibly containing
    processing columns that will change in number and contents).  */
 void
-arithmetic_indexs_final(struct tableparams *p, size_t *colmatch)
+arithmetic_indexs_final(struct tableparams *p)
 {
   size_t startind;
   size_t i, numcols;
@@ -317,27 +370,31 @@ arithmetic_indexs_final(struct tableparams *p, size_t 
*colmatch)
             if(atmp->index!=GAL_BLANK_SIZE_T)
               {
                 /* Small sanity check. */
-                if(colmatch[atmp->index]!=1)
-                  error(EXIT_FAILURE, 0, "arithmetic operands can (currently) "
-                        "only correspond to a single column");
+                if(p->colmatch[atmp->index]!=1)
+                  error(EXIT_FAILURE, 0, "arithmetic operands can "
+                        "(currently) only correspond to a single "
+                        "column, but more than one match was found "
+                        "for a column you used in column arithmetic");
 
                 /* Update the index in the full list of read columns. */
-                numcols=0; for(i=0;i<atmp->index;++i) numcols+=colmatch[i];
+                numcols=0;
+                for(i=0;i<atmp->index;++i) numcols+=p->colmatch[i];
                 atmp->index=numcols;
               }
         }
+
       /* A simple column. */
       else
         {
           /* See where the starting column for this patch of simple columns
              is. */
           startind=0;
-          for(i=0;i<tmp->start;++i) startind+=colmatch[i];
+          for(i=0;i<tmp->start;++i) startind+=p->colmatch[i];
 
           /* How many of the read columns are associated with the this
              patch of columns. */
           numcols=0;
-          for(i=0;i<tmp->numsimple;++i) numcols+=colmatch[tmp->start+i];
+          for(i=0;i<tmp->numsimple;++i) numcols+=p->colmatch[tmp->start+i];
 
           /* Update the values. */
           tmp->start=startind;
@@ -872,9 +929,56 @@ arithmetic_operator_run(struct tableparams *p,
 
 
 
+/* When the column identifier (name or number) wasn't in the main input
+   table (for example, it was added with '--catcolumnfile'), we need this
+   function to find the column to work with. */
+gal_data_t *
+arithmetic_read_at_usage(struct tableparams *p,
+                         struct arithmetic_token *token)
+{
+  size_t i;
+
+  /* If the number is blank, then we have a name and should return the
+     first column in the table that has the given name. */
+  if(token->num_at_usage==GAL_BLANK_SIZE_T)
+    {
+      /* Search all the existing columns in the table. */
+      for(i=0; i<p->numcolarray; ++i)
+        if( strcasecmp(p->colarray[i]->name, token->id_at_usage)==0 )
+          return p->colarray[i];
+
+      /* If control reaches here, then the requested name didn't exist in
+         the table. */
+      error(EXIT_FAILURE, 0, "'%s' doesn't correspond to the name of "
+            "any column in the table until this column arithmetic",
+            token->id_at_usage);
+    }
+
+  /* We already have the desired column number. */
+  else
+    if(token->num_at_usage > p->numcolarray)
+      error(EXIT_FAILURE, 0, "%zu is an invalid column number: the "
+            "table only has %zu columns before this column arithmetic "
+            "step", token->num_at_usage, p->numcolarray);
+    else
+      return p->colarray[token->num_at_usage-1];
+
+  /* If control reaches here, there is a bug! In then end, simply return
+     NULL to avoid compiler warnings. */
+  error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to find the "
+        "cause and fix it. This function should not reach this point",
+        __func__, PACKAGE_BUGREPORT);
+  return NULL;
+}
+
+
+
+
+
 /* Apply reverse polish mechanism for this column. */
 static void
-arithmetic_reverse_polish(struct tableparams *p, struct column_pack *outpack)
+arithmetic_reverse_polish(struct tableparams *p,
+                          struct column_pack *outpack)
 {
   struct arithmetic_token *token;
   gal_data_t *single, *stack=NULL;
@@ -906,6 +1010,15 @@ arithmetic_reverse_polish(struct tableparams *p, struct 
column_pack *outpack)
           token->constant=NULL;
         }
 
+      /* The column wasn't in the main input. */
+      else if(token->id_at_usage)
+        {
+          gal_list_data_add(&stack, arithmetic_read_at_usage(p, token));
+          token->num_at_usage=GAL_BLANK_SIZE_T;
+          free(token->id_at_usage);
+          token->id_at_usage=NULL;
+        }
+
       /* A column from the table. */
       else if(token->index!=GAL_BLANK_SIZE_T)
         gal_list_data_add(&stack, p->colarray[token->index]);
@@ -975,6 +1088,9 @@ arithmetic_operate(struct tableparams *p)
   size_t i;
   struct column_pack *outpack;
 
+  /* Set the final indexs and define 'colarray'. */
+  arithmetic_indexs_final(p);
+
   /* From now on, we will be looking for columns from the index in
      'colarray', so to keep things clean, we'll set all the 'next' elements
      to NULL. */
diff --git a/bin/table/arithmetic.h b/bin/table/arithmetic.h
index c1306c5b..091241b5 100644
--- a/bin/table/arithmetic.h
+++ b/bin/table/arithmetic.h
@@ -53,14 +53,12 @@ enum arithmetic_operators
 /* Functions */
 void
 arithmetic_init(struct tableparams *p, struct arithmetic_token **arith,
-                gal_list_str_t **toread, size_t *totcalled, char *expression);
+                gal_list_str_t **colstoread, size_t *totcalled,
+                char *expression, gal_data_t *colinfo, size_t numcols);
 
 void
 arithmetic_token_free(struct arithmetic_token *list);
 
-void
-arithmetic_indexs_final(struct tableparams *p, size_t *colmatch);
-
 void
 arithmetic_operate(struct tableparams *p);
 
diff --git a/bin/table/main.h b/bin/table/main.h
index c10ff4bb..cf91975d 100644
--- a/bin/table/main.h
+++ b/bin/table/main.h
@@ -66,16 +66,19 @@ struct arithmetic_token
   int            operator;  /* OPERATOR: Code of operator.                */
   size_t     num_operands;  /* OPERATOR: Number of required operands.     */
   size_t            index;  /* OPERAND: Index in requested columns.       */
+  char       *id_at_usage;  /* OPERAND: col identifier at usage time.     */
+  size_t     num_at_usage;  /* OPERAND: col number at usage.              */
   gal_data_t    *constant;  /* OPERAND: a constant/single number.         */
   char          *name_def;  /* Name given to the 'set-' operator.         */
   char          *name_use;  /* If this a usage of a name.                 */
   struct arithmetic_token *next;  /* Pointer to next token.               */
 };
 
+/*  */
 struct column_pack
 {
   size_t                    start; /* Starting ind. in requested columns. */
-  size_t                numsimple; /* Number of simple columns.           */
+  size_t                numsimple; /* Num. of simple columns (no change). */
   struct arithmetic_token  *arith; /* Arithmetic tokens to use.           */
   struct column_pack        *next; /* Next output column.                 */
 };
@@ -138,6 +141,7 @@ struct tableparams
   gsl_rng                *rng;  /* Main random number generator.        */
   const char        *rng_name;  /* Name of random number generator.     */
   unsigned long int  rng_seed;  /* Random number generator seed.        */
+  size_t            *colmatch;  /* Number of matches found for columns. */
 
   /* For arithmetic operators. */
   gal_list_str_t  *wcstoimg_p;  /* Pointer to the node.                 */
diff --git a/bin/table/table.c b/bin/table/table.c
index 6802eb51..77593db4 100644
--- a/bin/table/table.c
+++ b/bin/table/table.c
@@ -772,8 +772,8 @@ table_catcolumn(struct tableparams *p)
 {
   size_t counter=1;
   gal_list_str_t *filell, *hdull;
-  gal_data_t *tocat, *final, *newcol;
   char *tmpname, *hdu=NULL, cstr[100];
+  gal_data_t *col, *tocat, *final, *newcol;
   struct gal_options_common_params *cp=&p->cp;
 
   /* Go over all the given files. */
@@ -816,13 +816,20 @@ table_catcolumn(struct tableparams *p)
         for(newcol=tocat; newcol!=NULL; newcol=newcol->next)
           if(newcol->name)
             {
-              /* Add the counter suffix to the column name. */
-              sprintf(cstr, "-%zu", counter);
-              tmpname=gal_checkset_malloc_cat(newcol->name, cstr);
-
-              /* Free the old name and put in the new one. */
-              free(newcol->name);
-              newcol->name=tmpname;
+              /* If the new column's name is identical (case-insensitive)
+                 to an existing name in the existing table so far, we need
+                 to add a suffix. */
+              for(col=p->table; col!=NULL; col=col->next)
+                if( col->name && strcasecmp(col->name, newcol->name)==0 )
+                  {
+                    /* Add the counter suffix to the column name. */
+                    sprintf(cstr, "-%zu", counter);
+                    tmpname=gal_checkset_malloc_cat(newcol->name, cstr);
+
+                    /* Free the old name and put in the new one. */
+                    free(newcol->name);
+                    newcol->name=tmpname;
+                  }
             }
 
       /* Find the final column of the main table and add this table.*/
diff --git a/bin/table/ui.c b/bin/table/ui.c
index 9857c7fa..415fb430 100644
--- a/bin/table/ui.c
+++ b/bin/table/ui.c
@@ -581,6 +581,7 @@ ui_print_info_exit(struct tableparams *p)
   if(p->filename==NULL) p->filename="Standard-input";
   gal_list_str_free(lines, 1);
 
+
   /* If there was no actual data in the file, then inform the user */
   if(allcols==NULL)
     error(EXIT_FAILURE, 0, "%s: no usable data rows", p->filename);
@@ -617,13 +618,15 @@ ui_print_info_exit(struct tableparams *p)
    has comma-separated values. If they do then the list will be updated to
    be fully separate. */
 static void
-ui_columns_prepare(struct tableparams *p)
+ui_columns_prepare(struct tableparams *p, gal_list_str_t *lines)
 {
+  int tableformat;
   gal_data_t *strs;
   char *c, **strarr;
-  size_t i, totcalled=0;
+  gal_data_t *colinfo=NULL;
   struct column_pack *node, *last;
-  gal_list_str_t *tmp, *toread=NULL;
+  gal_list_str_t *tmp, *colstoread=NULL;
+  size_t i, totcalled=0, numcols, numrows;
 
   /* Go over the whole original list (where each node may have more than
      one value separated by a comma. */
@@ -645,37 +648,49 @@ ui_columns_prepare(struct tableparams *p)
       /* Go over all the given colum names/numbers. */
       for(i=0;i<strs->size;++i)
         {
-          /* See if this is an arithmetic column to be processed, or the
-             contents should just be printed. */
+          /* See if this is an arithmetic column to be processed, or its
+             just a "simple" column (where  */
           if(!strncmp(strarr[i], ARITHMETIC_CALL, ARITHMETIC_CALL_LENGTH))
             {
+              /* Arithmetic operations may be done on columns from other
+                 files (for example with '--catcolumnfile'). We therefore
+                 need to check if the requested column is in the main input
+                 file or not. If not, it should be set when column
+                 arithmetic starts. To do this, we need to get the input's
+                 column information. */
+              if(colinfo==NULL)
+                colinfo=gal_table_info(p->filename, p->cp.hdu, lines,
+                                       &numcols, &numrows, &tableformat);
+
               /* If this is the first arithmetic operation and the user has
                  already asked for some columns, we'll need to put all
                  previously requested simply-printed columns into an
                  'outcols' structure, then add this arithmetic operation's
                  'outcols'. */
-              if(p->outcols==NULL && toread)
+              if(p->outcols==NULL && colstoread)
                 {
                   /* Allocate an empty structure and set the necessary
                      pointers. */
                   node=ui_outcols_add_new_to_end(&p->outcols);
                   node->start=0;
-                  node->numsimple=gal_list_str_number(toread);
+                  node->numsimple=gal_list_str_number(colstoread);
                   totcalled=node->numsimple;
                 }
 
               /* Add a new column pack, then read all the tokens (while
                  specifying which columns it needs). */
               node=ui_outcols_add_new_to_end(&p->outcols);
-              arithmetic_init(p, &node->arith, &toread, &totcalled,
-                              strarr[i]+ARITHMETIC_CALL_LENGTH);
+              arithmetic_init(p, &node->arith, &colstoread, &totcalled,
+                              strarr[i]+ARITHMETIC_CALL_LENGTH, colinfo,
+                              numcols);
               free(strarr[i]);
             }
+
           /* This is a simple column (no change in values). */
           else
             {
               /* Add this column to the list of columns to read. */
-              gal_list_str_add(&toread, strarr[i], 0);
+              gal_list_str_add(&colstoread, strarr[i], 0);
 
               /* See if we have packaged the output columns. */
               if(p->outcols)
@@ -741,11 +756,15 @@ ui_columns_prepare(struct tableparams *p)
     }
   */
 
-  /* Delete the old list, then reverse the 'toread' list, and put it into
-     'p->columns'. */
+  /* Free the information from all the columns (that may have been gathered
+     if it was necessary). */
+  if(colinfo) gal_data_array_free(colinfo, numcols, 0);
+
+  /* Delete the old list, then reverse the 'colstoread' list, and put it
+     into 'p->columns'. */
   gal_list_str_free(p->columns, 1);
-  gal_list_str_reverse(&toread);
-  p->columns=toread;
+  gal_list_str_reverse(&colstoread);
+  p->columns=colstoread;
 }
 
 
@@ -1167,7 +1186,6 @@ ui_check_select_sort_after(struct tableparams *p, size_t 
nselect,
 static void
 ui_preparations(struct tableparams *p)
 {
-  size_t *colmatch;
   gal_list_str_t *lines;
   size_t nselect=0, origoutncols=0;
   size_t sortindout=GAL_BLANK_SIZE_T;
@@ -1180,14 +1198,14 @@ ui_preparations(struct tableparams *p)
     ui_print_info_exit(p);
 
 
-  /* Prepare the column names. */
-  ui_columns_prepare(p);
-
-
   /* If the input is from stdin, save it as 'lines'. */
   lines=gal_options_check_stdin(p->filename, p->cp.stdintimeout, "input");
 
 
+  /* Prepare the column names. */
+  ui_columns_prepare(p, lines);
+
+
   /* If any kind of row-selection is requested set 'p->selection' to 1. */
   p->selection = ( p->range || p->inpolygon || p->outpolygon || p->equal
                    || p->notequal || p->noblankll );
@@ -1202,17 +1220,17 @@ ui_preparations(struct tableparams *p)
 
   /* If we have any arithmetic operations, we need to make sure how many
      columns match every given column name. */
-  colmatch = ( p->outcols
-               ? gal_pointer_allocate(GAL_TYPE_SIZE_T,
-                                      gal_list_str_number(p->columns), 1,
-                                      __func__, "colmatch")
-               : NULL);
+  p->colmatch = ( p->outcols
+                  ? gal_pointer_allocate(GAL_TYPE_SIZE_T,
+                                         gal_list_str_number(p->columns),
+                                         1, __func__, "p->colmatch")
+                  : NULL);
 
 
   /* Read the necessary columns. */
   p->table=gal_table_read(p->filename, cp->hdu, lines, p->columns,
                           cp->searchin, cp->ignorecase, cp->numthreads,
-                          cp->minmapsize, p->cp.quietmmap, colmatch);
+                          cp->minmapsize, p->cp.quietmmap, p->colmatch);
   if(p->filename==NULL) p->filename="stdin";
   gal_list_str_free(lines, 1);
 
@@ -1231,21 +1249,17 @@ ui_preparations(struct tableparams *p)
           "non-blank lines)", p->filename);
 
 
-  /* Set the final indexs. */
-  if(p->outcols)
-    arithmetic_indexs_final(p, colmatch);
-
-
   /* Make sure the (possible) output name is writable. */
   gal_checkset_writable_remove(p->cp.output, 0, p->cp.dontdelete);
 
+
   /* If random rows are desired, we need to define a GSL random number
      generator structure. */
   if(p->rowrandom)
     p->rng=gal_checkset_gsl_rng(p->envseed, &p->rng_name, &p->rng_seed);
 
+
   /* Clean up. */
-  free(colmatch);
   if(selectindout) free(selectindout);
   if(selecttypeout) free(selecttypeout);
 }
@@ -1371,6 +1385,7 @@ ui_free_report(struct tableparams *p)
   if(p->wcshdu) free(p->wcshdu);
   gal_list_data_free(p->noblank);
   gal_list_str_free(p->columns, 1);
+  if(p->colmatch) free(p->colmatch);
   if(p->colarray) free(p->colarray);
   gal_list_data_free(p->colmetadata);
   gal_list_str_free(p->catcolumnhdu, 1);
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index f901bfbb..5ab12c00 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -3943,7 +3943,8 @@ $ asttable cat/xdf-f160w.fits -hCLUMPS 
--output=three-in-one.fits \
 $ asttable three-in-one.fits -i
 @end example
 
-As you see, to avoid confusion in column names, Table has intentionally 
appended a @code{-1} to the column names of the first concatenated table (so 
for example we have the original @code{RA} column, and another one called 
@code{RA-1}).
+As you see, to avoid confusion in column names, Table has intentionally 
appended a @code{-1} to the column names of the first concatenated table if the 
column names are already present in the original table.
+For example we have the original @code{RA} column, and another one called 
@code{RA-1}).
 Similarly a @code{-2} has been added for the columns of the second 
concatenated table.
 
 However, this example clearly shows a problem with this full concatenation: 
some columns are identical (for example @code{HOST_OBJ_ID} and 
@code{HOST_OBJ_ID-1}), or not needed (for example @code{RA-1} and @code{DEC-1} 
which are not necessary here).
@@ -12818,13 +12819,22 @@ By default the output column of the arithmetic 
operation will be given a generic
 But meta data are critically important and it is good practice to always have 
short, but descriptive, names for each columns, units and also some comments 
for more explanation.
 To add metadata to a column, you can use the @option{--colmetadata} option 
that is described in @ref{Invoking asttable} and @ref{Operation precedence in 
Table}.
 
-Finally, since the arithmetic expressions are a value to @option{--column}, it 
doesn't necessarily have to be a separate option, so the commands above are 
also identical to the command below (note that this only has one @option{-c} 
option).
+Since the arithmetic expressions are a value to @option{--column}, it doesn't 
necessarily have to be a separate option, so the commands above are also 
identical to the command below (note that this only has one @option{-c} option).
 Just be very careful with the quoting!
+With the @option{--colmetadata} option, we are also giving a name, units and a 
comment to the third column.
 
 @example
-$ asttable table.fits -cAWAV,SPECTRUM,'arith AWAV 1e10 x'
+$ asttable table.fits -cAWAV,SPECTRUM,'arith AWAV 1e10 x' \
+           --colmetadata=3,AWAV_A,angstrom,"Wavelength (in Angstroms)"
 @end example
 
+In case you need to append columns from other tables (with 
@option{--catcolumnfile}), you can use those extra columns in column arithmetic 
also.
+The easiest, and most robust, way is that your columns of interest (in all 
files whose columns are to be merged) have different names.
+In this scenario, you can simply use the names of the columns you plan to 
append.
+If there are similar names, note that by default Table appends a @code{-N} to 
similar names (where @code{N} is the file counter given to 
@option{--catcolumnfile}, see the description of @option{--catcolumnfile} for 
more).
+Using column numbers can get complicated: if the number is smaller than the 
main input's number of columns, the main input's column will be used.
+Otherwise (when the requested column number is larger than the main input's 
number of columns), the final output (after appending all the columns from all 
the possible files) column number will be used.
+
 Almost all the arithmetic operators of @ref{Arithmetic operators} are also 
supported for column arithmetic in Table.
 In particular, the few that are not present in the Gnuastro 
library@footnote{For a list of the Gnuastro library arithmetic operators, 
please see the macros starting with @code{GAL_ARITHMETIC_OP} and ending with 
the operator name in @ref{Arithmetic on datasets}.} aren't yet supported for 
column arithmetic.
 Besides the operators in @ref{Arithmetic operators}, several operators are 
only available in Table to use on table columns.
@@ -13260,10 +13270,12 @@ Note that the columns given to @option{--catcolumns} 
must be present in all the
 If the file given to this option is a FITS file, its necessary to also define 
the corresponding HDU/extension with @option{--catcolumnhdu}.
 Also note that no operation (for example row selection, arithmetic or etc) is 
applied to the table given to this option.
 
-If the appended columns have a name, the column names of each file will be 
appended with a @code{-N}, where @code{N} is a counter starting from 1 for each 
appended file.
+If the appended columns have a name, and their name is already present in the 
table before adding those columns, the column names of each file will be 
appended with a @code{-N}, where @code{N} is a counter starting from 1 for each 
appended table.
+Just note that in the FITS standard (and thus in Gnuastro), column names are 
not case-sensitive.
+
 This is done because when concatenating columns from multiple tables (more 
than two) into one, they may have the same name, and its not good practice to 
have multiple columns with the same name.
 You can disable this feature with @option{--catcolumnrawname}.
-Generally, you can use the @option{--colmetadata} option to update column 
metadata.
+Generally, you can use the @option{--colmetadata} option to update column 
metadata in the same command, after all the columns have been concatenated.
 
 For example, let's assume you have two catalogs of the same objects (same 
number of rows) in different filters.
 Such that @file{f160w-cat.fits} has a @code{MAGNITUDE} column that has the 
magnitude of each object in the @code{F160W} filter and similarly 
@file{f105w-cat.fits}, also has a @code{MAGNITUDE} column, but for the 
@code{F105W} filter.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]