gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 1817ff60: MakeCatalog: per-slice measurements


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 1817ff60: MakeCatalog: per-slice measurements in vector columns
Date: Sat, 29 Apr 2023 14:05:12 -0400 (EDT)

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

    MakeCatalog: per-slice measurements in vector columns
    
    Until now, MakeCatalog would write per-slice measurements (like the
    spectrum of an object in an IFU cube) in different HDUs of the output
    file. This was extremely slow and very inconvenient.
    
    With this commit, MakeCatalog now writes such measurements as vector
    columns in its single output table and the old '--spectrum' column has been
    removed. It has been replaced by separate measurements with this format:
    '--*-in-slice'.
    
    The following changes have also been made as part of this commit:
    
     - Book: Added new tutorial to show-case this feature. Which is also a good
       demonstration of vector column management.
    
     - Library (spectrallines.h): added a much larger database of lines.
    
     - CosmicCalculator: new option to specify the line unit to input/output.
---
 NEWS                                   |   46 +-
 bin/arithmetic/arithmetic.c            |   49 +-
 bin/convertt/ui.c                      |    3 +-
 bin/cosmiccal/args.h                   |   19 +-
 bin/cosmiccal/astcosmiccal.conf        |    3 +
 bin/cosmiccal/cosmiccal.c              |   29 +-
 bin/cosmiccal/main.h                   |    3 +
 bin/cosmiccal/ui.c                     |  169 ++-
 bin/cosmiccal/ui.h                     |    3 +-
 bin/fits/ui.c                          |    2 +-
 bin/match/ui.c                         |   13 +-
 bin/mkcatalog/args.h                   |  150 ++-
 bin/mkcatalog/columns.c                |  509 +++++++--
 bin/mkcatalog/main.h                   |   38 +-
 bin/mkcatalog/mkcatalog.c              |  241 ++---
 bin/mkcatalog/mkcatalog.h              |    7 +-
 bin/mkcatalog/parse.c                  |  611 +++++------
 bin/mkcatalog/ui.c                     |  303 ++----
 bin/mkcatalog/ui.h                     |   12 +
 bin/noisechisel/astnoisechisel-3d.conf |    4 +-
 bin/script/fits-view.in                |   16 +-
 bin/segment/astsegment-3d.conf         |    4 +-
 bin/statistics/ui.c                    |    2 +-
 bin/table/args.h                       |   45 +-
 bin/table/arithmetic.c                 |   12 +-
 bin/table/main.h                       |    6 +-
 bin/table/table.c                      |  119 +-
 bin/table/ui.c                         |  209 ++--
 bin/table/ui.h                         |    8 +-
 configure.ac                           |    3 +-
 doc/gnuastro.texi                      | 1853 ++++++++++++++++++++++++--------
 lib/fits.c                             |   25 +-
 lib/gnuastro-internal/options.h        |   13 +-
 lib/gnuastro/list.h                    |    2 +-
 lib/gnuastro/permutation.h             |    3 +-
 lib/gnuastro/speclines.h               |  886 ++++++++++++---
 lib/list.c                             |    9 +-
 lib/makeplugin.c                       |    6 +-
 lib/options.c                          |  167 ++-
 lib/permutation.c                      |  117 ++
 lib/speclines.c                        | 1133 ++++++++++++++++---
 lib/txt.c                              |   12 +-
 tests/during-dev.sh                    |    5 +-
 43 files changed, 5056 insertions(+), 1813 deletions(-)

diff --git a/NEWS b/NEWS
index bb8c8f75..8322825b 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,11 @@ See the end of the file for license conditions.
      Raul Infante-Sainz, Samane Raji, Zahra Sharbaf, Zohreh Ghaffari.
 
    Book:
+   - New tutorial on detection and spectrum extraction from 3D data has
+     been added in the "Tutorials" chapter. It uses a MUSE cube and
+     demonstrates how to subtract the continuum, run NoiseChisel, Segment
+     and MakeCatalog for obtaining spectra and creating pseudo narrow-band
+     images of emission-lines.
    - New "Shell tips" sub-section added (under the "Command-line" section
      of the "Common program behavior" chapter). This sub-section contains
      useful shell tips and tricks that can be useful when using Gnuastro's
@@ -72,6 +77,15 @@ See the end of the file for license conditions.
      - f32: same as 'float32' (to convert to 32-bit floating point).
      - f64: same as 'float64' (to convert to 64-bit floating point).
 
+   CosmicCalculator:
+   - Spectral line database has been increased to 235 spectral lines in the
+     UV and optical (previously only had 41 lines!) from:
+     http://astronomy.nmsu.edu/drewski/tableofemissionlines.html
+     To see the full list, run 'astcosmiccal --listlines'.
+   --lineunit: allows you to specify the units of the displayed spectral
+     line wavelengths. Currently, it take four units: 'm', 'micron', 'nm'
+     and 'angstrom'. We can add any other unit easily, just let us know.
+
    Crop:
    --append: if the output file already exists, append the cropped image
      HDU to the already existing HDUs of the file. Without this option, any
@@ -98,6 +112,20 @@ See the end of the file for license conditions.
      arcsec^2) of the sigma-clipped standard deviation of the values. This
      can be used to find the reliable surface brightness of a radial
      profile for example.
+   --sum-in-slice: [3D in; vector out] Sum of values in each slice.
+   --sum-err-in-slice: [3D in; vector out] Error in '--suminslice'.
+   --area-in-slice: [3D input; vector out] Number of labeled in each slice.
+   --sum-proj-in-slice: [3D input; vector out] Sum of projected area
+     in each slice.
+   --area-proj-in-slice: [3D in; vector out] Number of voxels that are used
+     in '--sum-proj-in-slice'.
+   --sum-proj-err-in-slice: [3D in; vector out] Error of '--sum-proj-in-slice'.
+   --area-other-in-slice: [3D in; vector out] Area of other label in
+     projected area on each slice.
+   --sum-other-in-slice: [3D in; vector out] Sum of other label in
+     projected area on each slice.
+   --sum-other-err-in-slice: [3D in; vector out] Area in
+     '--sum-other-in-slice'.
 
    NoiseChisel:
    --outliernumngb: the number of neighboring tiles to reject those that
@@ -118,7 +146,7 @@ See the end of the file for license conditions.
    Table:
    - Vector columns with multiple values per column are now supported. The
      following features have been added to help working on vector columns:
-     --Book: a new "Vector columns" section has been added under the Table
+     - Book: a new "Vector columns" section has been added under the Table
        program which descibes the core concepts and usage examples of the
        options below.
      --information: also identifies vector columns (a column with more than
@@ -130,6 +158,10 @@ See the end of the file for license conditions.
        separate single-valued columns.
      --keepvectfin: do not delete the input columns to '--tovector' and
        '--fromvector'.
+   --rowfirst: do row-based operations before column-based operations (by
+     default column-based operations are done first).
+   --transpose: column-based operator to transpose vector columns into a
+     new table that has the inverse number of rows and columns.
    --txteasy: (or '-Y') when output is a plain-text file or just gets
      printed on standard output (terminal), all floating point columns are
      printed in fixed point notation (as in '123.456') instead of the
@@ -139,7 +171,6 @@ See the end of the file for license conditions.
      readability, but be careful with some scenarios (for example
      '1.23e-120', which will show only as '0.0'!). For more, see the
      changes in Table in this version.
-
    - New column arithmetic operator:
      - sorted-to-interval: return two columns from a single (sorted) input,
        containing the minimum and maximum values of an interval. The
@@ -222,6 +253,12 @@ See the end of the file for license conditions.
     installing pre-built binaries it through services like PyPI, so they
     won't be needing it either.
 
+  CosmicCalculator:
+  - Given the major increase of the spectral line database, the old line
+    names have been changed to accommodate the full database. For example
+    'H-alpha' has replaced 'halpha'. Please run 'astcosmiccal --listlines'
+    to see the new names for the previous lines.
+
   MakeCatalog:
   - "Sum" used instead of "brightness"
     --sum: new name for the old '--brightness' column. "Brightness" has a
@@ -334,6 +371,9 @@ See the end of the file for license conditions.
     changed '--sum' in MakeCatalog (above) for more.
 
   Table:
+  - Given the newly added vector columns, the precedence on operations has
+    been updated. Please read the "Operation precedence in Table" section
+    of the book.
   - To avoid potential loss of information in floating point columns, when
     printing the columns to standard output (in the terminal) or saving in
     a plain-text file, the default floating point formats are now printed
@@ -356,6 +396,8 @@ See the end of the file for license conditions.
   Library:
   - gal_blank_remove_rows: new 'onlydim0' argument to ignore vector columns
     when checking for blanks.
+  - gal_list_str_cat: new 'delimiter' argument to specify the character for
+    printing between the separate string nodes in the single output string.
   - gal_txt_write: new 'tab0_img1' argument. Until now, this function would
     distinguish between images and tables using the dimensions of the
     input. But with the addition of vector columns in tables (that have 2
diff --git a/bin/arithmetic/arithmetic.c b/bin/arithmetic/arithmetic.c
index 2e88412b..8aaf6263 100644
--- a/bin/arithmetic/arithmetic.c
+++ b/bin/arithmetic/arithmetic.c
@@ -384,18 +384,16 @@ wrapper_for_filter(struct arithmeticparams *p, char 
*token, int operator)
      pop the necessary number of operands. */
   nparams = ndim + (issigclip ? 2 : 0 );
   for(i=0;i<nparams;++i)
-    gal_list_data_add(&params_list, operands_pop(p, token));
-
-
-  /* Make sure the parameters only have single values. */
-  i=0;
-  for(tmp=params_list; tmp!=NULL; tmp=tmp->next)
     {
-      ++i;
-      if(tmp->size!=1)
+      /* Add this to the list of parameters. */
+      gal_list_data_add(&params_list, operands_pop(p, token));
+
+      /* Make sure it only has a single element. */
+      if(params_list->size!=1)
         error(EXIT_FAILURE, 0, "the parameters given to the filtering "
-              "operators can only be numbers. Value number %zu has %zu "
-              "elements, so its an array", i, tmp->size);
+              "operators can only be numbers. Operand number %zu after "
+              "the main input has %zu elements, so its an array", i,
+              params_list->size);
     }
 
 
@@ -416,10 +414,23 @@ wrapper_for_filter(struct arithmeticparams *p, char 
*token, int operator)
       gal_data_free(tmp);
     }
 
-
-  /* If the input only has one element, filtering makes no sense, so don't
-     waste time, just add the input onto the stack. */
-  if(afp.input->size==1) afp.out=afp.input;
+  /* If the input only has one element, it is most probably and error (the
+     user has confused the parameters with the input dataset). So report a
+     warning filtering makes no sense, so don't waste time, just add the
+     input onto the stack. */
+  if(afp.input->size==1)
+    {
+      /* Inform the user that this is suspicious. */
+      if(p->cp.quiet==0)
+        error(EXIT_SUCCESS, 0, "WARNING: the first popped operand to the "
+              "filtering operators has a single element! This is most "
+              "probably a typo in the order of operands! Recall that the "
+              "filtering operators need the main input image/cube as the "
+              "first popped operand");
+
+      /* Set the input as the output. */
+      afp.out=afp.input;
+    }
   else
     {
       /* Allocate an array for the size of the filter and fill it in. The
@@ -451,8 +462,8 @@ wrapper_for_filter(struct arithmeticparams *p, char *token, 
int operator)
           /* If the width is larger than the input's size, change the width
              to the input's size. */
           if( fsize[i] > afp.input->dsize[i] )
-            error(EXIT_FAILURE, 0, "%s: the filter size along dimension %zu "
-                  "(%zu) is greater than the input's length in that "
+            error(EXIT_FAILURE, 0, "%s: the filter size along dimension "
+                  "%zu (%zu) is greater than the input's length in that "
                   "dimension (%zu)", __func__, i, fsize[i],
                   afp.input->dsize[i]);
 
@@ -494,8 +505,8 @@ wrapper_for_filter(struct arithmeticparams *p, char *token, 
int operator)
           break;
 
         default:
-          error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s to fix "
-                "the problem. The 'operator' code %d is not recognized",
+          error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s to "
+                "fix the problem. The 'operator' code %d is not recognized",
                 PACKAGE_BUGREPORT, __func__, operator);
         }
 
@@ -520,8 +531,8 @@ wrapper_for_filter(struct arithmeticparams *p, char *token, 
int operator)
 
   /* Clean up and add the output on top of the stack. */
   gal_data_free(zero);
-  gal_data_free(afp.input);
   gal_list_data_free(params_list);
+  if(afp.input!=afp.out) gal_data_free(afp.input); /* Single-element. */
 }
 
 
diff --git a/bin/convertt/ui.c b/bin/convertt/ui.c
index 45871ad5..478ac465 100644
--- a/bin/convertt/ui.c
+++ b/bin/convertt/ui.c
@@ -1231,7 +1231,8 @@ ui_set_output(struct converttparams *p)
     }
 
   /* Check if the output already exists and remove it if allowed. */
-  gal_checkset_writable_remove(cp->output, p->inputnames->v, 0,
+  gal_checkset_writable_remove(cp->output,
+                               p->inputnames ? p->inputnames->v : NULL, 0,
                                cp->dontdelete);
 }
 
diff --git a/bin/cosmiccal/args.h b/bin/cosmiccal/args.h
index 4bb404c0..c7818814 100644
--- a/bin/cosmiccal/args.h
+++ b/bin/cosmiccal/args.h
@@ -346,7 +346,7 @@ struct argp_option program_options[] =
       UI_KEY_LISTLINES,
       0,
       0,
-      "List known lines and rest frame wavelength.",
+      "List pre-defined lines at rest frame.",
       UI_GROUP_SPECTRAL_LINES,
       &p->listlines,
       GAL_OPTIONS_NO_ARG_TYPE,
@@ -359,7 +359,7 @@ struct argp_option program_options[] =
       UI_KEY_LISTLINESATZ,
       0,
       0,
-      "List known spectral lines at given redshift.",
+      "List pre-defined lines at the given redshift.",
       UI_GROUP_SPECTRAL_LINES,
       &p->listlinesatz,
       GAL_OPTIONS_NO_ARG_TYPE,
@@ -367,6 +367,19 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
+    {
+      "lineunit",
+      UI_KEY_LINEUNIT,
+      "STR",
+      0,
+      "Unit ('angstrom', 'nm', 'microm' or 'm').",
+      UI_GROUP_SPECTRAL_LINES,
+      &p->lineunit,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+    },
     {
       "lineatz",
       UI_KEY_LINEATZ,
@@ -382,8 +395,6 @@ struct argp_option program_options[] =
       ui_add_to_single_value,
     },
 
-
-
     {0}
   };
 
diff --git a/bin/cosmiccal/astcosmiccal.conf b/bin/cosmiccal/astcosmiccal.conf
index 06d9fa88..1df8a9af 100644
--- a/bin/cosmiccal/astcosmiccal.conf
+++ b/bin/cosmiccal/astcosmiccal.conf
@@ -41,3 +41,6 @@
  oradiation        0.0
 
 # Output:
+
+# Spectral lines:
+ lineunit     angstrom
diff --git a/bin/cosmiccal/cosmiccal.c b/bin/cosmiccal/cosmiccal.c
index b7a089a9..c8c8b8bb 100644
--- a/bin/cosmiccal/cosmiccal.c
+++ b/bin/cosmiccal/cosmiccal.c
@@ -203,19 +203,20 @@ cosmiccal(struct cosmiccalparams *p)
               break;
 
             case UI_KEY_ARCSECTANDIST:
-              printf("%f", ( gal_cosmology_angular_distance(p->redshift, p->H0,
-                                                             p->olambda,
-                                                             p->omatter,
-                                                             p->oradiation)
-                              * 1000 * M_PI / 3600 / 180 ) );
+              printf("%f", ( gal_cosmology_angular_distance(p->redshift,
+                                                            p->H0,
+                                                            p->olambda,
+                                                            p->omatter,
+                                                            p->oradiation)
+                             * 1000 * M_PI / 3600 / 180 ) );
               break;
 
             case UI_KEY_LUMINOSITYDIST:
               printf("%f", gal_cosmology_luminosity_distance(p->redshift,
-                                                              p->H0,
-                                                              p->olambda,
-                                                              p->omatter,
-                                                              p->oradiation));
+                                                             p->H0,
+                                                             p->olambda,
+                                                             p->omatter,
+                                                             p->oradiation));
               break;
 
             case UI_KEY_DISTANCEMODULUS:
@@ -240,8 +241,8 @@ cosmiccal(struct cosmiccalparams *p)
             case UI_KEY_LOOKBACKTIME:
               curage=gal_cosmology_age(0.0f, p->H0, p->olambda, p->omatter,
                                        p->oradiation);
-              zage=gal_cosmology_age(p->redshift, p->H0, p->olambda, 
p->omatter,
-                                     p->oradiation);
+              zage=gal_cosmology_age(p->redshift, p->H0, p->olambda,
+                                     p->omatter, p->oradiation);
               printf("%f", curage-zage);
               break;
 
@@ -264,7 +265,8 @@ cosmiccal(struct cosmiccalparams *p)
               break;
 
             case UI_KEY_LINEATZ:
-              printf("%g", gal_list_f64_pop(&p->specific_arg)*(1+p->redshift));
+              printf("%g", ( gal_list_f64_pop(&p->specific_arg)
+                             * (1+p->redshift) * p->lineunitmultip) );
               break;
 
             default:
@@ -274,7 +276,8 @@ cosmiccal(struct cosmiccalparams *p)
                     PACKAGE_BUGREPORT, tmp->v);
             }
 
-          /* Only add a space-character if there are more results to print. */
+          /* Only add a space-character if there are more results to
+             print. */
           if(tmp->next) printf(" ");
         }
 
diff --git a/bin/cosmiccal/main.h b/bin/cosmiccal/main.h
index e36d4997..626de62e 100644
--- a/bin/cosmiccal/main.h
+++ b/bin/cosmiccal/main.h
@@ -59,6 +59,7 @@ struct cosmiccalparams
   double            oradiation; /* Current radiation density.           */
   uint8_t            listlines; /* List the known spectral lines.       */
   uint8_t         listlinesatz; /* List the known spectral lines.       */
+  char *              lineunit; /* Unit of numbers for lines.           */
 
   /* Outputs. */
   gal_list_i32_t     *specific; /* Codes for single row calculations.   */
@@ -66,6 +67,8 @@ struct cosmiccalparams
 
   /* Internal: */
   time_t               rawtime; /* Starting time of the program.        */
+  double        lineunitmultip; /* Multiple for using line units.       */
+  uint8_t           haslineatz; /* A flag for sanity checks.            */
 };
 
 #endif
diff --git a/bin/cosmiccal/ui.c b/bin/cosmiccal/ui.c
index b665e085..40be5d6f 100644
--- a/bin/cosmiccal/ui.c
+++ b/bin/cosmiccal/ui.c
@@ -32,6 +32,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 #include <gnuastro/fits.h>
 #include <gnuastro/table.h>
+#include <gnuastro/pointer.h>
 #include <gnuastro/speclines.h>
 #include <gnuastro/cosmology.h>
 
@@ -206,6 +207,7 @@ ui_add_to_single_value(struct argp_option *option, char 
*arg,
 {
   int linecode;
   double *dptr, val=NAN;
+  gal_list_str_t *ltmp, *lines;
   struct cosmiccalparams *p = (struct cosmiccalparams *)params;
 
   /* In case of printing the option values. */
@@ -224,22 +226,36 @@ ui_add_to_single_value(struct argp_option *option, char 
*arg,
     {
     /* Options with arguments. */
     case UI_KEY_LINEATZ:
+
       /* Make sure an argument is given. */
       if(arg==NULL)
         error(EXIT_FAILURE, 0, "option '--lineatz' needs an argument");
 
-      /* If the argument is a number, read it, if not, see if its a known
-         specral line name. */
-      dptr=&val;
-      if( gal_type_from_string((void **)(&dptr), arg, GAL_TYPE_FLOAT64) )
+      /* The input can be a coma-separated string. */
+      lines=gal_options_parse_csv_strings_to_list(arg, filename, lineno);
+      gal_list_str_reverse(&lines); /* the function returns the raw list. */
+      for(ltmp=lines;ltmp!=NULL;ltmp=ltmp->next)
         {
-          linecode=gal_speclines_line_code(arg);
-          if(linecode==GAL_SPECLINES_INVALID)
-            error(EXIT_FAILURE, 0, "'%s' not a known spectral line name",
-                  arg);
-          val=gal_speclines_line_angstrom(linecode);
+          /* If the argument is a number, read it, if not, see if it is a
+             known specral line name. */
+          dptr=&val;
+          if( gal_type_from_string((void **)(&dptr), ltmp->v,
+                                   GAL_TYPE_FLOAT64) )
+            {
+              linecode=gal_speclines_line_code(ltmp->v);
+              if(linecode==GAL_SPECLINES_INVALID)
+                error(EXIT_FAILURE, 0, "'%s' not a known spectral line name",
+                      ltmp->v);
+              val=gal_speclines_line_angstrom(linecode);
+            }
+          gal_list_f64_add(&p->specific_arg, val);
+
+          /* Add this option to the print list and return. */
+          gal_list_i32_add(option->value, option->key);
         }
-      gal_list_f64_add(&p->specific_arg, val);
+
+      /* Activate the flag for sanity checks later. */
+      p->haslineatz=1;
       break;
 
     /* Options without arguments. */
@@ -257,10 +273,10 @@ ui_add_to_single_value(struct argp_option *option, char 
*arg,
           /* Only proceed if the (possibly given) argument is 1. */
           if(arg[0]=='0' && arg[1]=='\0') return NULL;
         }
-    }
 
-  /* Add this option to the print list and return. */
-  gal_list_i32_add(option->value, option->key);
+      /* Add this option to the print list and return. */
+      gal_list_i32_add(option->value, option->key);
+    }
   return NULL;
 }
 
@@ -392,10 +408,11 @@ ui_read_check_only_options(struct cosmiccalparams *p)
   /* Check if the density fractions add up to 1 (within floating point
      error). */
   if( sum > (1+1e-8) || sum < (1-1e-8) )
-    error(EXIT_FAILURE, 0, "sum of fractional densities is not 1, but %.8f. "
-          "The cosmological constant ('olambda'), matter ('omatter') "
-          "and radiation ('oradiation') densities are given as %.8f, %.8f, "
-          "%.8f", sum, p->olambda, p->omatter, p->oradiation);
+    error(EXIT_FAILURE, 0, "sum of fractional densities is not 1, but "
+          "%.8f. The cosmological constant ('olambda'), matter "
+          "('omatter') and radiation ('oradiation') densities are given "
+          "as %.8f, %.8f, %.8f", sum, p->olambda, p->omatter,
+          p->oradiation);
 
   /* Make sure that '--listlines' and '--listlinesatz' aren't called
      together. */
@@ -403,6 +420,15 @@ ui_read_check_only_options(struct cosmiccalparams *p)
     error(EXIT_FAILURE, 0, "'--listlines' and '--listlinesatz' can't be "
           "called together");
 
+  /* If any of the line options are requested, make sure that 'lineunit' is
+     also given. */
+  if( (p->listlines || p->listlinesatz || p->haslineatz || hasobsline)
+      && p->lineunit==0 )
+    error(EXIT_FAILURE, 0, "no '--lineunit' specified! For the "
+          "operations on lines, it is necessary to specify the unit "
+          "of the reported wavelength with this option. See the output "
+          "of '--help' for acceptable values");
+
   /* Make sure that '--redshift' and '--obsline' aren't called together. */
   if( (hasredshift + hasvelocity + hasobsline) > 1 )
     error(EXIT_FAILURE, 0, "only one of '--redshift', '--velocity', or "
@@ -434,30 +460,59 @@ ui_read_check_only_options(struct cosmiccalparams *p)
 static void
 ui_list_lines(struct cosmiccalparams *p)
 {
-  size_t i;
+  double ang;
+  size_t i, j;
+
+  /* Make sure '--lineunit' is given. */
+  if(p->lineunit==NULL)
+    error(EXIT_FAILURE, 0, "no unit specified for the wavelength of the "
+          "spectral lines. Please use '--lineunit' to specify your "
+          "desired unit");
 
   /* Print basic information. Note that '--listlinesatz' is requested, also
      print the redshift used. */
-  printf("# %s\n", PROGRAM_STRING);
-  if(p->listlinesatz)
-    printf("# Assumed redshift: %g\n", p->redshift);
-
-  /* Print column metadata. */
-  printf("# Column 1: Wavelength [Angstrom,f32] %s.\n",
-         ( p->listlinesatz
-           ? "Line wavelength at assumed redshift"
-           : "Rest frame wavelength of the line"));
-  printf("# Column 2: Name       [name,  str10] Line name in Gnuastro.\n");
+  if(p->cp.quiet==0)
+    {
+      printf("# %s\n", PROGRAM_STRING);
+      if(p->listlinesatz)
+        printf("# Assumed redshift: %g\n", p->redshift);
+      printf("# Source of rest frame wavelenghts (retrieved on 2023-01-15):\n"
+             "#     http://astronomy.nmsu.edu/drewski/tableofemission";
+             "lines.html\n");
+
+      /* Print column metadata. */
+      printf("# Column 1: Wavelength [%s,f32] %s.\n", p->lineunit,
+             ( p->listlinesatz
+               ? "Line wavelength at assumed redshift"
+               : "Rest frame wavelength of the line"));
+      printf("# Column 2: Name       [name,  str15] Line name in Gnuastro.\n");
+    }
 
   /* Print the line information. */
-  for(i=1;i<GAL_SPECLINES_INVALID_MAX;++i)
-    printf("%-15g%s\n",
-           ( p->listlinesatz
-             ? ( gal_speclines_line_angstrom(i) * (1+p->redshift) )
-             : gal_speclines_line_angstrom(i) ),
-           gal_speclines_line_name(i));
-
-  /* Abort the program. */
+  for(i=1;i<GAL_SPECLINES_NUMBER;++i)
+    {
+      /* Get the wavelength (in angstroms) for this line and print it. */
+      ang=gal_speclines_line_angstrom(i);
+      printf("%-20g%s\n",
+             ( p->listlinesatz
+               ? ( ang * (1+p->redshift) ) : ang ) * p->lineunitmultip,
+             gal_speclines_line_name(i));
+    }
+
+  /* Print the break locations. */
+  if(p->cp.quiet==0) printf("\n# Hydrogen series limits:\n");
+  for(i=0;i<GAL_SPECLINES_LIMIT_NUMBER;++i)
+    {
+      /* Get the wavelength (in angstroms) for this line and print it. */
+      j=i+GAL_SPECLINES_LIMIT_LYMAN;
+      ang=gal_speclines_line_angstrom(j);
+      printf("%-20g%s\n",
+             ( p->listlinesatz
+               ? ( ang * (1+p->redshift) ) : ang ) * p->lineunitmultip,
+             gal_speclines_line_name(j));
+    }
+
+  /* Abort the program successfully. */
   exit(EXIT_SUCCESS);
 }
 
@@ -465,6 +520,23 @@ ui_list_lines(struct cosmiccalparams *p)
 
 
 
+static void
+ui_preparations_lineunit(struct cosmiccalparams *p)
+{
+  if(      !strcmp(p->lineunit, "m")        ) p->lineunitmultip=1e-10;
+  else if( !strcmp(p->lineunit, "nano-m")   ) p->lineunitmultip=0.1;
+  else if( !strcmp(p->lineunit, "micro-m")  ) p->lineunitmultip=1e-4;
+  else if( !strcmp(p->lineunit, "angstrom") ) p->lineunitmultip=1;
+  else
+    error(EXIT_FAILURE, 0, "invalid value '%s' to '--lineunit'! Please "
+          "re-run this command with '--help' to see the acceptable "
+          "values", p->lineunit);
+}
+
+
+
+
+
 static void
 ui_preparations(struct cosmiccalparams *p)
 {
@@ -481,20 +553,23 @@ ui_preparations(struct cosmiccalparams *p)
           "'--redshift', '--velocity' (in km/s), or '--obsline' to specify "
           "a redshift, run with '--help' for more");
 
+  /* If a line unit is given find the factor that should be multiplied. */
+  if(p->lineunit || p->obsline) ui_preparations_lineunit(p);
+
   /* If '--listlines' is given, print them and abort the program
      successfully, don't continue with the preparations. Note that
      '--listlines' is the rest-frame lines. So we don't need any
      redshift. */
-  if(p->listlines)
-    ui_list_lines(p);
+  if(p->listlines) ui_list_lines(p);
 
   /* If '--obsline' has been given, set the redshift based on it (it can't
      be called with '--velocity'). */
   if(p->obsline)
     p->redshift = ( (p->obsline->status==GAL_SPECLINES_INVALID)
                     ? gal_speclines_line_redshift(obsline[0], obsline[1])
-                    : gal_speclines_line_redshift_code(obsline[0],
-                                                       p->obsline->status) );
+                    : gal_speclines_line_redshift_code( (obsline[0]
+                                                         / p->lineunitmultip),
+                                                        p->obsline->status) );
 
   /* If '--velocity' has been given, set the redshift based on it (it can't
      be called with '--obsline'). */
@@ -507,10 +582,20 @@ ui_preparations(struct cosmiccalparams *p)
      check.*/
   if(p->redshift==0.0f) p->redshift=MAIN_REDSHIFT_ZERO;
 
+  /* In case the redshift is negative, print an error. It will be detected
+     and abort the program, prior to this if given directly, but can also
+     happen with '--obsline' for example). */
+  if(p->redshift<0)
+    error(EXIT_FAILURE, 0, "the selected redshift (%.4f) is negative! "
+          "This can happen when you give unreasonable values to indirect "
+          "ways of specifying the redshift. For example calling "
+          "'--obsline=H-alpha,2000'. When calling '--obsline', please "
+          "make sure that your observed line is redder than the rest-frame "
+          "wavelength of the given line", p->redshift);
+
   /* Now that we have the redshift, we can print the 'listlinesatz'
      option. */
-  if(p->listlinesatz)
-    ui_list_lines(p);
+  if(p->listlinesatz) ui_list_lines(p);
 
   /* The list is filled out in a first-in-last-out order. By the time
      control reaches here, the list is finalized. So we should just reverse
diff --git a/bin/cosmiccal/ui.h b/bin/cosmiccal/ui.h
index db92e7da..ac64dabe 100644
--- a/bin/cosmiccal/ui.h
+++ b/bin/cosmiccal/ui.h
@@ -75,7 +75,8 @@ enum option_keys_enum
 
   /* Only with long version (start with a value 1000, the rest will be set
      automatically). */
-  UI_KEY_LISTLINES           = 1000,
+  UI_KEY_LINEUNIT            = 1000,
+  UI_KEY_LISTLINES,
   UI_KEY_LISTLINESATZ,
 };
 
diff --git a/bin/fits/ui.c b/bin/fits/ui.c
index 02c78070..463e0256 100644
--- a/bin/fits/ui.c
+++ b/bin/fits/ui.c
@@ -308,7 +308,7 @@ ui_check_copykeys(struct fitsparams *p)
         {
           if(p->copykeysrange[0]==GAL_BLANK_LONG)
             {
-              p->copykeysname=gal_options_parse_csv_strings_raw(pt,
+              p->copykeysname=gal_options_parse_csv_strings_to_data(pt,
                                                                 NULL, 0);
               break;
             }
diff --git a/bin/match/ui.c b/bin/match/ui.c
index 73753c89..7c51a489 100644
--- a/bin/match/ui.c
+++ b/bin/match/ui.c
@@ -628,14 +628,15 @@ ui_set_columns_sanity_check_read_aperture(struct 
matchparams *p)
   if(p->coord || p->kdtreemode==MATCH_KDTREE_BUILD)
     {
       if(p->ccol1==NULL)
-        error(EXIT_FAILURE, 0, "no value given to '--ccol1' (necessary with "
-              "'--coord')");
+        error(EXIT_FAILURE, 0, "no value given to '--ccol1' (necessary "
+              "with '--coord')");
     }
   else
     {
       if(p->ccol1==NULL || p->ccol2==NULL)
-        error(EXIT_FAILURE, 0, "both '--ccol1' and '--ccol2' must be given. "
-              "They specify the columns containing the coordinates to match");
+        error(EXIT_FAILURE, 0, "both '--ccol1' and '--ccol2' must be "
+              "given. They specify the columns containing the "
+              "coordinates to match");
     }
 
   /* Make sure the same number of columns is given to both. Note that a
@@ -661,8 +662,8 @@ ui_set_columns_sanity_check_read_aperture(struct 
matchparams *p)
       {
       case 1:
         if(p->aperture->size>1)
-          error(EXIT_FAILURE, 0, "%zu values given to '--aperture'. In a 1D "
-                "match, this option can only take one value",
+          error(EXIT_FAILURE, 0, "%zu values given to '--aperture'. In "
+                "a 1D match, this option can only take one value",
                 p->aperture->size);
         break;
 
diff --git a/bin/mkcatalog/args.h b/bin/mkcatalog/args.h
index 1db8293a..774b64c8 100644
--- a/bin/mkcatalog/args.h
+++ b/bin/mkcatalog/args.h
@@ -258,19 +258,6 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
-    {
-      "spectrum",
-      UI_KEY_SPECTRUM,
-      0,
-      0,
-      "Object spectrum for cube (3D) datasets.",
-      GAL_OPTIONS_GROUP_OUTPUT,
-      &p->spectrum,
-      GAL_OPTIONS_NO_ARG_TYPE,
-      GAL_OPTIONS_RANGE_0_OR_1,
-      GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
-    },
     {
       "inbetweenints",
       UI_KEY_INBETWEENINTS,
@@ -2006,6 +1993,143 @@ struct argp_option program_options[] =
 
 
 
+
+    /* Multi-valued measurements. */
+    {
+      0, 0, 0, 0,
+      "Vector (multi-valued) measurements",
+      UI_GROUP_COLUMNS_VECTOR
+    },
+    {
+      "sum-in-slice",
+      UI_KEY_SUMINSLICE,
+      0,
+      0,
+      "[3D input] Sum of values in each slice.",
+      UI_GROUP_COLUMNS_VECTOR,
+      0,
+      GAL_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_column_codes_ll
+    },
+    {
+      "sum-err-in-slice",
+      UI_KEY_SUMERRINSLICE,
+      0,
+      0,
+      "[3D input] Error in '--sum-in-slice'.",
+      UI_GROUP_COLUMNS_VECTOR,
+      0,
+      GAL_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_column_codes_ll
+    },
+    {
+      "area-in-slice",
+      UI_KEY_AREAINSLICE,
+      0,
+      0,
+      "[3D input] Number of labeled in each slice.",
+      UI_GROUP_COLUMNS_VECTOR,
+      0,
+      GAL_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_column_codes_ll
+    },
+    {
+      "sum-proj-in-slice",
+      UI_KEY_SUMPROJINSLICE,
+      0,
+      0,
+      "[3D input] Sum of projected area in each slice.",
+      UI_GROUP_COLUMNS_VECTOR,
+      0,
+      GAL_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_column_codes_ll
+    },
+    {
+      "area-proj-in-slice",
+      UI_KEY_AREAPROJINSLICE,
+      0,
+      0,
+      "[3D input] Num. voxels in '--sum-proj-in-slice'.",
+      UI_GROUP_COLUMNS_VECTOR,
+      0,
+      GAL_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_column_codes_ll
+    },
+    {
+      "sum-proj-err-in-slice",
+      UI_KEY_SUMPROJERRINSLICE,
+      0,
+      0,
+      "[3D input] Error of '--sum-proj-in-slice'.",
+      UI_GROUP_COLUMNS_VECTOR,
+      0,
+      GAL_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_column_codes_ll
+    },
+    {
+      "area-other-in-slice",
+      UI_KEY_AREAOTHERINSLICE,
+      0,
+      0,
+      "[3D input] Area of other lab. in projected area.",
+      UI_GROUP_COLUMNS_VECTOR,
+      0,
+      GAL_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_column_codes_ll
+    },
+    {
+      "sum-other-in-slice",
+      UI_KEY_SUMOTHERINSLICE,
+      0,
+      0,
+      "[3D input] Sum of other lab. in projected area.",
+      UI_GROUP_COLUMNS_VECTOR,
+      0,
+      GAL_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_column_codes_ll
+    },
+    {
+      "sum-other-err-in-slice",
+      UI_KEY_SUMOTHERERRINSLICE,
+      0,
+      0,
+      "[3D input] Area in '--sum-other-in-slice'.",
+      UI_GROUP_COLUMNS_VECTOR,
+      0,
+      GAL_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_column_codes_ll
+    },
+
+
+
+
     {0}
   };
 
diff --git a/bin/mkcatalog/columns.c b/bin/mkcatalog/columns.c
index 4758ad33..f1086e15 100644
--- a/bin/mkcatalog/columns.c
+++ b/bin/mkcatalog/columns.c
@@ -331,9 +331,9 @@ columns_sanity_check(struct mkcatalogparams *p)
           case UI_KEY_GEOW3:
           case UI_KEY_CLUMPSW3:
           case UI_KEY_CLUMPSGEOW3:
-            error(EXIT_FAILURE, 0, "%s (hdu %s) is a 2D dataset, so columns "
-                  "relating to a third dimension cannot be requested",
-                  p->objectsfile, p->cp.hdu);
+            error(EXIT_FAILURE, 0, "%s (hdu %s) is a 2D dataset, so "
+                  "columns relating to a third dimension cannot be "
+                  "requested", p->objectsfile, p->cp.hdu);
           }
       break;
 
@@ -377,9 +377,9 @@ void
 columns_define_alloc(struct mkcatalogparams *p)
 {
   gal_list_i32_t *colcode;
-  size_t ndim=p->objects->ndim;
   gal_list_str_t *strtmp, *noclumpimg=NULL;
   int disp_fmt=0, disp_width=0, disp_precision=0;
+  size_t dsize[2], colndim, inndim=p->objects->ndim;
   char *name=NULL, *unit=NULL, *ocomment=NULL, *ccomment=NULL;
   uint8_t otype=GAL_TYPE_INVALID, ctype=GAL_TYPE_INVALID, *oiflag, *ciflag;
 
@@ -391,14 +391,22 @@ columns_define_alloc(struct mkcatalogparams *p)
      smaller domain of raw measurements. So to avoid having to calculate
      something multiple times, each parameter will flag the intermediate
      parameters it requires in these arrays. */
-  oiflag = p->oiflag = gal_pointer_allocate(GAL_TYPE_UINT8, OCOL_NUMCOLS, 1,
-                                            __func__, "oiflag");
-  ciflag = p->ciflag = gal_pointer_allocate(GAL_TYPE_UINT8, CCOL_NUMCOLS, 1,
-                                            __func__, "ciflag");
+  oiflag = p->oiflag = gal_pointer_allocate(GAL_TYPE_UINT8, OCOL_NUMCOLS,
+                                            1, __func__, "oiflag");
+  ciflag = p->ciflag = gal_pointer_allocate(GAL_TYPE_UINT8, CCOL_NUMCOLS,
+                                            1, __func__, "ciflag");
 
   /* Allocate the columns. */
   for(colcode=p->columnids; colcode!=NULL; colcode=colcode->next)
     {
+      /* Dimensions of output column. By default: most columns will be
+         single dimensional, the vector columns will update this. Also,
+         vector outputs will need 'dsize[1]'. But to avoid forgetting,
+         we'll set it to an absurd value to cause a crash if it is
+         forgotten. */
+      colndim=1;
+      dsize[1]=GAL_BLANK_SIZE_T;
+
       /* Set the column-specific parameters, please follow the same order
          as 'args.h'. IMPORTANT: we want the names to be the same as the
          option names. Note that zero 'disp_' variables will be
@@ -486,7 +494,8 @@ columns_define_alloc(struct mkcatalogparams *p)
         case UI_KEY_SB:
           name           = "SURFACE_BRIGHTNESS";
           unit           = "mag/arcsec^2";
-          ocomment       = "Surface brightness (magnitude of 
brightness/area).";
+          ocomment       = "Surface brightness (magnitude of "
+                           "brightness/area).";
           ccomment       = ocomment;
           otype          = GAL_TYPE_FLOAT32;
           ctype          = GAL_TYPE_FLOAT32;
@@ -518,7 +527,8 @@ columns_define_alloc(struct mkcatalogparams *p)
         case UI_KEY_AREAXY:
           name           = "AREAXY";
           unit           = "counter";
-          ocomment       = "Projected valued pixels in first two dimensions.";
+          ocomment       = "Projected valued pixels in first two "
+                           "dimensions.";
           ccomment       = ocomment;
           otype          = GAL_TYPE_INT32;
           ctype          = GAL_TYPE_INT32;
@@ -964,7 +974,7 @@ columns_define_alloc(struct mkcatalogparams *p)
           oiflag[     OCOL_GY     ] = ciflag[ CCOL_GY     ] = 1;
           oiflag[     OCOL_SUMWHT ] = ciflag[ CCOL_SUMWHT ] = 1;
           oiflag[     OCOL_NUMALL ] = ciflag[ CCOL_NUMALL ] = 1;
-          if(ndim==3)
+          if(inndim==3)
             {
               oiflag[ OCOL_VZ ] = ciflag[ CCOL_VZ ] = 1;
               oiflag[ OCOL_GZ ] = ciflag[ CCOL_GZ ] = 1;
@@ -988,7 +998,7 @@ columns_define_alloc(struct mkcatalogparams *p)
           oiflag[     OCOL_GY     ] = ciflag[ CCOL_GY     ] = 1;
           oiflag[     OCOL_SUMWHT ] = ciflag[ CCOL_SUMWHT ] = 1;
           oiflag[     OCOL_NUMALL ] = ciflag[ CCOL_NUMALL ] = 1;
-          if(ndim==3)
+          if(inndim==3)
             {
               oiflag[ OCOL_VZ     ] = ciflag[ CCOL_VZ     ] = 1;
               oiflag[ OCOL_GZ     ] = ciflag[ CCOL_GZ     ] = 1;
@@ -1030,7 +1040,7 @@ columns_define_alloc(struct mkcatalogparams *p)
           oiflag[   OCOL_GX     ] = ciflag[ CCOL_GX     ] = 1;
           oiflag[   OCOL_GY     ] = ciflag[ CCOL_GY     ] = 1;
           oiflag[   OCOL_NUMALL ] = ciflag[ CCOL_NUMALL ] = 1;
-          if(ndim==3)
+          if(inndim==3)
             oiflag[ OCOL_GZ     ] = ciflag[ CCOL_GZ     ] = 1;
           break;
 
@@ -1048,7 +1058,7 @@ columns_define_alloc(struct mkcatalogparams *p)
           oiflag[   OCOL_GX     ] = ciflag[ CCOL_GX     ] = 1;
           oiflag[   OCOL_GY     ] = ciflag[ CCOL_GY     ] = 1;
           oiflag[   OCOL_NUMALL ] = ciflag[ CCOL_NUMALL ] = 1;
-          if(ndim==3)
+          if(inndim==3)
             oiflag[ OCOL_GZ     ] = ciflag[ CCOL_GZ     ] = 1;
           break;
 
@@ -1086,7 +1096,7 @@ columns_define_alloc(struct mkcatalogparams *p)
           oiflag[     OCOL_C_GY     ] = 1;
           oiflag[     OCOL_C_SUMWHT ] = 1;
           oiflag[     OCOL_C_NUMALL ] = 1;
-          if(ndim==3)
+          if(inndim==3)
             {
               oiflag[ OCOL_C_VZ     ] = 1;
               oiflag[ OCOL_C_GZ     ] = 1;
@@ -1110,7 +1120,7 @@ columns_define_alloc(struct mkcatalogparams *p)
           oiflag[     OCOL_C_GY     ] = 1;
           oiflag[     OCOL_C_SUMWHT ] = 1;
           oiflag[     OCOL_C_NUMALL ] = 1;
-          if(ndim==3)
+          if(inndim==3)
             {
               oiflag[ OCOL_C_VZ     ] = 1;
               oiflag[ OCOL_C_GZ     ] = 1;
@@ -1130,19 +1140,20 @@ columns_define_alloc(struct mkcatalogparams *p)
           columns_alloc_clumpsradec(p);
           oiflag[ OCOL_C_VX     ] = 1;
           oiflag[ OCOL_C_VY     ] = 1;
-          oiflag[ OCOL_C_VZ     ] = 1;
           oiflag[ OCOL_C_GX     ] = 1;
           oiflag[ OCOL_C_GY     ] = 1;
-          oiflag[ OCOL_C_GZ     ] = 1;
           oiflag[ OCOL_C_SUMWHT ] = 1;
           oiflag[ OCOL_C_NUMALL ] = 1;
-          if(ndim==3)
+          if(inndim==3)
             {
+              oiflag[ OCOL_C_VZ ] = 1;
+              oiflag[ OCOL_C_GZ ] = 1;
             }
           break;
 
         case UI_KEY_CLUMPSGEOW1:
-          name           = gal_checkset_malloc_cat("CLUMPS_GEO", p->ctype[0]);
+          name           = gal_checkset_malloc_cat("CLUMPS_GEO",
+                                                   p->ctype[0]);
           unit           = p->objects->wcs->cunit[0];
           ocomment       = "Geometric center of all clumps (WCS axis 1).";
           ccomment       = NULL;
@@ -1155,12 +1166,13 @@ columns_define_alloc(struct mkcatalogparams *p)
           oiflag[   OCOL_C_GX     ] = 1;
           oiflag[   OCOL_C_GY     ] = 1;
           oiflag[   OCOL_C_NUMALL ] = 1;
-          if(ndim==3)
+          if(inndim==3)
             oiflag[ OCOL_C_GZ     ] = 1;
           break;
 
         case UI_KEY_CLUMPSGEOW2:
-          name           = gal_checkset_malloc_cat("CLUMPS_GEO", p->ctype[1]);
+          name           = gal_checkset_malloc_cat("CLUMPS_GEO",
+                                                   p->ctype[1]);
           unit           = p->objects->wcs->cunit[1];
           ocomment       = "Geometric center of all clumps (WCS axis 2).";
           ccomment       = NULL;
@@ -1173,12 +1185,13 @@ columns_define_alloc(struct mkcatalogparams *p)
           oiflag[   OCOL_C_GX     ] = 1;
           oiflag[   OCOL_C_GY     ] = 1;
           oiflag[   OCOL_C_NUMALL ] = 1;
-          if(ndim==3)
+          if(inndim==3)
             oiflag[ OCOL_C_GZ     ] = 1;
           break;
 
         case UI_KEY_CLUMPSGEOW3:
-          name           = gal_checkset_malloc_cat("CLUMPS_GEO", p->ctype[2]);
+          name           = gal_checkset_malloc_cat("CLUMPS_GEO",
+                                                   p->ctype[2]);
           unit           = p->objects->wcs->cunit[2];
           ocomment       = "Geometric center of all clumps (WCS axis 3).";
           ccomment       = NULL;
@@ -1275,7 +1288,8 @@ columns_define_alloc(struct mkcatalogparams *p)
           name           = "STD";
           unit           = MKCATALOG_NO_UNIT;
           ocomment       = "Standard deviation of sky subtracted values.";
-          ccomment       = "Standard deviation of pixels subtracted by 
rivers.";
+          ccomment       = "Standard deviation of pixels subtracted by "
+                           "rivers.";
           otype          = GAL_TYPE_FLOAT32;
           ctype          = GAL_TYPE_FLOAT32;
           disp_fmt       = GAL_TABLE_DISPLAY_FMT_GENERAL;
@@ -1367,8 +1381,10 @@ columns_define_alloc(struct mkcatalogparams *p)
         case UI_KEY_SIGCLIPSTD:
           name           = "SIGCLIP-STD";
           unit           = MKCATALOG_NO_UNIT;
-          ocomment       = "Sigma-clipped standard deviation of object 
pixels.";
-          ccomment       = "Sigma-clipped standard deviation of clump pixels.";
+          ocomment       = "Sigma-clipped standard deviation of object "
+                            "pixels.";
+          ccomment       = "Sigma-clipped standard deviation of clump "
+            "pixels.";
           otype          = GAL_TYPE_FLOAT32;
           ctype          = GAL_TYPE_FLOAT32;
           disp_fmt       = GAL_TABLE_DISPLAY_FMT_GENERAL;
@@ -1515,7 +1531,8 @@ columns_define_alloc(struct mkcatalogparams *p)
         case UI_KEY_UPPERLIMITSB:
           name           = "UPPERLIMIT_SB";
           unit           = "mag/arcsec^2";
-          ocomment       = "Upper limit surface brightness over its 
footprint.";
+          ocomment       = "Upper limit surface brightness over its "
+                           "footprint.";
           ccomment       = ocomment;
           otype          = GAL_TYPE_FLOAT32;
           ctype          = GAL_TYPE_FLOAT32;
@@ -1586,7 +1603,7 @@ columns_define_alloc(struct mkcatalogparams *p)
           disp_width     = 8;
           disp_precision = 3;
           p->upperlimit  = 1;
-          oiflag[ OCOL_UPPERLIMIT_SKEW ] = oiflag[ CCOL_UPPERLIMIT_SKEW ] = 1;
+          oiflag[ OCOL_UPPERLIMIT_SKEW ]=oiflag[ CCOL_UPPERLIMIT_SKEW ]=1;
           break;
 
         case UI_KEY_RIVERMEAN:
@@ -1834,7 +1851,8 @@ columns_define_alloc(struct mkcatalogparams *p)
         case UI_KEY_HALFSUMAREA:
           name           = "HALF_SUM_AREA";
           unit           = "counter";
-          ocomment       = "Number of brightest pixels containing half of 
total sum.";
+          ocomment       = "Number of brightest pixels containing half "
+                           "of total sum.";
           ccomment       = ocomment;
           otype          = GAL_TYPE_INT32;
           ctype          = GAL_TYPE_INT32;
@@ -1849,7 +1867,8 @@ columns_define_alloc(struct mkcatalogparams *p)
         case UI_KEY_HALFMAXAREA:
           name           = "HALF_MAX_AREA";
           unit           = "counter";
-          ocomment       = "Number of pixels with a value larger than half the 
maximum.";
+          ocomment       = "Number of pixels with a value larger than "
+                           "half the maximum.";
           ccomment       = ocomment;
           otype          = GAL_TYPE_INT32;
           ctype          = GAL_TYPE_INT32;
@@ -1863,7 +1882,8 @@ columns_define_alloc(struct mkcatalogparams *p)
         case UI_KEY_HALFMAXSUM:
           name           = "HALF_MAX_SUM";
           unit           = MKCATALOG_NO_UNIT;
-          ocomment       = "Sum of pixels with a value larger than half the 
maximum.";
+          ocomment       = "Sum of pixels with a value larger than half "
+                           "the maximum.";
           ccomment       = ocomment;
           otype          = GAL_TYPE_FLOAT32;
           ctype          = GAL_TYPE_FLOAT32;
@@ -1877,7 +1897,8 @@ columns_define_alloc(struct mkcatalogparams *p)
         case UI_KEY_HALFMAXSB:
           name           = "HALF_MAX_SB";
           unit           = "mag/arcsec^2";
-          ocomment       = "Surface brightness for pixels above half the 
maximum.";
+          ocomment       = "Surface brightness for pixels above half "
+                           "the maximum.";
           ccomment       = ocomment;
           otype          = GAL_TYPE_FLOAT32;
           ctype          = GAL_TYPE_FLOAT32;
@@ -1892,7 +1913,8 @@ columns_define_alloc(struct mkcatalogparams *p)
         case UI_KEY_HALFSUMSB:
           name           = "HALF_SUM_SB";
           unit           = "mag/arcsec^2";
-          ocomment       = "Surface brightness for pixels above half the sum 
of all labeled pixels.";
+          ocomment       = "Surface brightness for pixels above half "
+                            "the sum of all labeled pixels.";
           ccomment       = ocomment;
           otype          = GAL_TYPE_FLOAT32;
           ctype          = GAL_TYPE_FLOAT32;
@@ -1919,12 +1941,14 @@ columns_define_alloc(struct mkcatalogparams *p)
           oiflag[ OCOL_SUM ] = ciflag[ CCOL_SUM ] = 1;
           if(colcode->v==UI_KEY_FRACMAX1SUM)
             {
-              ocomment = "Sum of pixels brighter than 1st fraction of 
maximum.";
+              ocomment = "Sum of pixels brighter than 1st fraction of "
+                         "maximum.";
               oiflag[ OCOL_FRACMAX1SUM ] = ciflag[ CCOL_FRACMAX1SUM ] = 1;
             }
           else
             {
-              ocomment = "Sum of pixels brighter than 2nd fraction of 
maximum.";
+              ocomment = "Sum of pixels brighter than 2nd fraction of "
+                         "maximum.";
               oiflag[ OCOL_FRACMAX2SUM ] = ciflag[ CCOL_FRACMAX2SUM ] = 1;
             }
           ccomment = ocomment;
@@ -1936,7 +1960,8 @@ columns_define_alloc(struct mkcatalogparams *p)
                              ? "FRAC_MAX1_AREA"
                              : "FRAC_MAX2_AREA" );
           unit           = "counter";
-          ocomment       = "Number of pixels brighter than given fraction of 
maximum value.";
+          ocomment       = "Number of pixels brighter than given fraction "
+                           "of maximum value.";
           ccomment       = ocomment;
           otype          = GAL_TYPE_INT32;
           ctype          = GAL_TYPE_INT32;
@@ -1962,9 +1987,11 @@ columns_define_alloc(struct mkcatalogparams *p)
           disp_fmt       = GAL_TABLE_DISPLAY_FMT_GENERAL;
           disp_width     = 10;
           disp_precision = 3;
-          oiflag[ OCOL_NUM        ] = ciflag[ CCOL_NUM        ] = 1; /* 
halfsumarea */
+          /* halfsumarea: */
+          oiflag[ OCOL_NUM        ] = ciflag[ CCOL_NUM        ] = 1;
           oiflag[ OCOL_SUM        ] = ciflag[ CCOL_SUM        ] = 1;
-          oiflag[ OCOL_SUMWHT     ] = ciflag[ CCOL_SUMWHT     ] = 1; /* 
axisratio. */
+          /* axisratio: */
+          oiflag[ OCOL_SUMWHT     ] = ciflag[ CCOL_SUMWHT     ] = 1;
           oiflag[ OCOL_VX         ] = ciflag[ CCOL_VX         ] = 1;
           oiflag[ OCOL_VY         ] = ciflag[ CCOL_VY         ] = 1;
           oiflag[ OCOL_VXX        ] = ciflag[ CCOL_VXX        ] = 1;
@@ -1981,46 +2008,199 @@ columns_define_alloc(struct mkcatalogparams *p)
             case UI_KEY_FWHM:
               name="FWHM";
               oiflag[ OCOL_HALFMAXNUM  ] = ciflag[ CCOL_HALFMAXNUM  ] = 1;
-              ocomment = "Full width at half maximum (accounting for 
ellipticity).";
+              ocomment = "Full width at half maximum (accounting for "
+                          "ellipticity).";
               break;
             case UI_KEY_HALFMAXRADIUS:
               name="HALF_MAX_RADIUS";
               oiflag[ OCOL_HALFMAXNUM  ] = ciflag[ CCOL_HALFMAXNUM  ] = 1;
-              ocomment = "Radius at half of maximum (accounting for 
ellipticity).";
+              ocomment = "Radius at half of maximum (accounting for "
+                         "ellipticity).";
               break;
             case UI_KEY_HALFSUMRADIUS:
               name="HALF_SUM_RADIUS";
               oiflag[ OCOL_HALFSUMNUM  ] = ciflag[ CCOL_HALFSUMNUM  ] = 1;
-              ocomment = "Radius at half of total sum (accounting for 
ellipticity).";
+              ocomment = "Radius at half of total sum (accounting for "
+                         "ellipticity).";
               break;
             case UI_KEY_FRACMAX1RADIUS:
               name="FRAC_MAX_RADIUS_1";
               oiflag[ OCOL_FRACMAX1NUM ] = ciflag[ CCOL_FRACMAX1NUM ] = 1;
-              ocomment = "Radius derived from area of 1st fraction of 
maximum.";
+              ocomment = "Radius derived from area of 1st fraction of "
+                         "maximum.";
               break;
             case UI_KEY_FRACMAX2RADIUS:
               name="FRAC_MAX_RADIUS_2";
               oiflag[ OCOL_FRACMAX2NUM ] = ciflag[ CCOL_FRACMAX2NUM ] = 1;
-              ocomment = "Radius derived from area of 2nd fraction of 
maximum.";
+              ocomment = "Radius derived from area of 2nd fraction of "
+                         "maximum.";
               break;
             }
           ccomment = ocomment;
           break;
 
+        case UI_KEY_SUMINSLICE:
+          colndim        = 2;
+          name           = "SUM-IN-SLICE";
+          unit           = MKCATALOG_NO_UNIT;
+          dsize[1]       = p->objects->dsize[0]; /* Third FITS dim. */
+          ocomment       = "Sum of values with this label in each slice.";
+          ccomment       = ocomment;
+          otype          = GAL_TYPE_FLOAT32;
+          ctype          = GAL_TYPE_FLOAT32;
+          disp_fmt       = 0;
+          disp_width     = 6;
+          disp_precision = 0;
+          oiflag[ OCOL_SUMINSLICE ] = 1;
+          oiflag[ OCOL_NUMINSLICE ] = 1;
+          break;
+
+        case UI_KEY_SUMERRINSLICE:
+          colndim        = 2;
+          name           = "SUM-ERR-IN-SLICE";
+          unit           = MKCATALOG_NO_UNIT;
+          dsize[1]       = p->objects->dsize[0]; /* Third FITS dim. */
+          ocomment       = "Error in 'SUM-IN-SLICE'";
+          ccomment       = ocomment;
+          otype          = GAL_TYPE_FLOAT32;
+          ctype          = GAL_TYPE_FLOAT32;
+          disp_fmt       = 0;
+          disp_width     = 6;
+          disp_precision = 0;
+          oiflag[ OCOL_SUMINSLICE ]    = 1;
+          oiflag[ OCOL_NUMINSLICE ]    = 1;
+          oiflag[ OCOL_SUMVARINSLICE ] = 1;
+          break;
+
+        case UI_KEY_AREAINSLICE:
+          colndim        = 2;
+          name           = "AREA-IN-SLICE";
+          unit           = "counter";
+          dsize[1]       = p->objects->dsize[0]; /* Third FITS dim. */
+          ocomment       = "Number of pixels of each label in each slice.";
+          ccomment       = ocomment;
+          otype          = GAL_TYPE_INT32;
+          ctype          = GAL_TYPE_INT32;
+          disp_fmt       = 0;
+          disp_width     = 6;
+          disp_precision = 0;
+          oiflag[ OCOL_NUMINSLICE ] = 1;
+          break;
+
+        case UI_KEY_SUMPROJINSLICE:
+          colndim        = 2;
+          name           = "SUM-PROJ-IN-SLICE";
+          unit           = MKCATALOG_NO_UNIT;
+          dsize[1]       = p->objects->dsize[0]; /* Third FITS dim. */
+          ocomment       = "Sum of values in projected area of each slice.";
+          ccomment       = ocomment;
+          otype          = GAL_TYPE_FLOAT32;
+          ctype          = GAL_TYPE_FLOAT32;
+          disp_fmt       = 0;
+          disp_width     = 6;
+          disp_precision = 0;
+          oiflag[ OCOL_SUMPROJINSLICE ] = 1;
+          oiflag[ OCOL_NUMPROJINSLICE ] = 1;
+          break;
+
+        case UI_KEY_SUMPROJERRINSLICE:
+          colndim        = 2;
+          name           = "SUM-PROJ-ERR-IN-SLICE";
+          unit           = MKCATALOG_NO_UNIT;
+          dsize[1]       = p->objects->dsize[0]; /* Third FITS dim. */
+          ocomment       = "Error in 'SUM-PROJ-IN-SLICE'";
+          ccomment       = ocomment;
+          otype          = GAL_TYPE_FLOAT32;
+          ctype          = GAL_TYPE_FLOAT32;
+          disp_fmt       = 0;
+          disp_width     = 6;
+          disp_precision = 0;
+          oiflag[ OCOL_SUMPROJINSLICE ]    = 1;
+          oiflag[ OCOL_NUMPROJINSLICE ]    = 1;
+          oiflag[ OCOL_SUMPROJVARINSLICE ] = 1;
+          break;
+
+        case UI_KEY_AREAPROJINSLICE:
+          colndim        = 2;
+          name           = "AREA-PROJ-IN-SLICE";
+          unit           = "counter";
+          dsize[1]       = p->objects->dsize[0]; /* Third FITS dim. */
+          ocomment       = "Number of usable pixels in "
+                           "'SUM-PROJ-IN-SLICE'.";
+          ccomment       = ocomment;
+          otype          = GAL_TYPE_INT32;
+          ctype          = GAL_TYPE_INT32;
+          disp_fmt       = 0;
+          disp_width     = 6;
+          disp_precision = 0;
+          oiflag[ OCOL_NUMPROJINSLICE ] = 1;
+          break;
+
+        case UI_KEY_SUMOTHERINSLICE:
+          colndim        = 2;
+          name           = "SUM-OTHER-IN-SLICE";
+          unit           = MKCATALOG_NO_UNIT;
+          dsize[1]       = p->objects->dsize[0]; /* Third FITS dim. */
+          ocomment       = "Sum in other labels in projection in each "
+                           "slice.";
+          ccomment       = ocomment;
+          otype          = GAL_TYPE_FLOAT32;
+          ctype          = GAL_TYPE_FLOAT32;
+          disp_fmt       = 0;
+          disp_width     = 6;
+          disp_precision = 0;
+          oiflag[ OCOL_SUMOTHERINSLICE ] = 1;
+          oiflag[ OCOL_NUMOTHERINSLICE ] = 1;
+          break;
+
+        case UI_KEY_SUMOTHERERRINSLICE:
+          colndim        = 2;
+          name           = "SUM-OTHER-ERR-IN-SLICE";
+          unit           = MKCATALOG_NO_UNIT;
+          dsize[1]       = p->objects->dsize[0]; /* Third FITS dim. */
+          ocomment       = "Error in 'SUM-OTHER-IN-SLICE'";
+          ccomment       = ocomment;
+          otype          = GAL_TYPE_FLOAT32;
+          ctype          = GAL_TYPE_FLOAT32;
+          disp_fmt       = 0;
+          disp_width     = 6;
+          disp_precision = 0;
+          oiflag[ OCOL_SUMOTHERINSLICE ]    = 1;
+          oiflag[ OCOL_NUMOTHERINSLICE ]    = 1;
+          oiflag[ OCOL_SUMOTHERVARINSLICE ] = 1;
+          break;
+
+        case UI_KEY_AREAOTHERINSLICE:
+          colndim        = 2;
+          name           = "AREA-OTHER-IN-SLICE";
+          unit           = "counter";
+          dsize[1]       = p->objects->dsize[0]; /* Third FITS dim. */
+          ocomment       = "Number of usable pixels in "
+                           "'SUM-OTHER-IN-SLICE'";
+          ccomment       = ocomment;
+          otype          = GAL_TYPE_INT32;
+          ctype          = GAL_TYPE_INT32;
+          disp_fmt       = 0;
+          disp_width     = 6;
+          disp_precision = 0;
+          oiflag[ OCOL_NUMOTHERINSLICE ] = 1;
+          break;
+
         default:
-          error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s to fix "
-                "the problem. The code %d is not an internally recognized "
-                "column code", __func__, PACKAGE_BUGREPORT, colcode->v);
+          error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s to "
+                "fix the problem. The code %d is not an internally "
+                "recognized column code", __func__, PACKAGE_BUGREPORT,
+                colcode->v);
         }
 
-
       /* If this is an object's column, add it to the list of columns. We
          will be using the 'status' element to keep the MakeCatalog code
          for the columns. */
       if(otype!=GAL_TYPE_INVALID)
         {
-          gal_list_data_add_alloc(&p->objectcols, NULL, otype, 1,
-                                  &p->numobjects, NULL, 0, p->cp.minmapsize,
+          dsize[0]=p->numobjects;
+          gal_list_data_add_alloc(&p->objectcols, NULL, otype, colndim,
+                                  dsize, NULL, 0, p->cp.minmapsize,
                                   p->cp.quietmmap, name, unit, ocomment);
           p->objectcols->status         = colcode->v;
           p->objectcols->disp_fmt       = disp_fmt;
@@ -2028,7 +2208,6 @@ columns_define_alloc(struct mkcatalogparams *p)
           p->objectcols->disp_precision = disp_precision;
         }
 
-
       /* Similar to the objects column above but for clumps, but since the
          clumps image is optional, we need a further check before actually
          allocating the column. */
@@ -2037,10 +2216,11 @@ columns_define_alloc(struct mkcatalogparams *p)
           /* If a clumps labeled image, add this column for the output. */
           if(p->clumps)
             {
-              gal_list_data_add_alloc(&p->clumpcols, NULL, ctype, 1,
-                                      &p->numclumps, NULL, 0,
-                                      p->cp.minmapsize, p->cp.quietmmap,
-                                      name, unit, ccomment);
+              dsize[0]=p->numclumps;
+              gal_list_data_add_alloc(&p->clumpcols, NULL, ctype, colndim,
+                                      dsize, NULL, 0, p->cp.minmapsize,
+                                      p->cp.quietmmap, name, unit,
+                                      ccomment);
               p->clumpcols->status         = colcode->v;
               p->clumpcols->disp_fmt       = disp_fmt;
               p->clumpcols->disp_width     = disp_width;
@@ -2072,10 +2252,10 @@ columns_define_alloc(struct mkcatalogparams *p)
     {
       gal_list_str_reverse(&noclumpimg);
       fprintf(stderr, "WARNING: the following column(s) are unique to "
-              "clumps (not objects), but the '--clumpscat' option has not "
-              "been called, or there were no clumps in the clumps labeled "
-              "image. Hence, these columns will be ignored in the "
-              "output.\n\n");
+              "clumps (not objects), but the '--clumpscat' option has "
+              "not been called, or there were no clumps in the clumps "
+              "labeled image. Hence, these columns will be ignored in "
+              "the output.\n\n");
       for(strtmp=noclumpimg; strtmp!=NULL; strtmp=strtmp->next)
         fprintf(stderr, "\t%s\n", strtmp->v);
       gal_list_str_free(noclumpimg, 1);
@@ -2113,8 +2293,8 @@ columns_define_alloc(struct mkcatalogparams *p)
 /******************************************************************/
 #define MKC_RATIO(TOP,BOT) ( (BOT)!=0.0f ? (TOP)/(BOT) : NAN )
 #define MKC_MAG(B) ( gal_units_counts_to_mag(B, p->zeropoint) )
-#define MKC_SB(B, A) ( ((B)>0 && (A)>0)                                 \
-                       ? MKC_MAG(B) + 2.5f * log10((A) * p->pixelarcsecsq) \
+#define MKC_SB(B, A) ( ((B)>0 && (A)>0)                                  \
+                       ? MKC_MAG(B) + 2.5f * log10((A)*p->pixelarcsecsq) \
                        : NAN )
 
 
@@ -2221,9 +2401,9 @@ columns_second_order(struct mkcatalog_passparams *pp, 
double *row,
 
     /* Error. */
     default:
-      error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix the "
-            "problem. %d is not a recognized key", __func__, PACKAGE_BUGREPORT,
-            key);
+      error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+            "the problem. %d is not a recognized key", __func__,
+            PACKAGE_BUGREPORT, key);
     }
 
   /* Return the output. */
@@ -2311,14 +2491,13 @@ columns_xy_extrema(struct mkcatalog_passparams *pp, 
double *oi,
       case UI_KEY_MINZ: return coord[ndim-3] + 1;                   break;
       case UI_KEY_MAXZ: return coord[ndim-3] + tile->dsize[ndim-3]; break;
       default:
-        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix the "
-              "problem. The value %d is not a recognized value", __func__,
-              PACKAGE_BUGREPORT, key);
+        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
+              "fix the problem. The value %d is not a recognized value",
+              __func__, PACKAGE_BUGREPORT, key);
       }
   else
     return 0;
 
-
   /* Control should not reach here. */
   error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s to fix the "
         "problem. Control should not reach the end of this function",
@@ -2330,6 +2509,73 @@ columns_xy_extrema(struct mkcatalog_passparams *pp, 
double *oi,
 
 
 
+/* Fill vector columns. */
+static void
+columns_vector_fill(int key, gal_data_t *column, gal_data_t *v,
+                    size_t oind)
+{
+  int sqr=0;
+  float *of32;
+  int32_t *oi32;
+  gal_data_t *vec;
+  int32_t *ii32, *ii32f;
+  double  *if64, *if64f;
+
+  /* Set the input pointer. */
+  switch(key)
+    {
+    case UI_KEY_SUMINSLICE:        vec=&v[VEC_SUMINSLICE];      break;
+    case UI_KEY_AREAINSLICE:       vec=&v[VEC_NUMINSLICE];      break;
+    case UI_KEY_SUMPROJINSLICE:    vec=&v[VEC_SUMPROJINSLICE];  break;
+    case UI_KEY_AREAPROJINSLICE:   vec=&v[VEC_NUMPROJINSLICE];  break;
+    case UI_KEY_AREAOTHERINSLICE:  vec=&v[VEC_NUMOTHERINSLICE]; break;
+    case UI_KEY_SUMOTHERINSLICE:   vec=&v[VEC_SUMOTHERINSLICE]; break;
+
+    /* Those that need special attention. */
+    case UI_KEY_SUMERRINSLICE:
+      vec=&v[VEC_SUMVARINSLICE];       sqr=1; break;
+    case UI_KEY_SUMPROJERRINSLICE:
+      vec=&v[VEC_SUMPROJVARINSLICE];   sqr=1; break;
+    case UI_KEY_SUMOTHERERRINSLICE:
+      vec=&v[VEC_SUMOTHERVARINSLICE];  sqr=1; break;
+
+    /* Unexpected! */
+    default:
+      error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at '%s' to "
+            "fix the problem. Column identifier '%d' is not expected "
+            "here", __func__, PACKAGE_BUGREPORT, key);
+    }
+
+  /* Set the pointers. */
+  ii32 = vec->array;       ii32f = ii32 + vec->size;
+  if64 = vec->array;       if64f = if64 + vec->size;
+
+  /* Copy the values, one by one.*/
+  switch(column->type)
+    {
+    case GAL_TYPE_INT32:
+      oi32=gal_pointer_increment(column->array, oind*column->dsize[1],
+                                 column->type);
+      if(sqr) {do *oi32++ = sqrt(*ii32); while(++ii32<ii32f);}
+      else    {do *oi32++ = *ii32;       while(++ii32<ii32f);}
+      break;
+
+    case GAL_TYPE_FLOAT32:
+      of32=gal_pointer_increment(column->array, oind*column->dsize[1],
+                                 column->type);
+      do *of32++ = *if64; while(++if64<if64f);
+      break;
+
+    default:
+      error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at '%s' to "
+            "fix the problem. Output type '%s' is not expected",
+            __func__, PACKAGE_BUGREPORT, gal_type_name(column->type, 1));
+    }
+}
+
+
+
+
 /* The magnitude error is directly derivable from the S/N:
 
    To derive the error in measuring the magnitude from the S/N, let's take
@@ -2387,13 +2633,12 @@ columns_fill(struct mkcatalog_passparams *pp)
   int key;
   double tmp;
   void *colarr;
-  gal_data_t *column;
-  double *ci, *oi=pp->oi;
   size_t tmpind=GAL_BLANK_SIZE_T;
-  size_t coord[3]={GAL_BLANK_SIZE_T, GAL_BLANK_SIZE_T, GAL_BLANK_SIZE_T};
-
+  gal_data_t *column, *vec=pp->vector;
+  double *ci, *oi=pp->oi, **vcc=NULL, **gcc=NULL;
+  double **vo=NULL, **vc=NULL, **go=NULL, **gc=NULL;
   size_t i, cind, coind, sr=pp->clumpstartindex, oind=GAL_BLANK_SIZE_T;
-  double **vo=NULL, **vc=NULL, **go=NULL, **gc=NULL, **vcc=NULL, **gcc=NULL;
+  size_t coord[3]={GAL_BLANK_SIZE_T, GAL_BLANK_SIZE_T, GAL_BLANK_SIZE_T};
 
   /* Find the object's index in final catalog. */
   if(p->outlabs)
@@ -2483,30 +2728,36 @@ columns_fill(struct mkcatalog_passparams *pp)
           break;
 
         case UI_KEY_GEOX:
-          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_GX], oi[OCOL_NUMALL] );
+          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_GX],
+                                               oi[OCOL_NUMALL] );
           break;
 
         case UI_KEY_GEOY:
-          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_GY], oi[OCOL_NUMALL] );
+          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_GY],
+                                               oi[OCOL_NUMALL] );
           break;
 
         case UI_KEY_GEOZ:
-          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_GZ], oi[OCOL_NUMALL] );
+          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_GZ],
+                                               oi[OCOL_NUMALL] );
           break;
 
         case UI_KEY_CLUMPSX:
-          ((float *)colarr)[oind] = POS_V_G(oi, OCOL_C_SUMWHT, OCOL_C_NUMWHT,
-                                            OCOL_C_VX, OCOL_C_GX);
+          ((float *)colarr)[oind] = POS_V_G(oi, OCOL_C_SUMWHT,
+                                            OCOL_C_NUMWHT, OCOL_C_VX,
+                                            OCOL_C_GX);
           break;
 
         case UI_KEY_CLUMPSY:
-          ((float *)colarr)[oind] = POS_V_G(oi, OCOL_C_SUMWHT, OCOL_C_NUMWHT,
-                                            OCOL_C_VY, OCOL_C_GY);
+          ((float *)colarr)[oind] = POS_V_G(oi, OCOL_C_SUMWHT,
+                                            OCOL_C_NUMWHT, OCOL_C_VY,
+                                            OCOL_C_GY);
           break;
 
         case UI_KEY_CLUMPSZ:
-          ((float *)colarr)[oind] = POS_V_G(oi, OCOL_C_SUMWHT, OCOL_C_NUMALL,
-                                            OCOL_C_VZ, OCOL_C_GZ);
+          ((float *)colarr)[oind] = POS_V_G(oi, OCOL_C_SUMWHT,
+                                            OCOL_C_NUMALL, OCOL_C_VZ,
+                                            OCOL_C_GZ);
           break;
 
         case UI_KEY_CLUMPSGEOX:
@@ -2525,27 +2776,33 @@ columns_fill(struct mkcatalog_passparams *pp)
           break;
 
         case UI_KEY_MINVALX:
-          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MINVX], 
oi[OCOL_MINVNUM] );
+          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MINVX],
+                                               oi[OCOL_MINVNUM] );
           break;
 
         case UI_KEY_MAXVALX:
-          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MAXVX], 
oi[OCOL_MAXVNUM] );
+          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MAXVX],
+                                               oi[OCOL_MAXVNUM] );
           break;
 
         case UI_KEY_MINVALY:
-          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MINVY], 
oi[OCOL_MINVNUM] );
+          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MINVY],
+                                               oi[OCOL_MINVNUM] );
           break;
 
         case UI_KEY_MAXVALY:
-          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MAXVY], 
oi[OCOL_MAXVNUM] );
+          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MAXVY],
+                                               oi[OCOL_MAXVNUM] );
           break;
 
         case UI_KEY_MINVALZ:
-          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MINVZ], 
oi[OCOL_MINVNUM] );
+          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MINVZ],
+                                               oi[OCOL_MINVNUM] );
           break;
 
         case UI_KEY_MAXVALZ:
-          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MAXVZ], 
oi[OCOL_MAXVNUM] );
+          ((float *)colarr)[oind] = MKC_RATIO( oi[OCOL_MAXVZ],
+                                               oi[OCOL_MAXVNUM] );
           break;
 
         case UI_KEY_MINVALNUM:
@@ -2562,7 +2819,8 @@ columns_fill(struct mkcatalog_passparams *pp)
         case UI_KEY_MAXY:
         case UI_KEY_MINZ:
         case UI_KEY_MAXZ:
-          ((uint32_t *)colarr)[oind]=columns_xy_extrema(pp, oi, coord, key);
+          ((uint32_t *)colarr)[oind]=columns_xy_extrema(pp, oi, coord,
+                                                        key);
           break;
 
         case UI_KEY_W1:
@@ -2589,10 +2847,10 @@ columns_fill(struct mkcatalog_passparams *pp)
         case UI_KEY_CLUMPSW1:
         case UI_KEY_CLUMPSW2:
         case UI_KEY_CLUMPSW3:
-          vcc[0][oind] = POS_V_G(oi, OCOL_C_SUMWHT, OCOL_C_NUMALL, OCOL_C_VX,
-                                 OCOL_C_GX);
-          vcc[1][oind] = POS_V_G(oi, OCOL_C_SUMWHT, OCOL_C_NUMALL, OCOL_C_VY,
-                                 OCOL_C_GY);
+          vcc[0][oind] = POS_V_G(oi, OCOL_C_SUMWHT, OCOL_C_NUMALL,
+                                 OCOL_C_VX, OCOL_C_GX);
+          vcc[1][oind] = POS_V_G(oi, OCOL_C_SUMWHT, OCOL_C_NUMALL,
+                                 OCOL_C_VY, OCOL_C_GY);
           if(p->objects->ndim==3)
             vcc[2][oind] = POS_V_G(oi, OCOL_C_SUMWHT, OCOL_C_NUMALL,
                                    OCOL_C_VZ, OCOL_C_GZ);
@@ -2724,7 +2982,8 @@ columns_fill(struct mkcatalog_passparams *pp)
           break;
 
         case UI_KEY_SKY:
-          ((float *)colarr)[oind] = MKC_RATIO(oi[OCOL_SUMSKY], 
oi[OCOL_NUMSKY]);
+          ((float *)colarr)[oind] = MKC_RATIO(oi[OCOL_SUMSKY],
+                                              oi[OCOL_NUMSKY]);
           break;
 
         case UI_KEY_SKYSTD:
@@ -2830,10 +3089,23 @@ columns_fill(struct mkcatalog_passparams *pp)
             ((float *)colarr)[oind] = tmp<1e-6 ? NAN : tmp;
           break;
 
+        case UI_KEY_SUMINSLICE:
+        case UI_KEY_AREAINSLICE:
+        case UI_KEY_SUMERRINSLICE:
+        case UI_KEY_SUMPROJINSLICE:
+        case UI_KEY_AREAPROJINSLICE:
+        case UI_KEY_SUMOTHERINSLICE:
+        case UI_KEY_AREAOTHERINSLICE:
+        case UI_KEY_SUMPROJERRINSLICE:
+        case UI_KEY_SUMOTHERERRINSLICE:
+          columns_vector_fill(key, column, vec, oind);
+          break;
+
         default:
           error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
-                "solve the problem. the output column code %d not recognized "
-                "(for objects). ", __func__, PACKAGE_BUGREPORT, key);
+                "solve the problem. the output column code %d not "
+                "recognized (for objects). ", __func__, PACKAGE_BUGREPORT,
+                key);
         }
     }
 
@@ -2927,27 +3199,33 @@ columns_fill(struct mkcatalog_passparams *pp)
             break;
 
           case UI_KEY_MINVALX:
-            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MINVX], 
ci[CCOL_MINVNUM] );
+            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MINVX],
+                                                 ci[CCOL_MINVNUM] );
             break;
 
           case UI_KEY_MAXVALX:
-            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MAXVX], 
ci[CCOL_MAXVNUM] );
+            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MAXVX],
+                                                 ci[CCOL_MAXVNUM] );
             break;
 
           case UI_KEY_MINVALY:
-            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MINVY], 
ci[CCOL_MINVNUM] );
+            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MINVY],
+                                                 ci[CCOL_MINVNUM] );
             break;
 
           case UI_KEY_MAXVALY:
-            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MAXVY], 
ci[CCOL_MAXVNUM] );
+            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MAXVY],
+                                                 ci[CCOL_MAXVNUM] );
             break;
 
           case UI_KEY_MINVALZ:
-            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MINVZ], 
ci[CCOL_MINVNUM] );
+            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MINVZ],
+                                                 ci[CCOL_MINVNUM] );
             break;
 
           case UI_KEY_MAXVALZ:
-            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MAXVZ], 
ci[CCOL_MAXVNUM] );
+            ((float *)colarr)[cind] = MKC_RATIO( ci[CCOL_MAXVZ],
+                                                 ci[CCOL_MAXVNUM] );
             break;
 
           case UI_KEY_MINVALNUM:
@@ -2958,12 +3236,12 @@ columns_fill(struct mkcatalog_passparams *pp)
             ((uint32_t *)colarr)[cind] = ci[CCOL_MAXVNUM];
             break;
 
-          case UI_KEY_MINX:  ((uint32_t *)colarr)[cind] = ci[CCOL_MINX];  
break;
-          case UI_KEY_MAXX:  ((uint32_t *)colarr)[cind] = ci[CCOL_MAXX];  
break;
-          case UI_KEY_MINY:  ((uint32_t *)colarr)[cind] = ci[CCOL_MINY];  
break;
-          case UI_KEY_MAXY:  ((uint32_t *)colarr)[cind] = ci[CCOL_MAXY];  
break;
-          case UI_KEY_MINZ:  ((uint32_t *)colarr)[cind] = ci[CCOL_MINZ];  
break;
-          case UI_KEY_MAXZ:  ((uint32_t *)colarr)[cind] = ci[CCOL_MAXZ];  
break;
+          case UI_KEY_MINX: ((uint32_t *)colarr)[cind]=ci[CCOL_MINX];break;
+          case UI_KEY_MAXX: ((uint32_t *)colarr)[cind]=ci[CCOL_MAXX];break;
+          case UI_KEY_MINY: ((uint32_t *)colarr)[cind]=ci[CCOL_MINY];break;
+          case UI_KEY_MAXY: ((uint32_t *)colarr)[cind]=ci[CCOL_MAXY];break;
+          case UI_KEY_MINZ: ((uint32_t *)colarr)[cind]=ci[CCOL_MINZ];break;
+          case UI_KEY_MAXZ: ((uint32_t *)colarr)[cind]=ci[CCOL_MAXZ];break;
 
           case UI_KEY_W1:
           case UI_KEY_W2:
@@ -3006,8 +3284,9 @@ columns_fill(struct mkcatalog_passparams *pp)
 
           case UI_KEY_STD:
             ((float *)colarr)[cind] =
-              gal_statistics_std_from_sums(oi[ CCOL_SUM ], oi[ CCOL_SUMP2 ],
-                                           oi[ CCOL_NUM ]);
+              gal_statistics_std_from_sums(oi[ CCOL_SUM   ],
+                                           oi[ CCOL_SUMP2 ],
+                                           oi[ CCOL_NUM   ]);
             break;
 
           case UI_KEY_MEDIAN:
@@ -3085,9 +3364,9 @@ columns_fill(struct mkcatalog_passparams *pp)
             break;
 
           case UI_KEY_RIVERMEAN:
-            ((float *)colarr)[cind] = ( ci[ CCOL_RIV_NUM]
-                                        ? ci[ CCOL_RIV_SUM ]/ci[ CCOL_RIV_NUM]
-                                        : NAN );
+            ((float *)colarr)[cind]=(ci[ CCOL_RIV_NUM]
+                                     ? ci[ CCOL_RIV_SUM ]/ci[ CCOL_RIV_NUM]
+                                     : NAN );
             break;
 
           case UI_KEY_RIVERNUM:
@@ -3104,8 +3383,8 @@ columns_fill(struct mkcatalog_passparams *pp)
             break;
 
           case UI_KEY_SKYSTD:
-            ((float *)colarr)[cind] = sqrt( MKC_RATIO( ci[ CCOL_SUMVAR ],
-                                                       ci[ CCOL_NUMVAR ] ));
+            ((float *)colarr)[cind] = sqrt( MKC_RATIO(ci[ CCOL_SUMVAR ],
+                                                      ci[ CCOL_NUMVAR ]));
             break;
 
           case UI_KEY_SEMIMAJOR:
diff --git a/bin/mkcatalog/main.h b/bin/mkcatalog/main.h
index 146c99f7..3d002c9c 100644
--- a/bin/mkcatalog/main.h
+++ b/bin/mkcatalog/main.h
@@ -132,6 +132,17 @@ enum objectcols
     OCOL_C_GZ,           /* Geometric center of clumps in object Z.   */
     OCOL_C_SUMWHT,       /* Sum of positive image pixels for wht.     */
     OCOL_C_NUMWHT,       /* Num of positive image pixels for wht.     */
+    OCOL_NUMINSLICE,     /* Number of used values in slice.           */
+    OCOL_SUMINSLICE,     /* Sum of values in each slice of label.     */
+    OCOL_NUMALLINSLICE,  /* Number of labeled pixels in slice.        */
+    OCOL_SUMVARINSLICE,  /* Sum of variance (including values).       */
+    OCOL_SUMPROJINSLICE, /* Sum of projected area on each slice.      */
+    OCOL_NUMPROJINSLICE, /* Sum of projected area on each slice.      */
+    OCOL_SUMPROJVARINSLICE,/* Error in sum of projected area.         */
+    OCOL_NUMOTHERINSLICE,/* Area of other labels in projected area.   */
+    OCOL_SUMOTHERINSLICE,/* Sum of other objects in projected area.   */
+    OCOL_SUMOTHERVARINSLICE,/* Variance in sum of other in proj. area.*/
+    OCOL_NUMALLOTHERINSLICE,/* Area of other labels in projected area.*/
 
     OCOL_NUMCOLS,        /* SHOULD BE LAST: total number of columns.  */
   };
@@ -206,6 +217,27 @@ enum clumpcols
 
 
 
+/* IDs for vector columns, which need a separate allocation. The names
+   should be the same as the 'OCOL_', just the prefix differs. */
+enum vector_cols
+  {
+    VEC_NUMINSLICE,
+    VEC_SUMINSLICE,
+    VEC_NUMALLINSLICE,
+    VEC_SUMVARINSLICE,
+    VEC_SUMPROJINSLICE,
+    VEC_NUMPROJINSLICE,
+    VEC_SUMPROJVARINSLICE,
+    VEC_NUMOTHERINSLICE,
+    VEC_SUMOTHERINSLICE,
+    VEC_SUMOTHERVARINSLICE,
+    VEC_NUMALLOTHERINSLICE,
+
+    VEC_NUM,
+  };
+
+
+
 
 
 /* Main program parameters structure */
@@ -232,7 +264,6 @@ struct mkcatalogparams
   uint8_t         subtractsky;  /* ==1: subtract the Sky from values.   */
   float           sfmagnsigma;  /* Surface brightness multiple of sigma.*/
   float             sfmagarea;  /* Surface brightness area (arcsec^2).  */
-  uint8_t            spectrum;  /* Object spectrum for 3D datasets.     */
   uint8_t       inbetweenints;  /* Keep rows (integer ids) with no labs.*/
   double         sigmaclip[2];  /* Sigma clip column settings.          */
 
@@ -244,7 +275,6 @@ struct mkcatalogparams
   double       upsigmaclip[2];  /* Sigma clip to measure upper limit.   */
   float              upnsigma;  /* Multiple of sigma to define up-lim.  */
   int32_t       checkuplim[2];  /* Object & clump ID to check dist.     */
-
   gal_data_t         *fracmax;  /* Fractions to use in --fracsumarea.   */
   float     spatialresolution;  /* Error in area (used in SB error).    */
 
@@ -259,7 +289,7 @@ struct mkcatalogparams
   gal_data_t          *upmask;  /* Upper limit magnitude mask.          */
   float                medstd;  /* Median standard deviation value.     */
   float               cpscorr;  /* Counts-per-second correction.        */
-  int32_t            *outlabs;  /* Labels in output catalog (when necessary) */
+  int32_t            *outlabs;  /* Labels in output cat (when necessary)*/
   int32_t         *outlabsinv;  /* Inverse of the 'outlabs' array.      */
   size_t           numobjects;  /* Number of object labels in image.    */
   float               clumpsn;  /* Clump S/N threshold.                 */
@@ -282,8 +312,6 @@ struct mkcatalogparams
   uint8_t      uprangewarning;  /* A warning must be printed.           */
   size_t         *hostobjid_c;  /* To sort the clumps table by Obj.ID.  */
   size_t         *numclumps_c;  /* To sort the clumps table by Obj.ID.  */
-  gal_data_t   *specsliceinfo;  /* Slice information for spectra.       */
-  gal_data_t         *spectra;  /* Array of datasets containing spectra.*/
   double        pixelarcsecsq;  /* Area of input's pixels in arcsec^2.  */
 
   char        *usedvaluesfile;  /* Ptr to final name used for values.   */
diff --git a/bin/mkcatalog/mkcatalog.c b/bin/mkcatalog/mkcatalog.c
index 04b79913..f107f757 100644
--- a/bin/mkcatalog/mkcatalog.c
+++ b/bin/mkcatalog/mkcatalog.c
@@ -89,59 +89,120 @@ mkcatalog_clump_starting_index(struct mkcatalog_passparams 
*pp)
 
 
 
-
-/* Each thread will call this function once. It will go over all the
-   objects that are assigned to it. */
-static void *
-mkcatalog_single_object(void *in_prm)
+/* Vector allocation (short name is used since it is repeated a lot). */
+static void
+mkcatalog_vec_alloc(struct mkcatalog_passparams *pp, size_t onum,
+                    size_t vnum, uint8_t type)
 {
-  struct gal_threads_params *tprm=(struct gal_threads_params *)in_prm;
-  struct mkcatalogparams *p=(struct mkcatalogparams *)(tprm->params);
-  size_t ndim=p->objects->ndim;
+  if( pp->p->oiflag[ onum ] )
+    gal_data_initialize(&pp->vector[vnum], 0, type, 1,
+                        &(pp->p->objects->dsize[0]), NULL, 1,
+                        pp->p->cp.minmapsize, pp->p->cp.quietmmap,
+                        NULL, NULL, NULL);
+}
+
 
-  size_t i;
-  uint8_t *oif=p->oiflag;
-  struct mkcatalog_passparams pp;
 
 
+
+/* Allocate all the necessary space. */
+static void
+mkcatalog_single_object_init(struct mkcatalogparams *p,
+                             struct mkcatalog_passparams *pp)
+{
+  uint8_t *oif=p->oiflag;
+  size_t ndim=p->objects->ndim;
+  uint8_t i32=GAL_TYPE_INT32, f64=GAL_TYPE_FLOAT64; /* For short lines.*/
+
   /* Initialize the mkcatalog_passparams elements. */
-  pp.p               = p;
-  pp.clumpstartindex = 0;
-  pp.rng             = p->rng ? gsl_rng_clone(p->rng) : NULL;
-  pp.oi              = gal_pointer_allocate(GAL_TYPE_FLOAT64, OCOL_NUMCOLS,
-                                            0, __func__, "pp.oi");
+  pp->p               = p;
+  pp->clumpstartindex = 0;
+  pp->rng             = p->rng ? gsl_rng_clone(p->rng) : NULL;
+  pp->oi              = gal_pointer_allocate(GAL_TYPE_FLOAT64,
+                                             OCOL_NUMCOLS, 0, __func__,
+                                             "pp->oi");
 
   /* If we have second order measurements, allocate the array keeping the
      temporary shift values for each object of this thread. Note that the
      clumps catalog (if requested), will have the same measurements, so its
      just enough to check the objects. */
-  pp.shift = ( ( oif[    OCOL_GXX ]
-                 || oif[ OCOL_GYY ]
-                 || oif[ OCOL_GXY ]
-                 || oif[ OCOL_VXX ]
-                 || oif[ OCOL_VYY ]
-                 || oif[ OCOL_VXY ] )
-               ? gal_pointer_allocate(GAL_TYPE_SIZE_T, ndim, 0, __func__,
-                                       "pp.shift")
-               : NULL );
+  pp->shift = ( (    oif[ OCOL_GXX ]
+                  || oif[ OCOL_GYY ]
+                  || oif[ OCOL_GXY ]
+                  || oif[ OCOL_VXX ]
+                  || oif[ OCOL_VYY ]
+                  || oif[ OCOL_VXY ] )
+                ? gal_pointer_allocate(GAL_TYPE_SIZE_T, ndim, 0, __func__,
+                                       "pp->shift")
+                : NULL );
 
   /* If we have upper-limit mode, then allocate the container to keep the
      values to calculate the standard deviation. */
   if(p->upperlimit)
     {
       /* Allocate the space to keep the upper-limit values. */
-      pp.up_vals = gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1, &p->upnum,
-                                  NULL, 0, p->cp.minmapsize, p->cp.quietmmap,
-                                  NULL, NULL, NULL);
+      pp->up_vals = gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1, &p->upnum,
+                                  NULL, 0, p->cp.minmapsize,
+                                  p->cp.quietmmap, NULL, NULL, NULL);
 
       /* Set the blank checked flag to 1. By definition, this dataset won't
          have any blank values. Also 'flag' is initialized to '0'. So we
          just have to set the checked flag ('GAL_DATA_FLAG_BLANK_CH') to
          one to inform later steps that there are no blank values. */
-      pp.up_vals->flag |= GAL_DATA_FLAG_BLANK_CH;
+      pp->up_vals->flag |= GAL_DATA_FLAG_BLANK_CH;
     }
   else
-    pp.up_vals=NULL;
+    pp->up_vals=NULL;
+
+  /* If any vector measurements are necessary, do the necessary
+     allocations: first the general array, to keep all that are necessary,
+     then the individual ones. */
+  pp->vector = ( (    oif[ OCOL_NUMINSLICE         ]
+                   || oif[ OCOL_SUMINSLICE         ]
+                   || oif[ OCOL_NUMALLINSLICE      ]
+                   || oif[ OCOL_SUMVARINSLICE      ]
+                   || oif[ OCOL_SUMPROJINSLICE     ]
+                   || oif[ OCOL_NUMPROJINSLICE     ]
+                   || oif[ OCOL_SUMPROJVARINSLICE  ]
+                   || oif[ OCOL_NUMOTHERINSLICE    ]
+                   || oif[ OCOL_SUMOTHERINSLICE    ]
+                   || oif[ OCOL_SUMOTHERVARINSLICE ]
+                   || oif[ OCOL_NUMALLOTHERINSLICE ] )
+                 ? gal_data_array_calloc(VEC_NUM)
+                 : NULL );
+  mkcatalog_vec_alloc(pp, OCOL_NUMINSLICE,      VEC_NUMINSLICE,     i32);
+  mkcatalog_vec_alloc(pp, OCOL_NUMALLINSLICE,   VEC_NUMALLINSLICE,  i32);
+  mkcatalog_vec_alloc(pp, OCOL_NUMPROJINSLICE,  VEC_NUMPROJINSLICE, i32);
+  mkcatalog_vec_alloc(pp, OCOL_NUMOTHERINSLICE, VEC_NUMOTHERINSLICE,i32);
+  mkcatalog_vec_alloc(pp, OCOL_SUMINSLICE,      VEC_SUMINSLICE,     f64);
+  mkcatalog_vec_alloc(pp, OCOL_SUMVARINSLICE,   VEC_SUMVARINSLICE,  f64);
+  mkcatalog_vec_alloc(pp, OCOL_SUMPROJINSLICE,  VEC_SUMPROJINSLICE, f64);
+  mkcatalog_vec_alloc(pp, OCOL_SUMOTHERINSLICE, VEC_SUMOTHERINSLICE,f64);
+  mkcatalog_vec_alloc(pp, OCOL_SUMOTHERVARINSLICE, VEC_SUMOTHERVARINSLICE,
+                      f64);
+  mkcatalog_vec_alloc(pp, OCOL_NUMALLOTHERINSLICE, VEC_NUMALLOTHERINSLICE,
+                      i32);
+  mkcatalog_vec_alloc(pp, OCOL_SUMPROJVARINSLICE, VEC_SUMPROJVARINSLICE,
+                      f64);
+}
+
+
+
+
+
+/* Each thread will call this function once. It will go over all the
+   objects that are assigned to it. */
+static void *
+mkcatalog_single_object(void *in_prm)
+{
+  struct gal_threads_params *tprm=(struct gal_threads_params *)in_prm;
+  struct mkcatalogparams *p=(struct mkcatalogparams *)(tprm->params);
+
+  size_t i;
+  struct mkcatalog_passparams pp;
+
+  /* Initialize and allocate all the necessary values. */
+  mkcatalog_single_object_init(p, &pp);
 
   /* Fill the desired columns for all the objects given to this thread. */
   for(i=0; tprm->indexs[i]!=GAL_BLANK_SIZE_T; ++i)
@@ -153,7 +214,6 @@ mkcatalog_single_object(void *in_prm)
                       ? p->outlabs[ tprm->indexs[i] ]
                       : tprm->indexs[i] + 1 );
       pp.tile     = &p->tiles[   tprm->indexs[i] ];
-      pp.spectrum = &p->spectra[ tprm->indexs[i] ];
 
       /* Initialize the parameters for this object/tile. */
       parse_initialize(&pp);
@@ -181,16 +241,16 @@ mkcatalog_single_object(void *in_prm)
 
       /* If an order-based calculation is requested, another pass is
          necessary. */
-      if( p->oiflag[ OCOL_MEDIAN ]
-          || p->oiflag[ OCOL_MAXIMUM ]
-          || p->oiflag[ OCOL_HALFMAXSUM ]
-          || p->oiflag[ OCOL_HALFMAXNUM ]
-          || p->oiflag[ OCOL_HALFSUMNUM ]
-          || p->oiflag[ OCOL_SIGCLIPNUM ]
-          || p->oiflag[ OCOL_SIGCLIPSTD ]
-          || p->oiflag[ OCOL_SIGCLIPMEAN ]
-          || p->oiflag[ OCOL_FRACMAX1NUM ]
-          || p->oiflag[ OCOL_FRACMAX2NUM ]
+      if(    p->oiflag[ OCOL_MEDIAN        ]
+          || p->oiflag[ OCOL_MAXIMUM       ]
+          || p->oiflag[ OCOL_HALFMAXSUM    ]
+          || p->oiflag[ OCOL_HALFMAXNUM    ]
+          || p->oiflag[ OCOL_HALFSUMNUM    ]
+          || p->oiflag[ OCOL_SIGCLIPNUM    ]
+          || p->oiflag[ OCOL_SIGCLIPSTD    ]
+          || p->oiflag[ OCOL_SIGCLIPMEAN   ]
+          || p->oiflag[ OCOL_FRACMAX1NUM   ]
+          || p->oiflag[ OCOL_FRACMAX2NUM   ]
           || p->oiflag[ OCOL_SIGCLIPMEDIAN ])
         parse_order_based(&pp);
 
@@ -209,6 +269,7 @@ mkcatalog_single_object(void *in_prm)
   free(pp.shift);
   gal_data_free(pp.up_vals);
   if(pp.rng) gsl_rng_free(pp.rng);
+  gal_data_array_free(pp.vector, VEC_NUM, 1);
 
   /* Wait until all the threads finish and return. */
   if(tprm->b) pthread_barrier_wait(tprm->b);
@@ -394,8 +455,8 @@ mkcatalog_outputs_keys_infiles(struct mkcatalogparams *p,
       if(p->sky->size==1)
         mkcatalog_outputs_keys_numeric(keylist, p->sky->array,
                                        p->sky->type, "INSKYVAL",
-                                       "Value of Sky used (a single number).",
-                                       NULL);
+                                       "Value of Sky used (a single "
+                                       "number).", NULL);
       else
         {
           gal_fits_key_write_filename("INSKY", p->usedskyfile, keylist, 0,
@@ -488,7 +549,8 @@ mkcatalog_outputs_keys(struct mkcatalogparams *p, int o0c1)
                                    "mag");
 
   /* Add the title for the keywords. */
-  gal_fits_key_list_title_add_end(&keylist, "Surface brightness limit (SBL)", 
0);
+  gal_fits_key_list_title_add_end(&keylist, "Surface brightness limit "
+                                  "(SBL)", 0);
 
   /* Print surface brightness limit. */
   if( !isnan(p->medstd) && !isnan(p->sfmagnsigma) )
@@ -496,12 +558,12 @@ mkcatalog_outputs_keys(struct mkcatalogparams *p, int 
o0c1)
       /* Used noise value (per pixel) and multiple of sigma. */
       mkcatalog_outputs_keys_numeric(&keylist, &p->medstd,
                                      GAL_TYPE_FLOAT32, "SBLSTD",
-                                     "Pixel STD for surface brightness limit.",
-                                     NULL);
+                                     "Pixel STD for surface brightness "
+                                     "limit.", NULL);
       mkcatalog_outputs_keys_numeric(&keylist, &p->sfmagnsigma,
                                      GAL_TYPE_FLOAT32, "SBLNSIG",
-                                     "Sigma multiple for surface brightness "
-                                     "limit.", NULL);
+                                     "Sigma multiple for surface "
+                                     "brightness limit.", NULL);
 
       /* Only print magnitudes if a zeropoint is given. */
       if( !isnan(p->zeropoint) )
@@ -511,8 +573,8 @@ mkcatalog_outputs_keys(struct mkcatalogparams *p, int o0c1)
                                          p->zeropoint);
           mkcatalog_outputs_keys_numeric(&keylist, &fvalue,
                                          GAL_TYPE_FLOAT32, "SBLMAGPX",
-                                         "Surface brightness limit per pixel.",
-                                         "mag/pix");
+                                         "Surface brightness limit per "
+                                         "pixel.", "mag/pix");
 
           /* Only print the SBL in fixed area if a WCS is present and a
              pixel area could be deduced. */
@@ -532,7 +594,8 @@ mkcatalog_outputs_keys(struct mkcatalogparams *p, int o0c1)
                                              p->zeropoint);
               mkcatalog_outputs_keys_numeric(&keylist, &fvalue,
                                              GAL_TYPE_FLOAT32, "SBLMAG",
-                                             "Surf. bright. limit in SBLAREA.",
+                                             "Surf. bright. limit in "
+                                             "SBLAREA.",
                                              "mag/arcsec^2");
             }
           else
@@ -646,8 +709,6 @@ sort_clumps_by_objid(struct mkcatalogparams *p)
 static void
 mkcatalog_write_outputs(struct mkcatalogparams *p)
 {
-  size_t i, scounter;
-  char str[200], *fname;
   gal_fits_list_key_t *keylist;
   gal_list_str_t *comments=NULL;
   int outisfits=gal_fits_name_is_fits(p->objectsout);
@@ -684,46 +745,6 @@ mkcatalog_write_outputs(struct mkcatalogparams *p)
         }
     }
 
-  /* Spectra. */
-  if(p->spectra)
-    {
-      /* Inform the user (Writing many FITS extensions can take
-         long). */
-      if(p->objectcols && outisfits)
-        printf("  - Catalog(s) complete, writing spectra.\n");
-
-      /* Start counting and writing the files. Note that due to some
-         conditions (for example in debugging), a 'p->spectra[i]' may not
-         actually contain any data. So we'll also count the number of
-         spectra that are written. */
-      scounter=0;
-      for(i=0;i<p->numobjects;++i)
-        if(p->spectra[i].ndim>0)
-          {
-            /* Increment the written spectra-counter. */
-            ++scounter;
-
-            /* Write the spectra based on the requested format. */
-            if(outisfits)
-              {
-                /* Write the table. */
-                sprintf(str, "SPECTRUM_%zu", i+1);
-                gal_table_write(&p->spectra[i], NULL, NULL,
-                                GAL_TABLE_FORMAT_BFITS,
-                                p->objectsout, str, 0);
-              }
-            else
-              {
-                sprintf(str, "-spec-%zu.txt", i+1);
-                fname=gal_checkset_automatic_output(&p->cp, p->objectsout,
-                                                    str);
-                gal_table_write(&p->spectra[i], NULL, NULL, 
GAL_TABLE_FORMAT_TXT,
-                                fname, NULL, 0);
-                free(fname);
-              }
-          }
-    }
-
   /* Configuration information. */
   if(outisfits)
     {
@@ -735,36 +756,16 @@ mkcatalog_write_outputs(struct mkcatalogparams *p)
 
 
   /* Inform the user */
-  if(!p->cp.quiet)
+  if(!p->cp.quiet && p->objectcols)
     {
-      if(p->objectcols)
+      if(p->clumpsout && strcmp(p->clumpsout,p->objectsout))
         {
-          if(p->clumpsout && strcmp(p->clumpsout,p->objectsout))
-            {
-              printf("  - Output objects catalog: %s\n", p->objectsout);
-              if(p->clumps)
-                printf("  - Output clumps catalog: %s\n", p->clumpsout);
-            }
-          else
-            printf("  - Catalog written to %s\n", p->objectsout);
-
-        }
-
-      if(p->spectra)
-        {
-          if(outisfits)
-            {
-              if(p->objectcols)
-                printf("  - Spectra in %zu extensions named 'SPECTRUM_NN'.\n",
-                       p->numobjects);
-              else
-                printf("  - Output: %s (Spectra in %zu extensions named "
-                       "'SPECTRUM_NN').\n)", p->objectsout, p->numobjects);
-            }
-          else
-            printf("  - Spectra in %zu files with '-spec-NN.txt' suffix.\n",
-                   p->numobjects);
+          printf("  - Output objects catalog: %s\n", p->objectsout);
+          if(p->clumps)
+            printf("  - Output clumps catalog: %s\n", p->clumpsout);
         }
+      else
+        printf("  - Catalog written to %s\n", p->objectsout);
     }
 }
 
diff --git a/bin/mkcatalog/mkcatalog.h b/bin/mkcatalog/mkcatalog.h
index d2604bab..c9c6a845 100644
--- a/bin/mkcatalog/mkcatalog.h
+++ b/bin/mkcatalog/mkcatalog.h
@@ -23,6 +23,11 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #ifndef MKCATALOG_H
 #define MKCATALOG_H
 
+
+
+
+
+/* Main structure for parsing individual objects. */
 struct mkcatalog_passparams
 {
   struct mkcatalogparams *p;    /* Main MakeCatalog paramers.           */
@@ -41,7 +46,7 @@ struct mkcatalog_passparams
   gsl_rng              *rng;    /* Random number generator.             */
   size_t    clumpstartindex;    /* Clump starting row in final catalog. */
   gal_data_t       *up_vals;    /* Container for upper-limit values.    */
-  gal_data_t      *spectrum;    /* Spectrum of each object.             */
+  gal_data_t        *vector;    /* Array of datasets for raw vectors.   */
 };
 
 void
diff --git a/bin/mkcatalog/parse.c b/bin/mkcatalog/parse.c
index 09ffa876..63bc4fdc 100644
--- a/bin/mkcatalog/parse.c
+++ b/bin/mkcatalog/parse.c
@@ -44,6 +44,10 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
+
+
+
+
 /* Both passes are going to need their starting pointers set, so we'll do
    that here. */
 void
@@ -51,16 +55,22 @@ parse_initialize(struct mkcatalog_passparams *pp)
 {
   struct mkcatalogparams *p=pp->p;
 
+  gal_data_t *vec;
   size_t i, ndim=p->objects->ndim;
   size_t *start_end=pp->start_end_inc;
 
   /* Initialize the number of clumps in this object. */
   pp->clumpsinobj=0;
 
-
   /* Initialize the intermediate values to zero. */
   memset(pp->oi, 0, OCOL_NUMCOLS * sizeof *pp->oi);
-
+  if(pp->vector)
+    for(i=0;i<VEC_NUM;++i)
+      {
+        vec=&(pp->vector[i]);
+        if(pp->vector[i].array)
+          memset(vec->array, 0, vec->size*gal_type_sizeof(vec->type));
+      }
 
   /* Set the shifts in every dimension to avoid round-off errors in large
      numbers for the non-linear calculations. We are using the first pixel
@@ -72,9 +82,9 @@ parse_initialize(struct mkcatalog_passparams *pp)
   if(pp->shift)
     {
       /* Get the coordinates of the tile's starting point. */
-      gal_dimension_index_to_coord( ( (float *)(pp->tile->array)
-                                      - (float *)(pp->tile->block->array) ),
-                                    ndim, p->objects->dsize, pp->shift);
+      gal_dimension_index_to_coord(( (float *)(pp->tile->array)
+                                     - (float *)(pp->tile->block->array) ),
+                                   ndim, p->objects->dsize, pp->shift);
 
       /* Change their counting to start from 1, not zero, since we will be
          using them as FITS coordinates. */
@@ -107,14 +117,14 @@ parse_initialize(struct mkcatalog_passparams *pp)
 
 
 static size_t *
-parse_spectrum_pepare(struct mkcatalog_passparams *pp, size_t *start_end_inc,
-                      int32_t **st_o, float **st_v, float **st_std)
+parse_vector_dim3_prepare(struct mkcatalog_passparams *pp,
+                          size_t *start_end_inc, int32_t **st_o,
+                          float **st_v, float **st_std)
 {
   size_t *tsize;
   gal_data_t *spectile;
   struct mkcatalogparams *p=pp->p;
-  size_t coord[3], minmax[6], numslices=p->objects->dsize[0];
-  gal_data_t *area, *sum, *esum, *proj, *eproj, *oarea, *osum, *oesum;
+  size_t coord[3], minmax[6];
 
   /* Get the coordinates of the spectral tile's starting element, then make
      the tile. */
@@ -122,10 +132,10 @@ parse_spectrum_pepare(struct mkcatalog_passparams *pp, 
size_t *start_end_inc,
                                                        pp->tile->array,
                                                        p->objects->type),
                                p->objects->ndim, p->objects->dsize, coord);
-  minmax[0]=0;                                   /* Changed to first slice.*/
+  minmax[0]=0;                             /* Changed to first slice.*/
   minmax[1]=coord[1];
   minmax[2]=coord[2];
-  minmax[3]=p->objects->dsize[0]-1;              /* Changed to last slice. */
+  minmax[3]=p->objects->dsize[0]-1;        /* Changed to last slice. */
   minmax[4]=coord[1]+pp->tile->dsize[1]-1;
   minmax[5]=coord[2]+pp->tile->dsize[2]-1;
   spectile=gal_tile_series_from_minmax(p->objects, minmax, 1);
@@ -140,54 +150,6 @@ parse_spectrum_pepare(struct mkcatalog_passparams *pp, 
size_t *start_end_inc,
                      : NULL )
                  : NULL );
 
-  /* Allocate the columns. */
-  area  = gal_data_alloc(NULL, GAL_TYPE_UINT32, 1, &numslices, NULL, 1,
-                         p->cp.minmapsize, p->cp.quietmmap, "AREA",
-                         "counter", "Area of object in a slice");
-  sum   = gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &numslices, NULL, 1,
-                         p->cp.minmapsize, p->cp.quietmmap, "SUM",
-                         p->values->unit, "Sum of values with this label.");
-  esum  = gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &numslices, NULL, 1,
-                         p->cp.minmapsize, p->cp.quietmmap, "SUM_ERR",
-                         p->values->unit, "Error in SUM column.");
-  proj  = gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &numslices, NULL, 1,
-                         p->cp.minmapsize, p->cp.quietmmap, "SUM_PROJECTED",
-                         p->values->unit, "Sum of full projected 2D area on "
-                         "a slice.");
-  eproj = gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &numslices, NULL, 1,
-                         p->cp.minmapsize, p->cp.quietmmap, 
"SUM_PROJECTED_ERR",
-                         p->values->unit, "Error in SUM_PROJECTED column.");
-  oarea = gal_data_alloc(NULL, GAL_TYPE_UINT32, 1, &numslices, NULL, 1,
-                         p->cp.minmapsize, p->cp.quietmmap, "AREA_OTHER",
-                         "counter", "Area covered by other labels in a 
slice.");
-  osum  = gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &numslices, NULL, 1,
-                         p->cp.minmapsize, p->cp.quietmmap, "SUM_OTHER",
-                         p->values->unit, "Sum of values in other labels on "
-                         "a slice.");
-  oesum = gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &numslices, NULL, 1,
-                         p->cp.minmapsize, p->cp.quietmmap, "SUM_OTHER_ERR",
-                         p->values->unit, "Error in SUM_OTHER column.");
-
-  /* Fill up the contents of the first element (note that the first
-     'gal_data_t' is actually in an array, so the skeleton is already
-     allocated, we just have to allocate its contents. */
-  gal_data_initialize(pp->spectrum, NULL, p->specsliceinfo->type, 1,
-                      &numslices, NULL, 0, p->cp.minmapsize,
-                      p->cp.quietmmap, NULL, NULL, NULL);
-  gal_data_copy_to_allocated(p->specsliceinfo, pp->spectrum);
-  pp->spectrum->next=gal_data_copy(p->specsliceinfo->next);
-
-
-  /* Add all the other columns in the final spectrum table. */
-  pp->spectrum->next->next                       = area;
-  area->next                                     = sum;
-  area->next->next                               = esum;
-  area->next->next->next                         = proj;
-  area->next->next->next->next                   = eproj;
-  area->next->next->next->next->next             = oarea;
-  area->next->next->next->next->next->next       = osum;
-  area->next->next->next->next->next->next->next = oesum;
-
   /* Clean up and return. */
   tsize=spectile->dsize;
   spectile->dsize=NULL;
@@ -199,134 +161,49 @@ parse_spectrum_pepare(struct mkcatalog_passparams *pp, 
size_t *start_end_inc,
 
 
 
-/* Since spectra will be a large table for many objects, it is very
-   important to not consume too much space in for columns that don't need
-   it. This function will check the integer columns and if they are smaller
-   than the maximum values of smaller types, */
-static void
-parse_spectrum_uint32_to_best_type(gal_data_t **input)
-{
-  gal_data_t *tmp=gal_statistics_maximum(*input);
-
-  /* If maximum is smaller than UINT8_MAX, convert it to uint8_t */
-  if( *(uint32_t *)(tmp->array) < UINT8_MAX )
-    *input = gal_data_copy_to_new_type_free(*input, GAL_TYPE_UINT8);
-
-  /* otherwise, if it is smaller than UINT16_MAX, convert it to uint16_t */
-  else if( *(uint32_t *)(tmp->array)      < UINT16_MAX )
-    *input = gal_data_copy_to_new_type_free(*input, GAL_TYPE_UINT16);
-
-  /* Clean up. */
-  gal_data_free(tmp);
-}
-
-
-
-
-
-static void
-parse_spectrum_end(struct mkcatalog_passparams *pp, gal_data_t *xybin)
-{
-  size_t i;
-  double *searr, *pearr, *osearr;
-  struct mkcatalogparams *p=pp->p;
-
-  /* The datasets and their pointers. */
-  gal_data_t *area  = pp->spectrum->next->next;
-  gal_data_t *sum   = area->next;
-  gal_data_t *esum  = area->next->next;
-  gal_data_t *proj  = area->next->next->next;
-  gal_data_t *eproj = area->next->next->next->next;
-  gal_data_t *oarea = area->next->next->next->next->next;
-  gal_data_t *osum  = area->next->next->next->next->next->next;
-  gal_data_t *oesum = area->next->next->next->next->next->next->next;
-
-  /* Apply corrections to the columns that need it. */
-  searr  = esum->array;
-  pearr  = eproj->array;
-  osearr = oesum->array;
-  for(i=0; i<p->objects->dsize[0]; ++i)
-    {
-      searr[i]  = sqrt( searr[i]  );
-      pearr[i]  = sqrt( pearr[i]  );
-      osearr[i] = sqrt( osearr[i] );
-    }
-
-  /* Convert the 'double' type columns to 'float'. The extra precision of
-     'double' was necessary when we were summing values in each slice. But
-     afterwards, it is not necessary at all (the measurement error is much
-     larger than a double-precision floating point number (15
-     decimals). But the extra space gained (double) is very useful in not
-     wasting too much memory and hard-disk space or online transfer time.*/
-  sum   = gal_data_copy_to_new_type_free(sum,   GAL_TYPE_FLOAT32);
-  esum  = gal_data_copy_to_new_type_free(esum,  GAL_TYPE_FLOAT32);
-  proj  = gal_data_copy_to_new_type_free(proj,  GAL_TYPE_FLOAT32);
-  eproj = gal_data_copy_to_new_type_free(eproj, GAL_TYPE_FLOAT32);
-  osum  = gal_data_copy_to_new_type_free(osum,  GAL_TYPE_FLOAT32);
-  oesum = gal_data_copy_to_new_type_free(oesum, GAL_TYPE_FLOAT32);
-
-  /* For the two area columns, find their maximum value and convert the
-     dataset to the smallest type that can hold them. */
-  parse_spectrum_uint32_to_best_type(&area);
-  parse_spectrum_uint32_to_best_type(&oarea);
-
-  /* List the datasets and write them into the pointer for this object
-     (exact copy of the statement in 'parse_spectrum_pepare'). */
-  pp->spectrum->next->next                       = area;
-  area->next                                     = sum;
-  area->next->next                               = esum;
-  area->next->next->next                         = proj;
-  area->next->next->next->next                   = eproj;
-  area->next->next->next->next->next             = oarea;
-  area->next->next->next->next->next->next       = osum;
-  area->next->next->next->next->next->next->next = oesum;
-}
-
-
-
-
-/* Each spectrum is a multi-column table (note that the slice counter and
-   wavelength are written in the end):
-
-     Column 3:  Number of object pixels.
-     Column 4:  Sum of object pixel values.
-     Column 5:  Error in Column 2.
-     Column 6:  Sum over all 2D projection over whole specturm.
-     Column 7:  Error in Column 4.
-     Column 8:  Area of other labels in this slice.
-     Column 9:  Flux by other objects in projected area.
-     Column 10: Error in Column 9.
- */
 static void
-parse_spectrum(struct mkcatalog_passparams *pp, gal_data_t *xybin)
+parse_vector_dim3(struct mkcatalog_passparams *pp, gal_data_t *xybin)
 {
   struct mkcatalogparams *p=pp->p;
 
-  gal_data_t *area;
-  float *st_v, *st_std;
-  uint32_t *narr, *oarr;
-  size_t nproj=0, *tsize, start_end_inc[2];
+  double var;
+  int needsvar;
+  gal_data_t *vector=pp->vector;
+  float *std=p->std?p->std->array:NULL;
+  size_t c[3], *dsize=p->objects->dsize;
+  size_t sind=0, pind=0, num_increment=1;
   uint8_t *xybinarr = xybin ? xybin->array : NULL;
-  int32_t *O, *OO, *st_o, *objarr=p->objects->array;
-  size_t tid, *dsize=p->objects->dsize, num_increment=1;
-  double var, *sarr, *searr, *parr, *pearr, *osarr, *osearr;
-  size_t increment=0, pind=0, sind=0, ndim=p->objects->ndim, c[3];
-  float st, sval, *V=NULL, *ST=NULL, *std=p->std?p->std->array:NULL;
-
-  /* Prepare the columns to write in. */
-  tsize  = parse_spectrum_pepare(pp, start_end_inc, &st_o, &st_v, &st_std);
-  area   = pp->spectrum->next->next;
-  narr   = area->array;
-  sarr   = area->next->array;
-  searr  = area->next->next->array;
-  parr   = area->next->next->next->array;
-  pearr  = area->next->next->next->next->array;
-  oarr   = area->next->next->next->next->next->array;
-  osarr  = area->next->next->next->next->next->next->array;
-  osearr = area->next->next->next->next->next->next->next->array;
-
-  /* If tile-id isn't necessary, set 'tid' to a blank value. */
-  tid = (p->std && p->std->size>1 && st_std == NULL) ? 0 : GAL_BLANK_SIZE_T;
+  float st, sval, *st_v, *st_std, *V=NULL, *ST=NULL;
+  int32_t *st_o, *O, *OO, *objarr=p->objects->array;
+  size_t tid, *tsize, increment=0, start_end_inc[2], ndim=p->objects->ndim;
+
+  /* Pointers to necessary temporary arrays (they will be NULL if they are
+     not necessary for the user). */
+  double  *suminslice         = vector[ VEC_SUMINSLICE         ].array;
+  double  *sumvarinslice      = vector[ VEC_SUMVARINSLICE      ].array;
+  double  *sumprojinslice     = vector[ VEC_SUMPROJINSLICE     ].array;
+  double  *sumprojvarinslice  = vector[ VEC_SUMPROJVARINSLICE  ].array;
+  double  *sumotherinslice    = vector[ VEC_SUMOTHERINSLICE    ].array;
+  double  *sumothervarinslice = vector[ VEC_SUMOTHERVARINSLICE ].array;
+  int32_t *numinslice         = vector[ VEC_NUMINSLICE         ].array;
+  int32_t *numallinslice      = vector[ VEC_NUMALLINSLICE      ].array;
+  int32_t *numprojinslice     = vector[ VEC_NUMPROJINSLICE     ].array;
+  int32_t *numotherinslice    = vector[ VEC_NUMOTHERINSLICE    ].array;
+  int32_t *numallotherinslice = vector[ VEC_NUMALLOTHERINSLICE ].array;
+
+  /* Prepare the parsing information. Also, if tile-id isn't necessary, set
+     'tid' to a blank value to cause a crash with a mistake. */
+  tsize=parse_vector_dim3_prepare(pp, start_end_inc, &st_o, &st_v, &st_std);
+  tid = (p->std && p->std->size>1 && st_std == NULL)?0:GAL_BLANK_SIZE_T;
+
+  /* Check if we need the variance. */
+  needsvar = ( sumvarinslice || sumprojvarinslice || sumothervarinslice
+               ? 1 : 0 );
+  if(needsvar && p->std==NULL)
+    error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at '%s' to fix "
+          "the problem. The requested column requires a variance "
+          "estimation, but the input standard deviation image is NULL",
+          __func__, PACKAGE_BUGREPORT);
 
   /* Parse each contiguous patch of memory covered by this object. */
   while( start_end_inc[0] + increment <= start_end_inc[1] )
@@ -337,21 +214,27 @@ parse_spectrum(struct mkcatalog_passparams *pp, 
gal_data_t *xybin)
       if( p->std && st_std ) ST = st_std + increment;
       OO = ( O = st_o + increment ) + pp->tile->dsize[ndim-1];
 
-      /* Parse the tile. */
+      /* Parse the "tile" for this label. */
       do
         {
-          /* Only continue if this voxel is useful: it isn't NaN, or its
-             covered by the projected area or object's label. */
-          if( !isnan(*V) && (xybin && xybinarr[pind]==2) )
+          /* Counters that don't depend on value. */
+          if(numallinslice) ++numallinslice[sind];
+          if(*O!=pp->object && numallotherinslice)
+            ++numallotherinslice[sind];
+
+          /* Only continue if this voxel is on a label and is useful (it
+             isn't NaN). */
+          if( !isnan(*V) )
             {
-              /* Get the error in measuing this pixel's flux. */
-              if(p->std)
+              /* Variance of this voxel (if necessary) */
+              if(needsvar)
                 {
                   /* If the standard deviation is given on a tile
                      structure, estimate the tile ID. */
                   if(tid != GAL_BLANK_SIZE_T)
                     {
-                      gal_dimension_index_to_coord(O-objarr, ndim, dsize, c);
+                      gal_dimension_index_to_coord(O-objarr, ndim, dsize,
+                                                   c);
                       tid=gal_tile_full_id_from_coord(&p->cp.tl, c);
                     }
 
@@ -364,34 +247,35 @@ parse_spectrum(struct mkcatalog_passparams *pp, 
gal_data_t *xybin)
                 }
               else var = NAN;
 
+              /* Only on this label. */
+              if(*O==pp->object) /* We are on this object. */
+                {
+                  if(numinslice)  ++numinslice[sind];
+                  if(suminslice)    suminslice[sind]    += *V;
+                  if(sumvarinslice) sumvarinslice[sind] += var;
+                }
 
-              /* Projected spectra: see if we have a value of '2' in the
-                 'xybin' array (showing that there is atleast one non-blank
-                 element there over the whole spectrum.  */
-              ++nproj;
-              parr [ sind ] += *V;
-              pearr[ sind ] += var;
-
-              /* Calculate the number of labeled/detected pixels that
-                 don't belong to this object. */
-              if(*O>0)
+              /* Projected measurements: see if we have a value of '2' in
+                 the 'xybin' array (showing that there is atleast one
+                 non-blank element there over the whole spectrum.  */
+              if(xybin && xybinarr[pind]==2)
                 {
-                  if(*O==pp->object)
-                    {
-                      ++narr[ sind ];
-                      sarr  [ sind ] += *V;
-                      searr [ sind ] += var;
-                    }
-                  else
+                  /* Raw measurements over the projection. */
+                  if(numprojinslice)  ++numprojinslice[sind];
+                  if(sumprojinslice)    sumprojinslice[sind]    += *V;
+                  if(sumprojvarinslice) sumprojvarinslice[sind] += var;
+
+                  /* Other labels over this projection. */
+                  if(*O!=pp->object)
                     {
-                      ++oarr [ sind ];
-                      osarr  [ sind ] += *V;
-                      osearr [ sind ] += var;
+                      if(numotherinslice) ++numotherinslice[sind];
+                      if(sumotherinslice)   sumotherinslice[sind]   += *V;
+                      if(sumothervarinslice)sumothervarinslice[sind]+=var;
                     }
                 }
             }
 
-          /* Increment the pointers. */
+          /* Values used, increment the pointrs for next voxel. */
           if( xybin            ) ++pind;
           if( p->values        ) ++V;
           if( p->std && st_std ) ++ST;
@@ -402,35 +286,35 @@ parse_spectrum(struct mkcatalog_passparams *pp, 
gal_data_t *xybin)
       increment += ( gal_tile_block_increment(p->objects, tsize,
                                               num_increment++, NULL) );
 
-      /* Increment the slice number, 'sind', and reset the projection (2D)
-         index 'pind' if we have just finished parsing a slice. */
+      /* If we have reached the end of one slice, increment the slice index
+         ('sind'), and reset the projection (2D) index 'pind' if we have
+         just finished parsing a slice. Also, set all the sum values
+         that didn't have any measurement to NAN. */
       if( (num_increment-1)%pp->tile->dsize[1]==0 )
         {
           /* If there was no measurement, set NaN for the values and their
              errors (zero is meaningful). */
-          if( nproj      ==0 ) parr[sind]  = pearr[sind]  = NAN;
-          if( narr[sind] ==0 ) sarr[sind]  = searr[sind]  = NAN;
-          if( oarr[sind] ==0 ) osarr[sind] = osearr[sind] = NAN;
-
-          nproj=pind=0;
+          if(numinslice && numinslice[sind]==0)
+            suminslice[sind]=NAN;
+          if(numprojinslice && numprojinslice[sind]==0)
+            sumprojinslice[sind]=NAN;
+          if(numotherinslice && numotherinslice[sind]==0)
+            sumotherinslice[sind]=NAN;
+
+          /* Set the projection-index to zero (since it counts on each
+             slice), and increment the slice-index. */
+          pind=0;
           ++sind;
         }
     }
 
-  /* Finalize the spectrum generation and clean up. */
-  parse_spectrum_end(pp, xybin);
+  /* Clean up and return. */
   free(tsize);
-
-  /* For a check.
-  gal_table_write(pp->spectrum, NULL, NULL, GAL_TABLE_FORMAT_BFITS,
-                  "spectrum.fits", "SPECTRUM", 0);
-  */
 }
 
 
 
 
-
 void
 parse_objects(struct mkcatalog_passparams *pp)
 {
@@ -462,21 +346,21 @@ parse_objects(struct mkcatalog_passparams *pp)
   /* If any coordinate columns are requested. */
   size_t *c = (
                /* Coordinate-related columns. */
-               ( oif[    OCOL_GX    ]
-                 || oif[ OCOL_GY    ]
-                 || oif[ OCOL_GZ    ]
-                 || oif[ OCOL_VX    ]
-                 || oif[ OCOL_VY    ]
-                 || oif[ OCOL_VZ    ]
-                 || oif[ OCOL_C_GX  ]
-                 || oif[ OCOL_C_GY  ]
-                 || oif[ OCOL_C_GZ  ]
-                 || oif[ OCOL_MINVX ]
-                 || oif[ OCOL_MAXVX ]
-                 || oif[ OCOL_MINVY ]
-                 || oif[ OCOL_MAXVY ]
-                 || oif[ OCOL_MINVZ ]
-                 || oif[ OCOL_MAXVZ ]
+               ( oif[    OCOL_GX      ]
+                 || oif[ OCOL_GY      ]
+                 || oif[ OCOL_GZ      ]
+                 || oif[ OCOL_VX      ]
+                 || oif[ OCOL_VY      ]
+                 || oif[ OCOL_VZ      ]
+                 || oif[ OCOL_C_GX    ]
+                 || oif[ OCOL_C_GY    ]
+                 || oif[ OCOL_C_GZ    ]
+                 || oif[ OCOL_MINVX   ]
+                 || oif[ OCOL_MAXVX   ]
+                 || oif[ OCOL_MINVY   ]
+                 || oif[ OCOL_MAXVY   ]
+                 || oif[ OCOL_MINVZ   ]
+                 || oif[ OCOL_MAXVZ   ]
                  || oif[ OCOL_MINVNUM ]
                  || oif[ OCOL_MAXVNUM ]
                  || sc
@@ -484,14 +368,21 @@ parse_objects(struct mkcatalog_passparams *pp)
                     the coordinate to find which tile a pixel belongs
                     to. */
                  || tid==GAL_BLANK_SIZE_T )
-               ? gal_pointer_allocate(GAL_TYPE_SIZE_T, ndim, 0, __func__, "c")
+               ? gal_pointer_allocate(GAL_TYPE_SIZE_T, ndim, 0, __func__,
+                                      "c")
                : NULL );
 
-  /* If an XY projection area is necessary, we'll need to allocate an array
-     to keep the projected space. */
-  if( p->spectrum
-      || oif[ OCOL_NUMALLXY ]
-      || oif[ OCOL_NUMXY    ] )
+  /* If any of the projection measurements are necessary, we need to
+     allocate an array to keep the projected space. */
+  if(    oif[ OCOL_NUMALLXY           ]
+      || oif[ OCOL_NUMXY              ]
+      || oif[ OCOL_SUMPROJINSLICE     ]
+      || oif[ OCOL_NUMPROJINSLICE     ]
+      || oif[ OCOL_SUMPROJVARINSLICE  ]
+      || oif[ OCOL_NUMOTHERINSLICE    ]
+      || oif[ OCOL_SUMOTHERINSLICE    ]
+      || oif[ OCOL_SUMOTHERVARINSLICE ]
+      || oif[ OCOL_NUMALLOTHERINSLICE ] )
     {
       xybin=gal_data_alloc(NULL, GAL_TYPE_UINT8, 2, &tsize[1], NULL,
                            1, p->cp.minmapsize, p->cp.quietmmap,
@@ -520,7 +411,7 @@ parse_objects(struct mkcatalog_passparams *pp)
               /* INTERNAL: Get the number of clumps in this object: it is
                  the largest clump ID over each object. */
               if( p->clumps && *C>0 )
-                pp->clumpsinobj = *C > pp->clumpsinobj ? *C : pp->clumpsinobj;
+                pp->clumpsinobj = *C > pp->clumpsinobj?*C:pp->clumpsinobj;
 
 
               /* Add to the area of this object. */
@@ -546,9 +437,9 @@ parse_objects(struct mkcatalog_passparams *pp)
                   if(pp->shift)
                     {
                       /* Calculate the shifted coordinates for second order
-                         calculations. The coordinate is incremented because
-                         from now on, the positions are in the FITS standard
-                         (starting from one).  */
+                         calculations. The coordinate is incremented
+                         because from now on, the positions are in the FITS
+                         standard (starting from one).  */
                       for(d=0;d<ndim;++d) sc[d] = c[d] + 1 - pp->shift[d];
 
                       /* Include the shifted values, note that the second
@@ -562,9 +453,9 @@ parse_objects(struct mkcatalog_passparams *pp)
                   if(p->clumps && *C>0)
                     {
                       if(oif[ OCOL_C_NUMALL ]) oi[ OCOL_C_NUMALL ]++;
-                      if(oif[ OCOL_C_GX ]) oi[ OCOL_C_GX ] += c[ ndim-1 ]+1;
-                      if(oif[ OCOL_C_GY ]) oi[ OCOL_C_GY ] += c[ ndim-2 ]+1;
-                      if(oif[ OCOL_C_GZ ]) oi[ OCOL_C_GZ ] += c[ ndim-3 ]+1;
+                      if(oif[ OCOL_C_GX ]) oi[ OCOL_C_GX ] += c[ndim-1]+1;
+                      if(oif[ OCOL_C_GY ]) oi[ OCOL_C_GY ] += c[ndim-2]+1;
+                      if(oif[ OCOL_C_GZ ]) oi[ OCOL_C_GZ ] += c[ndim-3]+1;
                     }
                 }
 
@@ -602,16 +493,16 @@ parse_objects(struct mkcatalog_passparams *pp)
                         {
                           minima_v = *V;
                           oi[ OCOL_MINVNUM ]=1;
-                          if(oif[OCOL_MINVX]) oi[ OCOL_MINVX ] = c[ ndim-1 ]+1;
-                          if(oif[OCOL_MINVY]) oi[ OCOL_MINVY ] = c[ ndim-2 ]+1;
-                          if(oif[OCOL_MINVZ]) oi[ OCOL_MINVZ ] = c[ ndim-3 ]+1;
+                          if(oif[OCOL_MINVX])oi[OCOL_MINVX]=c[ndim-1]+1;
+                          if(oif[OCOL_MINVY])oi[OCOL_MINVY]=c[ndim-2]+1;
+                          if(oif[OCOL_MINVZ])oi[OCOL_MINVZ]=c[ndim-3]+1;
                         }
                       else
                         {
                           oi[ OCOL_MINVNUM ]++;
-                          if(oif[OCOL_MINVX]) oi[ OCOL_MINVX ] += c[ ndim-1 
]+1;
-                          if(oif[OCOL_MINVY]) oi[ OCOL_MINVY ] += c[ ndim-2 
]+1;
-                          if(oif[OCOL_MINVZ]) oi[ OCOL_MINVZ ] += c[ ndim-3 
]+1;
+                          if(oif[OCOL_MINVX])oi[OCOL_MINVX]+=c[ndim-1]+1;
+                          if(oif[OCOL_MINVY])oi[OCOL_MINVY]+=c[ndim-2]+1;
+                          if(oif[OCOL_MINVZ])oi[OCOL_MINVZ]+=c[ndim-3]+1;
                         }
                     }
                   if( oif[ OCOL_MAXVNUM ] && *V>=maxima_v )
@@ -620,16 +511,16 @@ parse_objects(struct mkcatalog_passparams *pp)
                         {
                           maxima_v = *V;
                           oi[ OCOL_MAXVNUM ]=1;
-                          if(oif[OCOL_MAXVX]) oi[ OCOL_MAXVX ] = c[ ndim-1 ]+1;
-                          if(oif[OCOL_MAXVY]) oi[ OCOL_MAXVY ] = c[ ndim-2 ]+1;
-                          if(oif[OCOL_MAXVZ]) oi[ OCOL_MAXVZ ] = c[ ndim-3 ]+1;
+                          if(oif[OCOL_MAXVX])oi[OCOL_MAXVX]=c[ndim-1]+1;
+                          if(oif[OCOL_MAXVY])oi[OCOL_MAXVY]=c[ndim-2]+1;
+                          if(oif[OCOL_MAXVZ])oi[OCOL_MAXVZ]=c[ndim-3]+1;
                         }
                       else
                         {
                           oi[ OCOL_MAXVNUM ]++;
-                          if(oif[OCOL_MAXVX]) oi[ OCOL_MAXVX ] += c[ ndim-1 
]+1;
-                          if(oif[OCOL_MAXVY]) oi[ OCOL_MAXVY ] += c[ ndim-2 
]+1;
-                          if(oif[OCOL_MAXVZ]) oi[ OCOL_MAXVZ ] += c[ ndim-3 
]+1;
+                          if(oif[OCOL_MAXVX])oi[OCOL_MAXVX]+=c[ndim-1]+1;
+                          if(oif[OCOL_MAXVY])oi[OCOL_MAXVY]+=c[ndim-2]+1;
+                          if(oif[OCOL_MAXVZ])oi[OCOL_MAXVZ]+=c[ndim-3]+1;
                         }
                     }
 
@@ -639,9 +530,9 @@ parse_objects(struct mkcatalog_passparams *pp)
                     {
                       if(oif[ OCOL_NUMWHT ]) oi[ OCOL_NUMWHT ]++;
                       if(oif[ OCOL_SUMWHT ]) oi[ OCOL_SUMWHT ] += *V;
-                      if(oif[ OCOL_VX ]) oi[ OCOL_VX ] += *V*(c[ ndim-1 ]+1);
-                      if(oif[ OCOL_VY ]) oi[ OCOL_VY ] += *V*(c[ ndim-2 ]+1);
-                      if(oif[ OCOL_VZ ]) oi[ OCOL_VZ ] += *V*(c[ ndim-3 ]+1);
+                      if(oif[ OCOL_VX ]) oi[ OCOL_VX ] += *V*(c[ndim-1]+1);
+                      if(oif[ OCOL_VY ]) oi[ OCOL_VY ] += *V*(c[ndim-2]+1);
+                      if(oif[ OCOL_VZ ]) oi[ OCOL_VZ ] += *V*(c[ndim-3]+1);
                       if(pp->shift)
                         {
                           oi[ OCOL_VXX    ] += *V * sc[1] * sc[1];
@@ -651,7 +542,7 @@ parse_objects(struct mkcatalog_passparams *pp)
                       if(p->clumps && *C>0)
                         {
                           if(oif[ OCOL_C_NUMWHT ]) oi[ OCOL_C_NUMWHT ]++;
-                          if(oif[ OCOL_C_SUMWHT ]) oi[ OCOL_C_SUMWHT ] += *V;
+                          if(oif[ OCOL_C_SUMWHT ]) oi[ OCOL_C_SUMWHT ]+=*V;
                           if(oif[ OCOL_C_VX ])
                             oi[   OCOL_C_VX ] += *V * (c[ ndim-1 ]+1);
                           if(oif[ OCOL_C_VY ])
@@ -667,10 +558,10 @@ parse_objects(struct mkcatalog_passparams *pp)
               if(p->sky && oif[ OCOL_SUMSKY ])
                 {
                   skyval = ( pp->st_sky
-                             ? (isnan(*SK)?0:*SK)               /* Full array  
*/
+                             ? (isnan(*SK)?0:*SK)        /* Full array  */
                              : ( p->sky->size>1
-                                 ? (isnan(sky[tid])?0:sky[tid]) /* Tile        
*/
-                                 : sky[0] ) );                  /* Single 
value*/
+                                 ? (isnan(sky[tid])?0:sky[tid]) /* Tile */
+                                 : sky[0] ) );           /* Single value*/
                   if(!isnan(skyval))
                     {
                       oi[ OCOL_NUMSKY  ]++;
@@ -682,8 +573,9 @@ parse_objects(struct mkcatalog_passparams *pp)
               /* Sky standard deviation based measurements.*/
               if(p->std)
                 {
-                  /* Calculate the variance and save it in the output if 
necessary. */
-                  sval = pp->st_std ? *ST : (p->std->size>1?std[tid]:std[0]);
+                  /* Calculate the variance and save it in the output if
+                     necessary. */
+                  sval=pp->st_std ? *ST : (p->std->size>1?std[tid]:std[0]);
                   var = p->variance ? sval : sval*sval;
                   if(oif[ OCOL_SUMVAR ] && (!isnan(var)))
                     {
@@ -746,17 +638,26 @@ parse_objects(struct mkcatalog_passparams *pp)
       while(++u<uf);
 
       /* For a check on the projected 2D areas.
-      if(xybin && pp->object==2)
+      if(xybin && pp->object==1)
         {
           gal_fits_img_write(xybin, "xybin.fits", NULL, NULL);
-          exit(0);
+          printf("Created 'xybin.fits'\n"); exit(0);
         }
       */
     }
 
   /* Generate the Spectrum. */
-  if(p->spectrum)
-    parse_spectrum(pp, xybin);
+  if(    oif[ OCOL_SUMINSLICE         ]
+      || oif[ OCOL_NUMINSLICE         ]
+      || oif[ OCOL_NUMALLINSLICE      ]
+      || oif[ OCOL_SUMVARINSLICE      ]
+      || oif[ OCOL_SUMPROJINSLICE     ]
+      || oif[ OCOL_NUMOTHERINSLICE    ]
+      || oif[ OCOL_SUMOTHERINSLICE    ]
+      || oif[ OCOL_SUMPROJVARINSLICE  ]
+      || oif[ OCOL_SUMOTHERVARINSLICE ]
+      || oif[ OCOL_NUMALLOTHERINSLICE ])
+    parse_vector_dim3(pp, xybin);
 
   /* Clean up. */
   if(c)     free(c);
@@ -841,8 +742,8 @@ parse_clumps(struct mkcatalog_passparams *pp)
 
   /* Coordinate shift. */
   size_t *sc = ( pp->shift
-                 ? gal_pointer_allocate(GAL_TYPE_SIZE_T, ndim, 0, __func__,
-                                        "sc")
+                 ? gal_pointer_allocate(GAL_TYPE_SIZE_T, ndim, 0,
+                                        __func__, "sc")
                  : NULL );
 
   /* If any coordinate columns are requested. */
@@ -868,8 +769,8 @@ parse_clumps(struct mkcatalog_passparams *pp)
                   || cif[ CCOL_MAXVNUM ]
                   || sc
                   || tid==GAL_BLANK_SIZE_T )
-                ? gal_pointer_allocate(GAL_TYPE_SIZE_T, ndim, 0, __func__,
-                                       "c")
+                ? gal_pointer_allocate(GAL_TYPE_SIZE_T, ndim, 0,
+                                       __func__, "c")
                 : NULL );
 
   /* Preparations for neighbor parsing. */
@@ -940,7 +841,8 @@ parse_clumps(struct mkcatalog_passparams *pp)
                   if(c)
                     {
                       /* Get "C" the coordinates of this point. */
-                      gal_dimension_index_to_coord(O-objects, ndim, dsize, c);
+                      gal_dimension_index_to_coord(O-objects, ndim,
+                                                   dsize, c);
 
                       /* Position extrema measurements. */
                       if(cif[ CCOL_MINX ])
@@ -969,7 +871,7 @@ parse_clumps(struct mkcatalog_passparams *pp)
                         {
                           /* Shifted coordinates for second order moments,
                              see explanations in the first pass.*/
-                          for(d=0;d<ndim;++d) sc[d] = c[d] + 1 - pp->shift[d];
+                          for(d=0;d<ndim;++d) sc[d] = c[d]+1-pp->shift[d];
 
                           /* Raw second-order measurements. */
                           ci[ CCOL_GXX ] += sc[1] * sc[1];
@@ -1000,16 +902,22 @@ parse_clumps(struct mkcatalog_passparams *pp)
                             {
                               minima_v[cind] = *V;
                               ci[ CCOL_MINVNUM ]=1;
-                              if(cif[CCOL_MINVX]) ci[ CCOL_MINVX ] = c[ ndim-1 
]+1;
-                              if(cif[CCOL_MINVY]) ci[ CCOL_MINVY ] = c[ ndim-2 
]+1;
-                              if(cif[CCOL_MINVZ]) ci[ CCOL_MINVZ ] = c[ ndim-3 
]+1;
+                              if(cif[CCOL_MINVX])
+                                ci[ CCOL_MINVX ] = c[ ndim-1 ]+1;
+                              if(cif[CCOL_MINVY])
+                                ci[ CCOL_MINVY ] = c[ ndim-2 ]+1;
+                              if(cif[CCOL_MINVZ])
+                                ci[ CCOL_MINVZ ] = c[ ndim-3 ]+1;
                             }
                           else
                             {
                               ci[ CCOL_MINVNUM ]++;
-                              if(cif[CCOL_MINVX]) ci[ CCOL_MINVX ] += c[ 
ndim-1 ]+1;
-                              if(cif[CCOL_MINVY]) ci[ CCOL_MINVY ] += c[ 
ndim-2 ]+1;
-                              if(cif[CCOL_MINVZ]) ci[ CCOL_MINVZ ] += c[ 
ndim-3 ]+1;
+                              if(cif[CCOL_MINVX])
+                                ci[  CCOL_MINVX ] += c[ ndim-1 ]+1;
+                              if(cif[CCOL_MINVY])
+                                ci[  CCOL_MINVY ] += c[ ndim-2 ]+1;
+                              if(cif[CCOL_MINVZ])
+                                ci[  CCOL_MINVZ ] += c[ ndim-3 ]+1;
                             }
                         }
                       if( cif[ CCOL_MAXVNUM ] && *V>=maxima_v[cind] )
@@ -1018,16 +926,22 @@ parse_clumps(struct mkcatalog_passparams *pp)
                             {
                               maxima_v[cind] = *V;
                               ci[ CCOL_MAXVNUM ]=1;
-                              if(cif[CCOL_MAXVX]) ci[ CCOL_MAXVX ] = c[ ndim-1 
]+1;
-                              if(cif[CCOL_MAXVY]) ci[ CCOL_MAXVY ] = c[ ndim-2 
]+1;
-                              if(cif[CCOL_MAXVZ]) ci[ CCOL_MAXVZ ] = c[ ndim-3 
]+1;
+                              if(cif[CCOL_MAXVX])
+                                ci[  CCOL_MAXVX ] = c[ ndim-1 ]+1;
+                              if(cif[CCOL_MAXVY])
+                                ci[  CCOL_MAXVY ] = c[ ndim-2 ]+1;
+                              if(cif[CCOL_MAXVZ])
+                                ci[  CCOL_MAXVZ ] = c[ ndim-3 ]+1;
                             }
                           else
                             {
                               ci[ CCOL_MAXVNUM ]++;
-                              if(cif[CCOL_MAXVX]) ci[ CCOL_MAXVX ] += c[ 
ndim-1 ]+1;
-                              if(cif[CCOL_MAXVY]) ci[ CCOL_MAXVY ] += c[ 
ndim-2 ]+1;
-                              if(cif[CCOL_MAXVZ]) ci[ CCOL_MAXVZ ] += c[ 
ndim-3 ]+1;
+                              if(cif[CCOL_MAXVX])
+                                ci[  CCOL_MAXVX ] += c[ ndim-1 ]+1;
+                              if(cif[CCOL_MAXVY])
+                                ci[  CCOL_MAXVY ] += c[ ndim-2 ]+1;
+                              if(cif[CCOL_MAXVZ])
+                                ci[  CCOL_MAXVZ ] += c[ ndim-3 ]+1;
                             }
                         }
 
@@ -1302,22 +1216,22 @@ parse_area_of_frac_sum(struct mkcatalog_passparams *pp, 
gal_data_t *values,
       if(flag[ o1c0 ? OCOL_MAXIMUM : CCOL_MAXIMUM ])
         outarr[ o1c0 ? OCOL_MAXIMUM : CCOL_MAXIMUM ] = max;
 
-      /* The number of pixels within half the maximum. */
+      /* Number of pixels within half the maximum. */
       if(flag[ o1c0 ? OCOL_HALFMAXNUM : CCOL_HALFMAXNUM ])
         outarr[ o1c0 ? OCOL_HALFMAXNUM : CCOL_HALFMAXNUM ]
           = parse_frac_find(sorted_d, max, 0.5f, 0);
 
-      /* The number of pixels within the first requested fraction of maximum */
+      /* Number of pixels within the first requested fraction of maximum */
       if(flag[ o1c0 ? OCOL_FRACMAX1NUM : CCOL_FRACMAX1NUM ])
         outarr[ o1c0 ? OCOL_FRACMAX1NUM : CCOL_FRACMAX1NUM ]
           = parse_frac_find(sorted_d, max, fracmax[0], 0);
 
-      /* The number of pixels within the first requested fraction of maximum */
+      /* Number of pixels within the first requested fraction of maximum */
       if(flag[ o1c0 ? OCOL_FRACMAX2NUM : CCOL_FRACMAX2NUM ])
         outarr[ o1c0 ? OCOL_FRACMAX2NUM : CCOL_FRACMAX2NUM ]
           = parse_frac_find(sorted_d, max, fracmax[1], 0);
 
-      /* The sum of the pixels within the given fraction of the maximum. */
+      /* Sum of the pixels within the given fraction of the maximum. */
       if( flag[ o1c0 ? OCOL_HALFMAXSUM : CCOL_HALFMAXSUM ] )
         outarr[ o1c0 ? OCOL_HALFMAXSUM : CCOL_HALFMAXSUM ]
           = parse_frac_sum(sorted_d, max, 0.5f, 0);
@@ -1361,32 +1275,32 @@ parse_order_based(struct mkcatalog_passparams *pp)
      can just write NaN values for the necessary columns. */
   if(tmpsize==0)
     {
-      if(p->oiflag[ OCOL_MEDIAN        ]) pp->oi[ OCOL_MEDIAN       ] = NAN;
-      if(p->oiflag[ OCOL_MAXIMUM       ]) pp->oi[ OCOL_MAXIMUM      ] = NAN;
-      if(p->oiflag[ OCOL_HALFMAXSUM    ]) pp->oi[ OCOL_HALFMAXSUM   ] = NAN;
-      if(p->oiflag[ OCOL_HALFMAXNUM    ]) pp->oi[ OCOL_HALFMAXNUM   ] = 0;
-      if(p->oiflag[ OCOL_HALFSUMNUM    ]) pp->oi[ OCOL_HALFSUMNUM   ] = 0;
-      if(p->oiflag[ OCOL_FRACMAX1NUM   ]) pp->oi[ OCOL_FRACMAX1NUM  ] = 0;
-      if(p->oiflag[ OCOL_FRACMAX2NUM   ]) pp->oi[ OCOL_FRACMAX2NUM  ] = 0;
-      if(p->oiflag[ OCOL_SIGCLIPNUM    ]) pp->oi[ OCOL_SIGCLIPNUM   ] = 0;
-      if(p->oiflag[ OCOL_SIGCLIPSTD    ]) pp->oi[ OCOL_SIGCLIPSTD   ] = 0;
-      if(p->oiflag[ OCOL_SIGCLIPMEAN   ]) pp->oi[ OCOL_SIGCLIPMEAN  ] = NAN;
-      if(p->oiflag[ OCOL_SIGCLIPMEDIAN ]) pp->oi[ OCOL_SIGCLIPMEDIAN] = NAN;
+      if(p->oiflag[OCOL_MEDIAN       ]) pp->oi[ OCOL_MEDIAN       ] = NAN;
+      if(p->oiflag[OCOL_MAXIMUM      ]) pp->oi[ OCOL_MAXIMUM      ] = NAN;
+      if(p->oiflag[OCOL_HALFMAXSUM   ]) pp->oi[ OCOL_HALFMAXSUM   ] = NAN;
+      if(p->oiflag[OCOL_HALFMAXNUM   ]) pp->oi[ OCOL_HALFMAXNUM   ] = 0;
+      if(p->oiflag[OCOL_HALFSUMNUM   ]) pp->oi[ OCOL_HALFSUMNUM   ] = 0;
+      if(p->oiflag[OCOL_FRACMAX1NUM  ]) pp->oi[ OCOL_FRACMAX1NUM  ] = 0;
+      if(p->oiflag[OCOL_FRACMAX2NUM  ]) pp->oi[ OCOL_FRACMAX2NUM  ] = 0;
+      if(p->oiflag[OCOL_SIGCLIPNUM   ]) pp->oi[ OCOL_SIGCLIPNUM   ] = 0;
+      if(p->oiflag[OCOL_SIGCLIPSTD   ]) pp->oi[ OCOL_SIGCLIPSTD   ] = 0;
+      if(p->oiflag[OCOL_SIGCLIPMEAN  ]) pp->oi[ OCOL_SIGCLIPMEAN  ] = NAN;
+      if(p->oiflag[OCOL_SIGCLIPMEDIAN]) pp->oi[ OCOL_SIGCLIPMEDIAN] = NAN;
       if(p->clumps)
         for(i=0;i<pp->clumpsinobj;++i)
           {
             ci=&pp->ci[ i * CCOL_NUMCOLS ];
-            if(p->ciflag[ CCOL_MEDIAN        ]) ci[ CCOL_MEDIAN      ] = NAN;
-            if(p->ciflag[ CCOL_MAXIMUM       ]) ci[ CCOL_MAXIMUM     ] = NAN;
-            if(p->ciflag[ CCOL_HALFMAXSUM    ]) ci[ CCOL_HALFMAXSUM  ] = NAN;
-            if(p->ciflag[ CCOL_HALFMAXNUM    ]) ci[ CCOL_HALFMAXNUM  ] = 0;
-            if(p->ciflag[ CCOL_HALFSUMNUM    ]) ci[ CCOL_HALFSUMNUM  ] = 0;
-            if(p->ciflag[ CCOL_FRACMAX1NUM   ]) ci[ CCOL_FRACMAX1NUM ] = 0;
-            if(p->ciflag[ CCOL_FRACMAX2NUM   ]) ci[ CCOL_FRACMAX2NUM ] = 0;
-            if(p->ciflag[ CCOL_SIGCLIPNUM    ]) ci[ CCOL_SIGCLIPNUM  ] = 0;
-            if(p->ciflag[ CCOL_SIGCLIPSTD    ]) ci[ CCOL_SIGCLIPSTD  ] = 0;
-            if(p->ciflag[ CCOL_SIGCLIPMEAN   ]) ci[ CCOL_SIGCLIPMEAN ] = NAN;
-            if(p->ciflag[ CCOL_SIGCLIPMEDIAN ]) ci[ CCOL_SIGCLIPMEDIAN] = NAN;
+            if(p->ciflag[CCOL_MEDIAN     ])   ci[ CCOL_MEDIAN      ] = NAN;
+            if(p->ciflag[CCOL_MAXIMUM    ])   ci[ CCOL_MAXIMUM     ] = NAN;
+            if(p->ciflag[CCOL_HALFMAXSUM ])   ci[ CCOL_HALFMAXSUM  ] = NAN;
+            if(p->ciflag[CCOL_HALFMAXNUM ])   ci[ CCOL_HALFMAXNUM  ] = 0;
+            if(p->ciflag[CCOL_HALFSUMNUM ])   ci[ CCOL_HALFSUMNUM  ] = 0;
+            if(p->ciflag[CCOL_FRACMAX1NUM])   ci[ CCOL_FRACMAX1NUM ] = 0;
+            if(p->ciflag[CCOL_FRACMAX2NUM])   ci[ CCOL_FRACMAX2NUM ] = 0;
+            if(p->ciflag[CCOL_SIGCLIPNUM ])   ci[ CCOL_SIGCLIPNUM  ] = 0;
+            if(p->ciflag[CCOL_SIGCLIPSTD ])   ci[ CCOL_SIGCLIPSTD  ] = 0;
+            if(p->ciflag[CCOL_SIGCLIPMEAN])   ci[ CCOL_SIGCLIPMEAN ] = NAN;
+            if(p->ciflag[CCOL_SIGCLIPMEDIAN]) ci[ CCOL_SIGCLIPMEDIAN]=NAN;
           }
       return;
     }
@@ -1404,8 +1318,8 @@ parse_order_based(struct mkcatalog_passparams *pp)
       errno=0;
       clumpsvals=malloc(pp->clumpsinobj * sizeof *clumpsvals);
       if(clumpsvals==NULL)
-        error(EXIT_FAILURE, errno, "%s: couldn't allocate 'clumpsvals' for "
-              "%zu clumps", __func__, pp->clumpsinobj);
+        error(EXIT_FAILURE, errno, "%s: couldn't allocate 'clumpsvals' "
+              "for %zu clumps", __func__, pp->clumpsinobj);
 
       /* Allocate the array necessary to keep the values of each clump. */
       ccounter=gal_pointer_allocate(GAL_TYPE_SIZE_T, pp->clumpsinobj, 1,
@@ -1469,7 +1383,8 @@ parse_order_based(struct mkcatalog_passparams *pp)
   /* Calculate the necessary values for the objects. */
   if(p->oiflag[ OCOL_MEDIAN ])
     {
-      result=gal_data_copy_to_new_type_free(gal_statistics_median(objvals, 1),
+      result=gal_data_copy_to_new_type_free(gal_statistics_median(objvals,
+                                                                  1),
                                             GAL_TYPE_FLOAT64);
       pp->oi[OCOL_MEDIAN]=*((double *)(result->array));
       gal_data_free(result);
@@ -1524,9 +1439,11 @@ parse_order_based(struct mkcatalog_passparams *pp)
               if(clumpsvals[i])
                 {
                   result=gal_statistics_median(clumpsvals[i], 1);
-                  result=gal_data_copy_to_new_type_free(result, 
GAL_TYPE_FLOAT64);
+                  result=gal_data_copy_to_new_type_free(result,
+                                                        GAL_TYPE_FLOAT64);
                   ci[ CCOL_MEDIAN ] = ( *((double *)(result->array))
-                                        - (ci[ CCOL_RIV_SUM ]/ci[ CCOL_RIV_NUM 
]) );
+                                        - (   ci[ CCOL_RIV_SUM ]
+                                            / ci[ CCOL_RIV_NUM ]) );
                   gal_data_free(result);
                 }
               else ci[ CCOL_MEDIAN ] = NAN;
@@ -1540,28 +1457,36 @@ parse_order_based(struct mkcatalog_passparams *pp)
             {
               if(clumpsvals[i])
                 {
-                  result=gal_statistics_sigma_clip(clumpsvals[i], 
p->sigmaclip[0],
+                  result=gal_statistics_sigma_clip(clumpsvals[i],
+                                                   p->sigmaclip[0],
                                                    p->sigmaclip[1], 1, 1);
                   sigcliparr=result->array;
                   if(p->ciflag[ CCOL_SIGCLIPNUM ])
                     ci[CCOL_SIGCLIPNUM]=sigcliparr[0];
                   if(p->ciflag[ CCOL_SIGCLIPSTD ])
                     ci[CCOL_SIGCLIPSTD]=( sigcliparr[3]
-                                          - (ci[ CCOL_RIV_SUM ]/ci[ 
CCOL_RIV_NUM ]));
+                                          - (   ci[ CCOL_RIV_SUM ]
+                                              / ci[ CCOL_RIV_NUM ]));
                   if(p->ciflag[ CCOL_SIGCLIPMEAN ])
                     ci[CCOL_SIGCLIPMEAN]=( sigcliparr[2]
-                                           - (ci[ CCOL_RIV_SUM ]/ci[ 
CCOL_RIV_NUM ]));
+                                           - (   ci[ CCOL_RIV_SUM ]
+                                               / ci[ CCOL_RIV_NUM ]));
                   if(p->ciflag[ CCOL_SIGCLIPMEDIAN ])
                     ci[CCOL_SIGCLIPMEDIAN]=( sigcliparr[1]
-                                             - (ci[ CCOL_RIV_SUM ]/ci[ 
CCOL_RIV_NUM ]));
+                                             - (   ci[ CCOL_RIV_SUM ]
+                                                 / ci[ CCOL_RIV_NUM ]));
                   gal_data_free(result);
                 }
               else
                 {
-                  if(p->ciflag[ CCOL_SIGCLIPNUM    ]) ci[ CCOL_SIGCLIPNUM  
]=NAN;
-                  if(p->ciflag[ CCOL_SIGCLIPSTD    ]) ci[ CCOL_SIGCLIPSTD  
]=NAN;
-                  if(p->ciflag[ CCOL_SIGCLIPMEAN   ]) ci[ CCOL_SIGCLIPMEAN 
]=NAN;
-                  if(p->ciflag[ CCOL_SIGCLIPMEDIAN ]) 
ci[CCOL_SIGCLIPMEDIAN]=NAN;
+                  if(p->ciflag[ CCOL_SIGCLIPNUM    ])
+                    ci[ CCOL_SIGCLIPNUM  ]=NAN;
+                  if(p->ciflag[ CCOL_SIGCLIPSTD    ])
+                    ci[ CCOL_SIGCLIPSTD  ]=NAN;
+                  if(p->ciflag[ CCOL_SIGCLIPMEAN   ])
+                    ci[ CCOL_SIGCLIPMEAN ]=NAN;
+                  if(p->ciflag[ CCOL_SIGCLIPMEDIAN ])
+                    ci[CCOL_SIGCLIPMEDIAN]=NAN;
                 }
             }
 
@@ -1579,14 +1504,14 @@ parse_order_based(struct mkcatalog_passparams *pp)
                 parse_area_of_frac_sum(pp, clumpsvals[i], ci, 0);
               else
                 {
-                  if( p->ciflag[ CCOL_MAXIMUM     ]) ci[ CCOL_MAXIMUM     
]=NAN;
-                  if( p->ciflag[ CCOL_HALFMAXNUM  ]) ci[ CCOL_HALFMAXNUM  
]=NAN;
-                  if( p->ciflag[ CCOL_HALFMAXSUM  ]) ci[ CCOL_HALFMAXSUM  
]=NAN;
-                  if( p->ciflag[ CCOL_HALFSUMNUM  ]) ci[ CCOL_HALFSUMNUM  
]=NAN;
-                  if( p->ciflag[ CCOL_FRACMAX1NUM ]) ci[ CCOL_FRACMAX1NUM 
]=NAN;
-                  if( p->ciflag[ CCOL_FRACMAX1SUM ]) ci[ CCOL_FRACMAX1SUM 
]=NAN;
-                  if( p->ciflag[ CCOL_FRACMAX2NUM ]) ci[ CCOL_FRACMAX2NUM 
]=NAN;
-                  if( p->ciflag[ CCOL_FRACMAX2SUM ]) ci[ CCOL_FRACMAX2SUM 
]=NAN;
+                  if(p->ciflag[CCOL_MAXIMUM    ]) ci[CCOL_MAXIMUM    ]=NAN;
+                  if(p->ciflag[CCOL_HALFMAXNUM ]) ci[CCOL_HALFMAXNUM ]=NAN;
+                  if(p->ciflag[CCOL_HALFMAXSUM ]) ci[CCOL_HALFMAXSUM ]=NAN;
+                  if(p->ciflag[CCOL_HALFSUMNUM ]) ci[CCOL_HALFSUMNUM ]=NAN;
+                  if(p->ciflag[CCOL_FRACMAX1NUM]) ci[CCOL_FRACMAX1NUM]=NAN;
+                  if(p->ciflag[CCOL_FRACMAX1SUM]) ci[CCOL_FRACMAX1SUM]=NAN;
+                  if(p->ciflag[CCOL_FRACMAX2NUM]) ci[CCOL_FRACMAX2NUM]=NAN;
+                  if(p->ciflag[CCOL_FRACMAX2SUM]) ci[CCOL_FRACMAX2SUM]=NAN;
                 }
             }
 
diff --git a/bin/mkcatalog/ui.c b/bin/mkcatalog/ui.c
index caacf661..b08c47c0 100644
--- a/bin/mkcatalog/ui.c
+++ b/bin/mkcatalog/ui.c
@@ -227,15 +227,14 @@ ui_column_codes_ll(struct argp_option *option, char *arg,
       if( arg[0]=='0' && arg[1]=='\0' ) return NULL;
       else if ( !(arg[0]=='1' && arg[1]=='\0')  )
         error_at_line(EXIT_FAILURE, 0, filename, lineno, "'%s' is not a "
-                      "valid value to the '%s' option: ('%s').\n\n'%s' is "
-                      "an on/off option specifying if you want this column "
-                      "in the output catalog, it doesn't take any "
-                      "arguments. In a configuration file, it can only take "
-                      "a value of '0' (to be ignored) or '1'", arg,
+                      "valid value to the '%s' option: ('%s').\n\n'%s' "
+                      "is an on/off option specifying if you want this "
+                      "column in the output catalog, it doesn't take any "
+                      "arguments. In a configuration file, it can only "
+                      "take a value of '0' (to be ignored) or '1'", arg,
                       option->name, option->doc, option->name);
     }
 
-
   /* The user wants this column, so add it to the list. Note that the 'ids'
      column means three columns. */
   if(option->key==UI_KEY_IDS)
@@ -318,8 +317,8 @@ ui_check_upperlimit(struct argp_option *option, char *arg,
             error_at_line(EXIT_FAILURE, 0, filename, lineno, "%g (value "
                           "number %zu given to '--%s') is not an "
                           "integer. The value(s) to this option are "
-                          "object/clump labels/identifiers, so they must be "
-                          "integers", d[i], i+1, option->name);
+                          "object/clump labels/identifiers, so they must "
+                          "be integers", d[i], i+1, option->name);
           if( d[i]<=0 )
             error_at_line(EXIT_FAILURE, 0, filename, lineno, "%g (value "
                           "number %zu given to '--%s') is not positive. "
@@ -378,10 +377,10 @@ ui_read_check_only_options(struct mkcatalogparams *p)
     error(EXIT_FAILURE, 0, "no clumps catalog is requested, hence "
           "'--checkuplim' is only available for objects (one value "
           "must be given to it).\n\n"
-          "To ask for a clumps catalog, please append '--clumpscat' to the "
-          "command calling MakeCatalog.\n\n"
-          "If you want the upperlimit check table for an object, only give "
-          "one value (the object's label) to '--checkuplim'.");
+          "To ask for a clumps catalog, please append '--clumpscat' to "
+          "the command calling MakeCatalog.\n\n"
+          "If you want the upperlimit check table for an object, only "
+          "give one value (the object's label) to '--checkuplim'.");
 
   /* See if '--skyin' is a filename or a value. When the string is ONLY a
      number (and nothing else), 'tailptr' will point to the end of the
@@ -392,8 +391,8 @@ ui_read_check_only_options(struct mkcatalogparams *p)
       if(*tailptr=='\0')
         {
           /* Allocate the data structure. */
-          p->sky=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1, &one, NULL, 0, -1,
-                                1, NULL, NULL, NULL);
+          p->sky=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1, &one, NULL,
+                                0, -1, 1, NULL, NULL, NULL);
 
           /* Write the value inside it. */
           *((float *)(p->sky->array))=tmp;
@@ -407,8 +406,8 @@ ui_read_check_only_options(struct mkcatalogparams *p)
       if(*tailptr=='\0')
         {
           /* Allocate the data structure. */
-          p->std=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1, &one, NULL, 0, -1,
-                                1, NULL, NULL, NULL);
+          p->std=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1, &one, NULL,
+                                0, -1, 1, NULL, NULL, NULL);
 
           /* Write the value inside it. */
           *((float *)(p->std->array))=tmp;
@@ -459,10 +458,11 @@ ui_check_options_and_arguments(struct mkcatalogparams *p)
   if(p->objectsfile)
     {
       if( gal_fits_file_recognized(p->objectsfile) && p->cp.hdu==NULL )
-        error(EXIT_FAILURE, 0, "no HDU specified. When the input is a FITS "
-              "file, a HDU must also be specified, you can use the '--hdu' "
-              "('-h') option and give it the HDU number (starting from "
-              "zero), extension name, or anything acceptable by CFITSIO");
+        error(EXIT_FAILURE, 0, "no HDU specified. When the input is a "
+              "FITS file, a HDU must also be specified, you can use the "
+              "'--hdu' ('-h') option and give it the HDU number (starting "
+              "from zero), extension name, or anything acceptable by "
+              "CFITSIO");
 
     }
   else
@@ -500,13 +500,13 @@ ui_set_filenames(struct mkcatalogparams *p)
 
   p->usedvaluesfile = p->valuesfile ? p->valuesfile : p->objectsfile;
 
-  p->usedskyfile    = ( p->skyfile
-                       ? p->skyfile
-                       : ( p->valuesfile ? p->valuesfile : p->objectsfile ) );
+  p->usedskyfile = ( p->skyfile
+                     ? p->skyfile
+                     : (p->valuesfile ? p->valuesfile : p->objectsfile) );
 
-  p->usedstdfile    = ( p->stdfile
-                       ? p->stdfile
-                       : ( p->valuesfile ? p->valuesfile : p->objectsfile ) );
+  p->usedstdfile = ( p->stdfile
+                     ? p->stdfile
+                     : (p->valuesfile ? p->valuesfile : p->objectsfile) );
 }
 
 
@@ -560,10 +560,11 @@ ui_wcs_info(struct mkcatalogparams *p)
       for(i=0;i<p->objects->ndim;++i)
         {
           /* CTYPE might contain '-' characters, we just want the first
-             non-dash characters. The loop will either stop either at the end
-             or where there is a dash. So we can just replace it with an
-             end-of-string character. */
-          gal_checkset_allocate_copy(p->objects->wcs->ctype[i], &p->ctype[i]);
+             non-dash characters. The loop will either stop either at the
+             end or where there is a dash. So we can just replace it with
+             an end-of-string character. */
+          gal_checkset_allocate_copy(p->objects->wcs->ctype[i],
+                                     &p->ctype[i]);
           c=p->ctype[i]; while(*c!='\0' && *c!='-') ++c;
           *c='\0';
         }
@@ -584,7 +585,8 @@ ui_num_clumps(struct mkcatalogparams *p)
   gal_list_i32_t *tmp, **labsinobj;
   int32_t *o=p->objects->array, *of=o+p->objects->size, *c=p->clumps->array;
 
-  /* Allocate array of lists to keep the unique labels within each object. */
+  /* Allocate array of lists to keep the unique labels within each
+     object. */
   errno=0;
   labsinobj=calloc(p->numobjects+1, sizeof *labsinobj);
   if(labsinobj==NULL)
@@ -600,7 +602,8 @@ ui_num_clumps(struct mkcatalogparams *p)
         {
           /* See if the label has already been found. */
           olab = p->outlabsinv ? p->outlabsinv[*o] : *o;
-          for(tmp=labsinobj[olab];tmp!=NULL;tmp=tmp->next) if(tmp->v==*c) 
break;
+          for(tmp=labsinobj[olab];tmp!=NULL;tmp=tmp->next)
+            if(tmp->v==*c) break;
 
           /* When it wasn't found, 'tmp==NULL'. */
           if(tmp==NULL)
@@ -835,6 +838,7 @@ ui_one_tile_per_object_correct_numobjects(struct 
mkcatalogparams *p)
 static void
 ui_read_labels(struct mkcatalogparams *p)
 {
+  gal_list_i32_t *colcode;
   gal_data_t *tmp, *keys=gal_data_array_calloc(2);
 
   /* Read it into memory. */
@@ -859,11 +863,24 @@ ui_read_labels(struct mkcatalogparams *p)
           p->cp.hdu, p->objects->ndim);
 
 
-  /* Make sure the '--spectrum' option is not given on a 2D image.  */
-  if(p->spectrum && p->objects->ndim!=3)
-    error(EXIT_FAILURE, 0, "%s (hdu %s) has %zu dimensions, but '--spectrum' "
-          "is currently only defined on 3D datasets", p->objectsfile,
-          p->cp.hdu, p->objects->ndim);
+  /* If a column needs a 3D input, do the check here.  */
+  for(colcode=p->columnids; colcode!=NULL; colcode=colcode->next)
+    switch(colcode->v)
+      {
+      case UI_KEY_SUMINSLICE:         case UI_KEY_SUMERRINSLICE:
+      case UI_KEY_AREAINSLICE:        case UI_KEY_SUMPROJINSLICE:
+      case UI_KEY_AREAPROJINSLICE:    case UI_KEY_SUMPROJERRINSLICE:
+      case UI_KEY_AREAOTHERINSLICE:   case UI_KEY_SUMOTHERINSLICE:
+      case UI_KEY_SUMOTHERERRINSLICE:
+        if(p->objects->ndim!=3)
+          error(EXIT_FAILURE, 0, "%s (hdu %s) has %zu dimensions, but "
+                "at least one requested column requires a 3D input "
+                "(for example those ending with 'inslice', they are "
+                "clearly marked with '[3D input]' in the output of "
+                "'%s --help')", p->objectsfile, p->cp.hdu,
+                p->objects->ndim, PROGRAM_EXEC);
+        break;
+      }
 
 
   /* See if the total number of objects is given in the header keywords. */
@@ -874,7 +891,7 @@ ui_read_labels(struct mkcatalogparams *p)
   if(keys[0].status) /* status!=0: the key couldn't be read by CFITSIO. */
     {
       tmp=gal_statistics_maximum(p->objects);
-      p->numobjects=*((int32_t *)(tmp->array)); /*numobjects is in int32_t.*/
+      p->numobjects=*((int32_t *)(tmp->array)); /*numobjects is int32_t.*/
       gal_data_free(tmp);
     }
 
@@ -883,8 +900,8 @@ ui_read_labels(struct mkcatalogparams *p)
      error (it is pointless to build a catalog). */
   if(p->numobjects==0)
     error(EXIT_FAILURE, 0, "no object labels (non-zero pixels) in "
-          "%s (hdu %s). To make a catalog, labeled regions must be defined",
-          p->objectsfile, p->cp.hdu);
+          "%s (hdu %s). To make a catalog, labeled regions must be "
+          "defined", p->objectsfile, p->cp.hdu);
 
 
   /* See if the labels image has blank pixels and set the flags
@@ -911,8 +928,8 @@ ui_read_labels(struct mkcatalogparams *p)
               "give a specific HDU using its number (counting from zero) "
               "or name. If the dataset is in another file, please use "
               "'--clumpsfile' to give the filename. If you don't want any "
-              "clumps catalog output, remove the '--clumpscat' option from "
-              "the command-line or give it a value of zero in a "
+              "clumps catalog output, remove the '--clumpscat' option "
+              "from the command-line or give it a value of zero in a "
               "configuration file", p->usedclumpsfile);
 
       /* Read the clumps image. */
@@ -955,11 +972,11 @@ ui_read_labels(struct mkcatalogparams *p)
             error(EXIT_FAILURE, 0, "%s (hdu: %s): the 'NUMCLUMPS' header "
                   "keyword has a value of zero, but there are positive "
                   "pixels in the array, showing that there are clumps in "
-                  "image. This is a wrong usage of the 'NUMCLUMPS' keyword."
-                  "It must contain the total number of clumps (irrespective "
-                  "of how many objects there are). Please correct this issue "
-                  "and run MakeCatalog again", p->usedclumpsfile,
-                  p->clumpshdu);
+                  "image. This is a wrong usage of the 'NUMCLUMPS' "
+                  "keyword. It must contain the total number of clumps "
+                  "(irrespective of how many objects there are). Please "
+                  "correct this issue and run MakeCatalog again",
+                  p->usedclumpsfile, p->clumpshdu);
 
           /* Since there are no clumps, we won't bother creating a clumps
              catalog and from this step onward, we'll act as if no clumps
@@ -997,7 +1014,6 @@ ui_necessary_inputs(struct mkcatalogparams *p, int 
*values, int *sky,
   /* Set necessary inputs based on options. */
   if(p->forcereadstd) *std=1;
   if(p->upperlimit) *values=1;
-  if(p->spectrum) *values=*std=1;
 
   /* Go over all the object columns. Note that the objects and clumps (if
      the '--clumpcat' option is given) inputs are mandatory and it is not
@@ -1066,6 +1082,17 @@ ui_necessary_inputs(struct mkcatalogparams *p, int 
*values, int *sky,
         case OCOL_C_GZ:               /* Only clump labels. */     break;
         case OCOL_C_SUMWHT:           *values        = 1;          break;
         case OCOL_C_NUMWHT:           *values        = 1;          break;
+        case OCOL_SUMINSLICE:         *values        = 1;          break;
+        case OCOL_NUMINSLICE:         *values        = 1;          break;
+        case OCOL_NUMALLINSLICE:      /* Only object labels. */    break;
+        case OCOL_SUMVARINSLICE:      *values = *std = 1;          break;
+        case OCOL_SUMPROJINSLICE:     *values        = 1;          break;
+        case OCOL_NUMPROJINSLICE:     *values        = 1;          break;
+        case OCOL_NUMOTHERINSLICE:    *values        = 1;          break;
+        case OCOL_SUMOTHERINSLICE:    *values        = 1;          break;
+        case OCOL_SUMPROJVARINSLICE:  *values = *std = 1;          break;
+        case OCOL_SUMOTHERVARINSLICE: *values = *std = 1;          break;
+        case OCOL_NUMALLOTHERINSLICE: /* Only object labels. */    break;
         default:
           error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
                 "fix the problem. The code %zu is not a recognized "
@@ -1267,7 +1294,8 @@ ui_preparations_read_inputs(struct mkcatalogparams *p)
               "give the filename", p->usedvaluesfile);
 
       /* Read the values dataset. */
-      p->values=gal_array_read_one_ch_to_type(p->usedvaluesfile, p->valueshdu,
+      p->values=gal_array_read_one_ch_to_type(p->usedvaluesfile,
+                                              p->valueshdu,
                                               NULL, GAL_TYPE_FLOAT32,
                                               p->cp.minmapsize,
                                               p->cp.quietmmap);
@@ -1291,12 +1319,16 @@ ui_preparations_read_inputs(struct mkcatalogparams *p)
         {
           for(column=p->objectcols; column!=NULL; column=column->next)
             if( !strcmp(column->unit, MKCATALOG_NO_UNIT) )
-              { free(column->unit);
-                gal_checkset_allocate_copy(p->values->unit, &column->unit); }
+              {
+                free(column->unit);
+                gal_checkset_allocate_copy(p->values->unit, &column->unit);
+              }
           for(column=p->clumpcols; column!=NULL; column=column->next)
             if( !strcmp(column->unit, MKCATALOG_NO_UNIT) )
-              { free(column->unit);
-                gal_checkset_allocate_copy(p->values->unit, &column->unit); }
+              {
+                free(column->unit);
+                gal_checkset_allocate_copy(p->values->unit, &column->unit);
+              }
         }
     }
 
@@ -1313,10 +1345,10 @@ ui_preparations_read_inputs(struct mkcatalogparams *p)
             error(EXIT_FAILURE, 0, "%s: no HDU/extension provided for the "
                   "SKY dataset. Atleast one column needs this dataset, or "
                   "you have asked to subtract the Sky from the values.\n\n"
-                  "Please use the '--skyhdu' option to give a specific HDU "
-                  "using its number (counting from zero) or name. If the "
-                  "dataset is in another file, please use '--skyin' to "
-                  "give the filename", p->usedskyfile);
+                  "Please use the '--skyhdu' option to give a specific "
+                  "HDU using its number (counting from zero) or name. If "
+                  "the dataset is in another file, please use '--skyin' "
+                  "to give the filename", p->usedskyfile);
 
           /* Read the Sky dataset. */
           p->sky=gal_array_read_one_ch_to_type(p->usedskyfile, p->skyhdu,
@@ -1353,7 +1385,8 @@ ui_preparations_read_inputs(struct mkcatalogparams *p)
       /* Read the Sky standard deviation image into memory. */
       p->std=gal_array_read_one_ch_to_type(p->usedstdfile, p->stdhdu,
                                            NULL, GAL_TYPE_FLOAT32,
-                                           p->cp.minmapsize, p->cp.quietmmap);
+                                           p->cp.minmapsize,
+                                           p->cp.quietmmap);
       p->std->ndim=gal_dimension_remove_extra(p->std->ndim,
                                               p->std->dsize, NULL);
 
@@ -1396,17 +1429,17 @@ ui_preparations_read_inputs(struct mkcatalogparams *p)
 
           /* Check its size. */
           if( gal_dimension_is_different(p->objects, p->upmask) )
-            error(EXIT_FAILURE, 0, "'%s' (hdu: %s) and '%s' (hdu: %s) have a"
-                  "different dimension/size", p->upmaskfile, p->upmaskhdu,
-                  p->objectsfile, p->cp.hdu);
+            error(EXIT_FAILURE, 0, "'%s' (hdu: %s) and '%s' (hdu: %s) "
+                  "have a different dimension/size", p->upmaskfile,
+                  p->upmaskhdu, p->objectsfile, p->cp.hdu);
 
           /* If it isn't an integer type, report an error. */
           if( p->upmask->type==GAL_TYPE_FLOAT32
               || p->upmask->type==GAL_TYPE_FLOAT64 )
             error(EXIT_FAILURE, 0, "%s (hdu: %s) has a %s numerical data "
-                  "type. Only integer type inputs are acceptable as a mask."
-                  "If the values are indeed integers, only placed in a "
-                  "floating point container, you can use Gnuastro's "
+                  "type. Only integer type inputs are acceptable as a "
+                  "mask. If the values are indeed integers, only placed "
+                  "in a floating point container, you can use Gnuastro's "
                   "Arithmetic program to conver the numeric data type",
                   p->upmaskfile, p->upmaskhdu,
                   gal_type_name(p->upmask->type, 1));
@@ -1444,9 +1477,9 @@ ui_preparations_read_keywords(struct mkcatalogparams *p)
           /* Read the keywords from the standard deviation image. */
           keys=gal_data_array_calloc(2);
           keys[0].next=&keys[1];
-          keys[0].name="MINSTD";              keys[1].name="MEDSTD";
-          keys[0].type=GAL_TYPE_FLOAT32;      keys[1].type=GAL_TYPE_FLOAT32;
-          keys[0].array=&minstd;              keys[1].array=&p->medstd;
+          keys[0].name="MINSTD";          keys[1].name="MEDSTD";
+          keys[0].type=GAL_TYPE_FLOAT32;  keys[1].type=GAL_TYPE_FLOAT32;
+          keys[0].array=&minstd;          keys[1].array=&p->medstd;
           gal_fits_key_read(p->usedstdfile, p->stdhdu, keys, 0, 0);
 
           /* If the two keywords couldn't be read. We don't want to slow
@@ -1539,8 +1572,10 @@ ui_preparations_both_names(struct mkcatalogparams *p)
      file. */
   if(p->cp.tableformat==GAL_TABLE_FORMAT_TXT)
     {
-      p->objectsout=gal_checkset_automatic_output(&p->cp, basename, "_o.txt");
-      p->clumpsout=gal_checkset_automatic_output(&p->cp, basename, "_c.txt");
+      p->objectsout=gal_checkset_automatic_output(&p->cp, basename,
+                                                  "_o.txt");
+      p->clumpsout=gal_checkset_automatic_output(&p->cp, basename,
+                                                 "_c.txt");
     }
   else
     {
@@ -1555,7 +1590,8 @@ ui_preparations_both_names(struct mkcatalogparams *p)
                                        p->cp.dontdelete);
         }
       else
-        p->objectsout=gal_checkset_automatic_output(&p->cp, basename, suffix);
+        p->objectsout=gal_checkset_automatic_output(&p->cp, basename,
+                                                    suffix);
       p->clumpsout=p->objectsout;
     }
 
@@ -1607,7 +1643,8 @@ ui_preparations_outnames(struct mkcatalogparams *p)
         {
           suffix = ( p->cp.tableformat==GAL_TABLE_FORMAT_TXT
                      ? "_cat.txt" : "_cat.fits" );
-          p->objectsout=gal_checkset_automatic_output(&p->cp, p->objectsfile,
+          p->objectsout=gal_checkset_automatic_output(&p->cp,
+                                                      p->objectsfile,
                                                       suffix);
         }
     }
@@ -1643,91 +1680,6 @@ ui_preparations_outnames(struct mkcatalogparams *p)
 
 
 
-/* When a spectrum is requested, the slice information (slice number and
-   slice WCS) is common to all different spectra. So instead of calculating
-   it every time, we'll just make it once here, then copy it for every
-   object.
-
-   The Slice information is going to be written in every spectrum. So we
-   don't want it to take too much space. Therefore, only when the number of
-   slices is less than 65535 (2^16-1), will we actually use a 32-bit
-   integer type for the slice number column.
-*/
-static void
-ui_preparations_spectrum_wcs(struct mkcatalogparams *p)
-{
-  double *xarr, *yarr, *zarr;
-  gal_data_t *x, *y, *z, *coords;
-  size_t i, numslices=p->objects->dsize[0];
-  size_t slicenumtype=numslices>=65535 ? GAL_TYPE_UINT32 : GAL_TYPE_UINT16;
-
-  /* A small sanity check. */
-  if(p->objects->ndim!=3)
-    error(EXIT_FAILURE, 0, "%s (hdu %s) is a %zuD dataset, but '--spectrum' "
-          "is currently only defined on 3D datasets", p->objectsfile,
-          p->cp.hdu, p->objects->ndim);
-
-  /* Allocate space for the slice number as well as the X and Y positions
-     for WCS conversion. Note that the 'z' axis is going to be converted to
-     WCS later, so we'll just give it the basic information now.*/
-  x=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &numslices, NULL, 0,
-                   p->cp.minmapsize, p->cp.quietmmap, NULL, NULL, NULL);
-  y=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &numslices, NULL, 0,
-                   p->cp.minmapsize, p->cp.quietmmap, NULL, NULL, NULL);
-  z=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &numslices, NULL, 0,
-                   p->cp.minmapsize, p->cp.quietmmap, p->ctype[2],
-                   p->objects->wcs->cunit[2], "Slice WCS coordinates.");
-
-  /* Write values into the 3 coordinates. */
-  xarr=x->array; yarr=y->array; zarr=z->array;
-  for(i=0;i<numslices;++i) { zarr[i]=i+1; xarr[i]=yarr[i]=1; }
-
-
-  /* Convert the coordinates to WCS. We are doing this inplace to avoid too
-     much memory/speed consumption. */
-  coords=x;
-  coords->next=y;
-  coords->next->next=z;
-  gal_wcs_img_to_world(coords, p->objects->wcs, 1);
-
-  /* For a check.
-  for(i=0;i<numslices;++i)
-    printf("%g, %g, %g\n", xarr[i], yarr[i], zarr[i]);
-  exit(0);
-  */
-
-  /* Allocate the slice counter array (we are doing it again because we
-     want it to be in integer type now). */
-  p->specsliceinfo=gal_data_alloc(NULL, slicenumtype, 1, &numslices, NULL, 0,
-                                  p->cp.minmapsize, p->cp.quietmmap, "SLICE",
-                                  "counter",
-                                  "Slice number in cube (counting from 1).");
-  if(p->specsliceinfo->type==GAL_TYPE_UINT16)
-    for(i=0;i<numslices;++i) ((uint16_t *)(p->specsliceinfo->array))[i]=i+1;
-  else
-    for(i=0;i<numslices;++i) ((uint32_t *)(p->specsliceinfo->array))[i]=i+1;
-
-  /* Set the slice WCS column information. Note that 'z' is now the WCS
-     coordinate value of the third dimension, and to avoid wasting extra
-     space (this column is repeated one very object's spectrum), we'll
-     convert it to a 32-bit floating point dataset. */
-  p->specsliceinfo->next=gal_data_copy_to_new_type(z, GAL_TYPE_FLOAT32);
-
-  /* For a final check.
-  gal_table_write(p->specsliceinfo, NULL, NULL, GAL_TABLE_FORMAT_BFITS,
-                  "specsliceinfo.fits", "test-debug", 0);
-  */
-
-  /* Clean up. */
-  gal_data_free(x);
-  gal_data_free(y);
-  gal_data_free(z);
-}
-
-
-
-
-
 /* Sanity checks and preparations for the upper-limit magnitude. */
 static void
 ui_preparations_upperlimit(struct mkcatalogparams *p)
@@ -1740,8 +1692,8 @@ ui_preparations_upperlimit(struct mkcatalogparams *p)
     {
       for(i=0;p->uprange[i]!=-1;++i) ++c;
       if(c!=p->objects->ndim)
-        error(EXIT_FAILURE, 0, "%zu values given to '--uprange', but input "
-              "has %zu dimensions", c, p->objects->ndim);
+        error(EXIT_FAILURE, 0, "%zu values given to '--uprange', but "
+              "input has %zu dimensions", c, p->objects->ndim);
     }
 
   /* Check the number of random samples. */
@@ -1786,7 +1738,7 @@ void
 ui_preparations(struct mkcatalogparams *p)
 {
   /* If no columns are requested, then inform the user. */
-  if(p->columnids==NULL && p->spectrum==0)
+  if(p->columnids==NULL)
     error(EXIT_FAILURE, 0, "no measurements requested! Please run again "
           "with '--help' for the possible list of measurements");
 
@@ -1816,14 +1768,6 @@ ui_preparations(struct mkcatalogparams *p)
   ui_preparations_outnames(p);
 
 
-  /* If a spectrum is requested, generate the two WCS columns. */
-  if(p->spectrum)
-    {
-      ui_preparations_spectrum_wcs(p);
-      p->spectra=gal_data_array_calloc(p->numobjects);
-    }
-
-
   /* Allocate the reference random number generator and seed values. It
      will be cloned once for every thread. If the user hasn't called
      'envseed', then we want it to be different for every run, so we need
@@ -1875,7 +1819,8 @@ ui_preparations(struct mkcatalogparams *p)
 /**************************************************************/
 
 void
-ui_read_check_inputs_setup(int argc, char *argv[], struct mkcatalogparams *p)
+ui_read_check_inputs_setup(int argc, char *argv[],
+                           struct mkcatalogparams *p)
 {
   char *tmp;
   struct gal_options_common_params *cp=&p->cp;
@@ -1960,7 +1905,8 @@ ui_read_check_inputs_setup(int argc, char *argv[], struct 
mkcatalogparams *p)
           else
             printf("  - Sky: %s (hdu: %s)\n", p->usedskyfile, p->skyhdu);
           if(p->subtractsky)
-            printf("    - Sky has been subtracted from values internally.\n");
+            printf("    - Sky has been subtracted from values "
+                   "internally.\n");
         }
 
       if(p->std)
@@ -2010,7 +1956,7 @@ ui_read_check_inputs_setup(int argc, char *argv[], struct 
mkcatalogparams *p)
 void
 ui_free_report(struct mkcatalogparams *p, struct timeval *t1)
 {
-  size_t d, i;
+  size_t d;
 
   /* The temporary arrays for WCS coordinates. */
   if(p->wcs_vo ) gal_list_data_free(p->wcs_vo);
@@ -2059,27 +2005,10 @@ ui_free_report(struct mkcatalogparams *p, struct 
timeval *t1)
   if(p->outlabs) free(p->outlabs);
   gal_list_data_free(p->clumpcols);
   gal_list_data_free(p->objectcols);
-  gal_list_data_free(p->specsliceinfo);
   if(p->outlabsinv) free(p->outlabsinv);
   if(p->upcheckout) free(p->upcheckout);
   gal_data_array_free(p->tiles, p->numobjects, 0);
 
-  /* Clean up the spectra. */
-  if(p->spectra)
-    {
-      /* Note that each element of the array is the first node in a list of
-         datasets. So we can't free the first one with
-         'gal_list_data_free', we'll delete all the nodes after it in the
-         loop. */
-      for(i=0;i<p->numobjects;++i)
-        {
-          gal_list_data_free( p->spectra[i].next );
-          p->spectra[i].next=NULL;
-          gal_data_free_contents(&p->spectra[i]);
-        }
-      gal_data_array_free(p->spectra, p->numobjects, 0);
-    }
-
   /* If the Sky or its STD image were given in tiles, then we defined a
      tile structure to deal with them. The initialization of the tile
      structure is checked with its 'ndim' element. */
diff --git a/bin/mkcatalog/ui.h b/bin/mkcatalog/ui.h
index 5028db01..c28bda7a 100644
--- a/bin/mkcatalog/ui.h
+++ b/bin/mkcatalog/ui.h
@@ -42,6 +42,7 @@ enum program_args_groups
   UI_GROUP_COLUMNS_SURFACEBRIGHTNESS,
   UI_GROUP_COLUMNS_MORPHOLOGY,
   UI_GROUP_COLUMNS_ELLIPTICAL,
+  UI_GROUP_COLUMNS_VECTOR,
 };
 
 
@@ -197,6 +198,17 @@ enum option_keys_enum
   UI_KEY_FRACMAX2AREA,
   UI_KEY_FRACMAX1RADIUS,
   UI_KEY_FRACMAX2RADIUS,
+
+  /* Vector columns */
+  UI_KEY_SUMINSLICE,
+  UI_KEY_SUMERRINSLICE,
+  UI_KEY_AREAINSLICE,
+  UI_KEY_SUMPROJINSLICE,
+  UI_KEY_AREAPROJINSLICE,
+  UI_KEY_SUMPROJERRINSLICE,
+  UI_KEY_AREAOTHERINSLICE,
+  UI_KEY_SUMOTHERINSLICE,
+  UI_KEY_SUMOTHERERRINSLICE,
 };
 
 
diff --git a/bin/noisechisel/astnoisechisel-3d.conf 
b/bin/noisechisel/astnoisechisel-3d.conf
index eebed947..336478f7 100644
--- a/bin/noisechisel/astnoisechisel-3d.conf
+++ b/bin/noisechisel/astnoisechisel-3d.conf
@@ -24,8 +24,8 @@
 
 # Tessellation
  numchannels        1,1,1
- tilesize         15,15,15
- largetilesize    50,50,50
+ tilesize          15,15,5
+ largetilesize    50,50,15
 
 # Detection:
  meanmedqdiff        0.005
diff --git a/bin/script/fits-view.in b/bin/script/fits-view.in
index a04e0151..346caa52 100644
--- a/bin/script/fits-view.in
+++ b/bin/script/fits-view.in
@@ -404,11 +404,18 @@ else
             # Open DS9 based on the number of dimension.
             if [ "$ndim" = 2 ]; then
 
+                # If a HDU is specified, ignore other HDUs (recall that
+                # with '-mecube' we are viewing all the HDUs as a single
+                # cube.
+                if [ x"$hdu" = x ]; then mecube="-mecube";
+                else                     mecube="";
+                fi
+
                 # 2D multi-extension file: use the "Cube" window to
                 # flip/slide through the extensions.
                 execom="$ds9exec $ds9scaleopt \
                                  $ds9geoopt \
-                                 -mecube \
+                                 $mecube \
                                  $inwithhdu \
                                  -zoom to fit \
                                  -wcs degrees \
@@ -423,6 +430,11 @@ else
                                  $ds9extra"
             else
 
+                # If a HDU is given, don't use multi-frame.
+                if [ x"$hdu" = x ]; then mframe="-multiframe";
+                else                     mframe="";
+                fi
+
                 # 3D multi-extension file: The "Cube" window will slide
                 # between the slices of a single extension. To flip through
                 # the extensions (not the slices), press the top row
@@ -432,7 +444,7 @@ else
                 # the same slice).
                 execom="$ds9exec $ds9scaleopt \
                                  $ds9geoopt -wcs degrees \
-                                 -multiframe \
+                                 $mframe \
                                  $inwithhdu \
                                  -lock slice image \
                                  -lock frame image \
diff --git a/bin/segment/astsegment-3d.conf b/bin/segment/astsegment-3d.conf
index 4c949995..402f9d8a 100644
--- a/bin/segment/astsegment-3d.conf
+++ b/bin/segment/astsegment-3d.conf
@@ -28,8 +28,8 @@
 
 # Tessellation
  numchannels      1,1,1
- tilesize       15,15,15
- largetilesize  50,50,50
+ tilesize        15,15,5
+ largetilesize  50,50,15
 
 # Segmentation
  snminarea            15
diff --git a/bin/statistics/ui.c b/bin/statistics/ui.c
index 8f1a7cc5..d2b618b1 100644
--- a/bin/statistics/ui.c
+++ b/bin/statistics/ui.c
@@ -853,7 +853,7 @@ ui_read_columns_in_one(struct statisticsparams *p)
 
       /* Read the different comma-separated strings into an array (within a
          'gal_data_t'). */
-      strs=gal_options_parse_csv_strings_raw(tmp->v, NULL, 0);
+      strs=gal_options_parse_csv_strings_to_data(tmp->v, NULL, 0);
       strarr=strs->array;
 
       /* Add each array element to the final list of columns. */
diff --git a/bin/table/args.h b/bin/table/args.h
index 4c84c765..03150a60 100644
--- a/bin/table/args.h
+++ b/bin/table/args.h
@@ -42,7 +42,8 @@ struct argp_option program_options[] =
       GAL_TYPE_STRLL,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_csv_strings_append
     },
     {
       "wcsfile",
@@ -237,6 +238,30 @@ struct argp_option program_options[] =
 
 
 
+    /* Operation precendence */
+    {
+      0, 0, 0, 0,
+      "Precedence (default: column operations first)",
+      UI_GROUP_PRECEDENCE
+    },
+    {
+      "rowfirst",
+      UI_KEY_ROWFIRST,
+      0,
+      0,
+      "Apply row-based operations first.",
+      UI_GROUP_PRECEDENCE,
+      &p->rowfirst,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
+
+
+
+
+
     /* Output columns. */
     {
       0, 0, 0, 0,
@@ -259,9 +284,9 @@ struct argp_option program_options[] =
     {
       "colmetadata",
       UI_KEY_COLMETADATA,
-      "STR,STR[,STR,STR]",
+      "ID,S,S,S",
       0,
-      "Column metadata (name, unit, comments).",
+      "Column metadata (S=STR: Name, Unit, Comments).",
       UI_GROUP_OUTCOLS,
       &p->colmetadata,
       GAL_TYPE_STRING,
@@ -310,7 +335,19 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
-
+    {
+      "transpose",
+      UI_KEY_TRANSPOSE,
+      0,
+      0,
+      "Transpose table (must only contain vector cols).",
+      UI_GROUP_OUTCOLS,
+      &p->transpose,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
 
 
 
diff --git a/bin/table/arithmetic.c b/bin/table/arithmetic.c
index 5885f871..edb323c0 100644
--- a/bin/table/arithmetic.c
+++ b/bin/table/arithmetic.c
@@ -37,6 +37,8 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro-internal/arithmetic-set.h>
 
 #include "main.h"
+
+#include "ui.h"
 #include "arithmetic.h"
 
 
@@ -375,7 +377,7 @@ arithmetic_indexs_final(struct tableparams *p)
   p->colarray=gal_list_data_to_array_ptr(p->table, &p->numcolarray);
 
   /* go over each package of columns. */
-  for(tmp=p->outcols;tmp!=NULL;tmp=tmp->next)
+  for(tmp=p->colpack;tmp!=NULL;tmp=tmp->next)
     {
       /* If we are on an arithmetic operation. */
       if(tmp->arith)
@@ -1240,7 +1242,7 @@ arithmetic_operate(struct tableparams *p)
   p->table=NULL;
 
   /* Go over each package of columns. */
-  for(outpack=p->outcols; outpack!=NULL; outpack=outpack->next)
+  for(outpack=p->colpack; outpack!=NULL; outpack=outpack->next)
     {
       if(outpack->arith)
         arithmetic_reverse_polish(p, outpack);
@@ -1255,4 +1257,10 @@ arithmetic_operate(struct tableparams *p)
      column contents have either been moved into the new table, or have
      already been freed. */
   gal_list_data_reverse(&p->table);
+
+  /* Clean up. */
+  ui_colpack_free(p->colpack);
+  if(p->colarray) free(p->colarray);
+  p->colarray=NULL;
+  p->colpack=NULL;
 }
diff --git a/bin/table/main.h b/bin/table/main.h
index c0f812a6..8567de01 100644
--- a/bin/table/main.h
+++ b/bin/table/main.h
@@ -76,7 +76,7 @@ struct arithmetic_token
   struct arithmetic_token *next;  /* Pointer to next token.               */
 };
 
-/*  */
+/* For arithmetic operations. */
 struct column_pack
 {
   size_t                    start; /* Starting ind. in requested columns. */
@@ -100,6 +100,7 @@ struct tableparams
   gal_list_str_t     *columns;  /* List of given columns.               */
   uint8_t         information;  /* ==1: only print FITS information.    */
   uint8_t     colinfoinstdout;  /* ==1: print column metadata in CL.    */
+  uint8_t            rowfirst;  /* Do row-based operations first.       */
   gal_data_t           *range;  /* Range to limit output.               */
   gal_data_t       *inpolygon;  /* Columns to check if inside polygon.  */
   gal_data_t      *outpolygon;  /* Columns to check if outside polygon. */
@@ -122,6 +123,7 @@ struct tableparams
   gal_data_t      *fromvector;  /* Extract columns from a vector column.*/
   uint8_t         keepvectfin;  /* Keep in.s --tovector & --fromvector. */
   gal_list_str_t    *tovector;  /* Merge columns into a vector column.  */
+  uint8_t           transpose;  /* Transpose vector columns.            */
   gal_list_str_t  *catrowfile;  /* Filename to concat column wise.      */
   gal_list_str_t   *catrowhdu;  /* HDU/extension for the catcolumn.     */
   gal_data_t     *colmetadata;  /* Set column metadata.                 */
@@ -132,7 +134,7 @@ struct tableparams
   int         txtf64precision;  /* Precision of float32 in text.        */
 
   /* Internal. */
-  struct column_pack *outcols;  /* Output column packages.              */
+  struct column_pack *colpack;  /* Output column packages.              */
   gal_data_t         *noblank;  /* Remove rows that have blank.         */
   gal_data_t           *table;  /* Linked list of output table columns. */
   struct wcsprm          *wcs;  /* WCS structure for conversion.        */
diff --git a/bin/table/table.c b/bin/table/table.c
index ff1ece15..30011aa1 100644
--- a/bin/table/table.c
+++ b/bin/table/table.c
@@ -430,11 +430,11 @@ static void
 table_select_by_value(struct tableparams *p)
 {
   gal_data_t *rowids;
+  size_t i, *s, ngood=0;
   struct list_select *tmp;
   uint8_t *u, *uf, *ustart;
-  size_t i, *s, ngood=0;
   int inplace=GAL_ARITHMETIC_FLAG_INPLACE;
-  gal_data_t *mask, *blmask, *addmask=NULL;
+  gal_data_t *mask, *col, *blmask, *addmask=NULL;
 
   /* It may happen that the input table is empty! In such cases, just
      return and don't bother with this step. */
@@ -442,13 +442,14 @@ table_select_by_value(struct tableparams *p)
     return;
 
   /* Allocate datasets for the necessary numbers and write them in. */
-  mask=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, p->table->dsize, NULL, 1,
-                      p->cp.minmapsize, p->cp.quietmmap, NULL, NULL, NULL);
+  mask=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &p->table->dsize[0],
+                      NULL, 1, p->cp.minmapsize, p->cp.quietmmap,
+                      NULL, NULL, NULL);
 
   /* Go over each selection criteria and remove the necessary elements. */
   for(tmp=p->selectcol;tmp!=NULL;tmp=tmp->next)
     {
-      /* Make sure the input isn't a vector column. */
+      /* Make sure the selection column isn't a vector column. */
       if(tmp->col->ndim!=1)
         error(EXIT_FAILURE, 0, "row selection by value (for example with "
               "'--range', '--inpolygon', '--equal' or '--noblank') is "
@@ -456,6 +457,19 @@ table_select_by_value(struct tableparams *p)
               "this feature, please get in touch with us at '%s' to add "
               "it", PACKAGE_BUGREPORT);
 
+      /* Make sure all the to-be-used table columns at this point have the
+         same number of rows as the selection column (can be different when
+         transposing). */
+      for(col=p->table;col!=NULL;col=col->next)
+        if(tmp->col->dsize[0]!=col->dsize[0])
+          error(EXIT_FAILURE, 0, "the number of rows in the column given "
+                "for selection by value (for example '--range' or '--equal') "
+                "is not the same as the number of rows in the table when "
+                "they are applied. This may happen due to operators like "
+                "'--transpose'. In such cases, you probably want row-based "
+                "operators to have precedence over column-based operators. "
+                "If this is your case, please call '--rowfirst'");
+
       /* Do the specific type of selection. */
       switch(tmp->type)
         {
@@ -911,6 +925,42 @@ table_catcolumn(struct tableparams *p)
 
 
 
+static void
+table_transpose(struct tableparams *p)
+{
+  gal_data_t *tmp;
+  size_t refwidth=p->table->dsize[1];
+
+  /* Temporary error. */
+  if(p->colpack)
+    error(EXIT_FAILURE, 0, "'--transpose' is currently not supported "
+          "with Column Arithmetic. Please pipe the transposed table "
+          "into a new 'asttable' command for doing column arithmetic "
+          "on the new columns");
+
+  /* Basic sanity checks and counting of final output columns. */
+  for(tmp=p->table; tmp!=NULL; tmp=tmp->next)
+    {
+      /* Inputs should be vectors. */
+      if(tmp->ndim!=2)
+        error(EXIT_FAILURE, 0, "only vector columns should be present "
+              "in the table when using '--transpose'");
+      if(tmp->dsize[1] != refwidth)
+        error(EXIT_FAILURE, 0, "all vector columns given to '--transpose' "
+              "should have the same length (number of tokens/elements)");
+
+      /* Apply the transposition. */
+      gal_permutation_transpose_2d(tmp);
+
+      /* Remove extra dimensions if necessary. */
+      if(tmp->dsize[1]==1) tmp->ndim=1;
+    }
+}
+
+
+
+
+
 static void
 table_fromvector(struct tableparams *p)
 {
@@ -925,12 +975,17 @@ table_fromvector(struct tableparams *p)
       vector=gal_list_data_select_by_id(p->table, tmp->name, NULL);
       if(vector==NULL) table_error_no_column("--fromvector", tmp->name);
 
+      /* If we don't need this vector column any more, remove it from the
+         table. */
+      if(p->keepvectfin==0) gal_list_data_remove(&p->table, vector);
+
       /* Make sure the selected column is actually a vector. */
       if(vector->ndim!=2)
         error(EXIT_FAILURE, 0, "column '%s' (given to '--fromvector') "
               "is not a vector", tmp->name);
 
       /* Loop over the values and make sure they are within the range. */
+      indexs=NULL;
       iarr=tmp->array;
       for(i=0;i<tmp->size;++i)
         {
@@ -959,16 +1014,10 @@ table_fromvector(struct tableparams *p)
       ext=gal_table_col_vector_extract(vector, indexs);
       gal_list_data_last(p->table)->next=ext;
 
-      /* Remove the vector column (if requested). */
-      if(p->keepvectfin==0)
-        {
-          gal_list_data_remove(&p->table, vector);
-          gal_data_free(vector);
-        }
+      /* Clean up (remove the vector column, if requested). */
+      gal_list_sizet_free(indexs);
+      if(p->keepvectfin==0) gal_data_free(vector);
     }
-
-  /* Clean up. */
-  gal_list_sizet_free(indexs);
 }
 
 
@@ -987,7 +1036,7 @@ table_tovector(struct tableparams *p)
   for(tstr=p->tovector;tstr!=NULL;tstr=tstr->next)
     {
       /* Extract the separate csv. */
-      ids=gal_options_parse_csv_strings_raw(tstr->v, NULL, 0);
+      ids=gal_options_parse_csv_strings_to_data(tstr->v, NULL, 0);
 
       /* Allocate an array of dataset pointers to keep the columns that
          should be removed. */
@@ -1493,7 +1542,7 @@ table_txt_formats(struct tableparams *p)
 /***************       Top function         *******************/
 /**************************************************************/
 void
-table(struct tableparams *p)
+table_column(struct tableparams *p)
 {
   /* Concatenate the columns of tables (if required). */
   if(p->catcolumnfile) table_catcolumn(p);
@@ -1501,6 +1550,20 @@ table(struct tableparams *p)
   /* Extract columns from vector. */
   if(p->fromvector) table_fromvector(p);
 
+  /* Merge columns into a vector column. */
+  if(p->tovector) table_tovector(p);
+
+  /* If any arithmetic operations are needed, do them. */
+  if(p->colpack) arithmetic_operate(p);
+}
+
+
+
+
+
+void
+table_row(struct tableparams *p)
+{
   /* Concatenate the rows of multiple tables (if required). */
   if(p->catrowfile) table_catrows(p);
 
@@ -1511,23 +1574,29 @@ table(struct tableparams *p)
   if(p->sort) table_sort(p);
 
   /* If the output number of rows is limited, apply them. */
-  if( p->rowrange
+  if(    p->rowrange
       || p->rowrandom
       || p->head!=GAL_BLANK_SIZE_T
       || p->tail!=GAL_BLANK_SIZE_T )
     table_select_by_position(p);
 
-  /* If any arithmetic operations are needed, do them. */
-  if(p->outcols)
-    arithmetic_operate(p);
+  /* Transpose the input table. */
+  if(p->transpose) table_transpose(p);
+}
+
 
-  /* Merge columns into a vector column. */
-  if(p->tovector) table_tovector(p);
 
-  /* When column metadata should be updated. */
-  if(p->colmetadata) table_colmetadata(p);
 
-  /* When any columns with blanks should be removed. */
+
+void
+table(struct tableparams *p)
+{
+  /* Do the requested operations. */
+  if(p->rowfirst) { table_row(p);    table_column(p); }
+  else            { table_column(p); table_row(p);    }
+
+  /* Last steps (independent of '--rowfirst'). */
+  if(p->colmetadata) table_colmetadata(p);
   if(p->noblankend) table_noblankend(p);
 
   /* Write the output or a warning/error (it can become NULL!) */
diff --git a/bin/table/ui.c b/bin/table/ui.c
index 28b064b2..09c7b07d 100644
--- a/bin/table/ui.c
+++ b/bin/table/ui.c
@@ -66,14 +66,15 @@ static char
 args_doc[] = "ASTRdata";
 
 const char
-doc[] = GAL_STRINGS_TOP_HELP_INFO PROGRAM_NAME" can be used to view the "
-  "information, select columns, or convert tables. The inputs and outputs "
-  "can be plain text (with white-space or comma as delimiters), FITS ascii, "
-  "or FITS binary tables. The output columns can either be selected by "
-  "number (counting from 1), name or using regular expressions. For regular "
-  "expressions, enclose the value to the '--column' ('-c') option in "
-  "slashes ('\\', as in '-c\\^mag\\'). To print the selected columns on the "
-  "command-line, don't specify an output file.\n"
+doc[] = GAL_STRINGS_TOP_HELP_INFO PROGRAM_NAME" can be used to view "
+  "the information, select columns, or convert tables. The inputs and "
+  "outputs can be plain text (with white-space or comma as delimiters), "
+  "FITS ascii, or FITS binary tables. The output columns can either be "
+  "selected by number (counting from 1), name or using regular "
+  "expressions. For regular expressions, enclose the value to the "
+  "'--column' ('-c') option in slashes ('\\', as in '-c\\^mag\\'). "
+  "To print the selected columns on the command-line, don't specify "
+  "an output file.\n"
   GAL_STRINGS_MORE_HELP_INFO
   /* After the list of options: */
   "\v"
@@ -516,9 +517,9 @@ ui_list_select_free(struct list_select *list, int freevalue)
 /**************************************************************/
 /***************      Packaged columns      *******************/
 /**************************************************************/
-/* Return the last outcols element. */
+/* Return the last 'colpack' element. */
 static struct column_pack *
-ui_outcols_last(struct column_pack *list)
+ui_colpack_last(struct column_pack *list)
 {
   if(list)
     {
@@ -535,7 +536,7 @@ ui_outcols_last(struct column_pack *list)
 /* Allocate a clean 'out_columns' structure and put it at the top of the
    list. */
 static struct column_pack *
-ui_outcols_add_new_to_end(struct column_pack **list)
+ui_colpack_add_new_to_end(struct column_pack **list)
 {
   struct column_pack *last, *node;
 
@@ -556,7 +557,7 @@ ui_outcols_add_new_to_end(struct column_pack **list)
      add this node. */
   if(*list)
     {
-      last=ui_outcols_last(*list);
+      last=ui_colpack_last(*list);
       last->next=node;
     }
   else
@@ -570,8 +571,8 @@ ui_outcols_add_new_to_end(struct column_pack **list)
 
 
 
-static void
-ui_outcols_free(struct column_pack *list)
+void
+ui_colpack_free(struct column_pack *list)
 {
   struct column_pack *tmp;
   while(list!=NULL)
@@ -661,118 +662,112 @@ static void
 ui_columns_prepare(struct tableparams *p, gal_list_str_t *lines)
 {
   int tableformat;
-  gal_data_t *strs;
-  char *c, **strarr;
   gal_data_t *colinfo=NULL;
   struct column_pack *node, *last;
   gal_list_str_t *tmp, *colstoread=NULL;
-  size_t i, totcalled=0, numcols, numrows;
+  size_t i, totcalled=0, numcols, numrows, numsimple;
+  char *str, countstr[11]; /* an un-signed 32-bit integer takes 10 chars */
 
-  /* Go over the whole original list (where each node may have more than
-     one value separated by a comma. */
+  /* Go over the list of requested columns from the main input. */
   for(tmp=p->columns;tmp!=NULL;tmp=tmp->next)
     {
-      /* Remove any possibly commented new-line where we have a backslash
-         followed by a new-line character (replace the two characters with
-         two single space characters). This can happen with the 'arith'
-         argument in a script, when it gets long (bug #58371). But to be
-         general in other cases too, we'll just correct it here. */
-      for(c=tmp->v;*c!='\0';++c)
-        if(*c=='\\' && *(c+1)=='\n') { *c=' '; *(++c)=' '; }
-
-      /* Read the different comma-separated strings into an array (within a
-         'gal_data_t'). */
-      strs=gal_options_parse_csv_strings_raw(tmp->v, NULL, 0);
-      strarr=strs->array;
-
-      /* Go over all the given colum names/numbers. */
-      for(i=0;i<strs->size;++i)
+      /* For easy reading. */
+      str=tmp->v;
+
+      /* If this is an arithmetic column.  */
+      if(!strncmp(str, 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 'colpack'
+             structure, then add this arithmetic operation's 'colpack'. */
+          if(p->colpack==NULL && colstoread)
+            {
+              /* Allocate an empty structure and set the necessary
+                 pointers. */
+              node=ui_colpack_add_new_to_end(&p->colpack);
+              node->start=0;
+              node->numsimple=gal_list_str_number(colstoread);
+              totcalled=node->numsimple;
+            }
+
+          /* Add a new column pack for this arithmetic operation, then read
+             all the tokens (while specifying which columns it needs). */
+          node=ui_colpack_add_new_to_end(&p->colpack);
+          arithmetic_init(p, &node->arith, &colstoread, &totcalled,
+                          str+ARITHMETIC_CALL_LENGTH, colinfo, numcols);
+        }
+
+      /* This is a simple column (no change in values). */
+      else
         {
-          /* 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))
+          /* If the value is '_all', then we should add all the input's
+             columns. Otherwise, just add this string. */
+          if( !strcmp(str, "_all") )
             {
-              /* 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. */
+              /* Load column information (it not already loaded). */
               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 && colstoread)
+                                       &numcols, &numrows,
+                                       &tableformat);
+
+              /* Add all the input column counters to the list of columns
+                 to read */
+              numsimple=gal_list_data_number(colinfo);
+              for(i=0;i<numsimple;++i)
                 {
-                  /* 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(colstoread);
-                  totcalled=node->numsimple;
+                  sprintf(countstr, "%u", (uint32_t)(i+1));
+                  gal_list_str_add(&colstoread, countstr, 1);
                 }
-
-              /* 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, &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(&colstoread, strarr[i], 0);
+              numsimple=1;
+              gal_list_str_add(&colstoread, str, 1);
+            }
 
-              /* See if we have packaged the output columns. */
-              if(p->outcols)
+          /* See if we have packaged the output columns. */
+          if(p->colpack)
+            {
+              /* If the previous column package was an arithmetic
+                 operation, allocate a new node. */
+              last=ui_colpack_last(p->colpack);
+              if(last->arith)
                 {
-                  /* If the previous column package was an arithmetic
-                     operation, allocate a new node. */
-                  last=ui_outcols_last(p->outcols);
-                  if(last->arith)
-                    {
-                      node=ui_outcols_add_new_to_end(&p->outcols);
-                      node->start=totcalled;
-                      node->numsimple=1;
-                    }
-
-                  /* The previous package of columns are simple (we don't
-                     need to change their value), so we can just increment
-                     the number of columns there and don't need to allocate
-                     a new one. */
-                  else
-                    last->numsimple+=1;
+                  node=ui_colpack_add_new_to_end(&p->colpack);
+                  node->start=totcalled;
+                  node->numsimple=numsimple;
                 }
 
-              /* Increment the total number of called columns. */
-              totcalled+=1;
+              /* The previous package of columns are simple (we don't need
+                 to change their value), so we can just increment the
+                 number of columns there and don't need to allocate a new
+                 one. */
+              else
+                last->numsimple+=numsimple;
             }
 
-          /* The pointer allocated string is either being used (and later
-             freed) else, or has already been freed. So its necessary to
-             set it to NULL. */
-          strarr[i]=NULL;
+          /* Increment the total number of called columns. */
+          totcalled+=1;
         }
-
-      /* Clean up. */
-      gal_data_free(strs);
     }
 
   /* For a check
-  if(p->outcols)
+  if(p->colpack)
     {
       struct column_pack *tmp;
       struct arithmetic_token *atmp;
-      for(tmp=p->outcols;tmp!=NULL;tmp=tmp->next)
+      for(tmp=p->colpack;tmp!=NULL;tmp=tmp->next)
         if(tmp->arith)
           {
             printf("Arithmetic: \n");
@@ -920,8 +915,8 @@ ui_check_select_sort_before(struct tableparams *p, 
gal_list_str_t *lines,
   if(p->inpolygon)
     {
       strarr=p->inpolygon->array;
-      inpolytmp=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &one, NULL, 1, -1, 1,
-                               strarr[0], NULL, NULL);
+      inpolytmp=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &one, NULL, 1,
+                               -1, 1, strarr[0], NULL, NULL);
       inpolytmp->next=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &one, NULL,
                                      1, -1, 1, strarr[1], NULL, NULL);
       select[SELECT_TYPE_INPOLYGON]=inpolytmp;
@@ -929,8 +924,8 @@ ui_check_select_sort_before(struct tableparams *p, 
gal_list_str_t *lines,
   if(p->outpolygon)
     {
       strarr=p->outpolygon->array;
-      outpolytmp=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &one, NULL, 1, -1, 1,
-                               strarr[0], NULL, NULL);
+      outpolytmp=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &one, NULL,
+                                1, -1, 1, strarr[0], NULL, NULL);
       outpolytmp->next=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &one, NULL,
                                      1, -1, 1, strarr[1], NULL, NULL);
       select[SELECT_TYPE_OUTPOLYGON]=outpolytmp;
@@ -1107,7 +1102,8 @@ ui_check_select_sort_before(struct tableparams *p, 
gal_list_str_t *lines,
       for(k=0;k<SELECT_TYPE_NUMBER;++k)
         for(dtmp=select[k];dtmp!=NULL;dtmp=dtmp->next)
           {
-            if(*sortindout!=GAL_BLANK_SIZE_T && selectindout[i]==*sortindout)
+            if(  *sortindout!=GAL_BLANK_SIZE_T
+               && selectindout[i]==*sortindout)
               {
                 selecttypeout[i]=k;
                 selectindout[i]=*sortindout;
@@ -1262,12 +1258,13 @@ ui_preparations(struct tableparams *p)
      extra columns. */
   if(p->selection || p->sort)
     ui_check_select_sort_before(p, lines, &nselect, &origoutncols,
-                                &sortindout, &selectindout, &selecttypeout);
+                                &sortindout, &selectindout,
+                                &selecttypeout);
 
 
   /* If we have any arithmetic operations, we need to make sure how many
      columns match every given column name. */
-  p->colmatch = ( p->outcols
+  p->colmatch = ( p->colpack
                   ? gal_pointer_allocate(GAL_TYPE_SIZE_T,
                                          gal_list_str_number(p->columns),
                                          1, __func__, "p->colmatch")
@@ -1428,13 +1425,11 @@ ui_free_report(struct tableparams *p)
   /* Free the allocated arrays: */
   free(p->cp.hdu);
   free(p->cp.output);
-  ui_outcols_free(p->outcols);
   gal_list_data_free(p->table);
   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);
   gal_list_str_free(p->catcolumnfile, 1);
diff --git a/bin/table/ui.h b/bin/table/ui.h
index b2cda224..445b1a07 100644
--- a/bin/table/ui.h
+++ b/bin/table/ui.h
@@ -33,7 +33,8 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 /* Option groups particular to this program. */
 enum program_args_groups
 {
-  UI_GROUP_OUTCOLS = GAL_OPTIONS_GROUP_AFTER_COMMON,
+  UI_GROUP_PRECEDENCE = GAL_OPTIONS_GROUP_AFTER_COMMON,
+  UI_GROUP_OUTCOLS,
   UI_GROUP_OUTROWS,
 };
 
@@ -81,8 +82,10 @@ enum option_keys_enum
   UI_KEY_ENVSEED,
   UI_KEY_ROWRANGE,
   UI_KEY_TOVECTOR,
+  UI_KEY_ROWFIRST,
   UI_KEY_ROWRANDOM,
   UI_KEY_INPOLYGON,
+  UI_KEY_TRANSPOSE,
   UI_KEY_OUTPOLYGON,
   UI_KEY_FROMVECTOR,
   UI_KEY_CATCOLUMNRAWNAME,
@@ -98,6 +101,9 @@ ui_read_check_inputs_setup(int argc, char *argv[], struct 
tableparams *p);
 void
 ui_list_select_free(struct list_select *list, int freevalue);
 
+void
+ui_colpack_free(struct column_pack *list);
+
 void
 ui_free_report(struct tableparams *p);
 
diff --git a/configure.ac b/configure.ac
index 702fd691..60b275ea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -286,7 +286,6 @@ AC_MSG_RESULT( $path_warning )
 has_gsl=yes
 has_libgit2=1
 has_cmath=yes
-with_python=no
 has_wcslib=yes
 has_cfitsio=yes
 has_libtiff=yes
@@ -770,7 +769,7 @@ AS_IF([test "x$has_topcat" = "xno"], [anywarnings=yes])
 AC_ARG_WITH([python],
             [AS_HELP_STRING([--with-python],
                             [enable support for python])],
-            [with_python=yes], [])
+            [], [with_python=no])
 AS_IF([test "x$with_python" == xyes],
       [
         # Variables to simplify commands below.
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 3785e217..fe9d971a 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -272,6 +272,7 @@ Tutorials
 * Detecting large extended targets::  NoiseChisel for huge extended targets.
 * Building the extended PSF::   How to extract an extended PSF from science 
data.
 * Sufi simulates a detection::  Simulating a detection.
+* Detecting lines and extracting spectra in 3D data::  Extracting spectra and 
emission line properties.
 
 General program usage tutorial
 
@@ -318,6 +319,16 @@ Building the extended PSF
 * Uniting the different PSF components::  Merging all the components into one 
PSF.
 * Subtracting the PSF::         Having the PSF, we now want to subtract it.
 
+Detecting lines and extracting spectra in 3D data
+
+* Viewing spectra and redshifted lines::  Interactively see the spectra of an 
object
+* Sky lines in optical IFUs::   How to see sky lines in a cube.
+* Continuum subtraction::       Removing the continuum from a data cube.
+* 3D detection with NoiseChisel::  Finding emission-lines and their spectra.
+* 3D measurements and spectra::  Measuring 3d properties including spectra.
+* Extracting a single spectrum and plotting it::  Extracting a single vector 
row.
+* Pseudo narrow-band images::   Collapsing the third dimension into a 2D image.
+
 Installation
 
 * Dependencies::                Necessary packages for Gnuastro.
@@ -659,7 +670,7 @@ MakeCatalog measurements
 * Surface brightness measurements::  Various ways to measure surface 
brightness.
 * Morphology measurements nonparametric::  Non-parametric morphology.
 * Morphology measurements elliptical::  Elliptical morphology measurements.
-* Spectra measurement in a cube::  How to get the value of a label across all 
slices.
+* Measurements per slice spectra::  Measurements on each slice (like spectra).
 
 Invoking MakeCatalog
 
@@ -718,9 +729,9 @@ High-level calculations
 
 CosmicCalculator
 
-* Distance on a 2D curved space::  Distances in 2D for simplicity
+* Distance on a 2D curved space::  Distances in 2D for simplicity.
 * Extending distance concepts to 3D::  Going to 3D (our real universe).
-* Invoking astcosmiccal::       How to run CosmicCalculator
+* Invoking astcosmiccal::       How to run CosmicCalculator.
 
 Invoking CosmicCalculator
 
@@ -2002,6 +2013,7 @@ For an explanation of the conventions we use in the 
example codes through the bo
 * Detecting large extended targets::  NoiseChisel for huge extended targets.
 * Building the extended PSF::   How to extract an extended PSF from science 
data.
 * Sufi simulates a detection::  Simulating a detection.
+* Detecting lines and extracting spectra in 3D data::  Extracting spectra and 
emission line properties.
 @end menu
 
 
@@ -2329,7 +2341,7 @@ The returned value is @mymath{9.06711} arcmin@mymath{^2}.
 In other words, the image does cover this area, but there is no data in more 
than half of the pixels.
 So let's calculate the area coverage over-which we actually have data.
 
-The FITS world coordinate system (WCS) meta data standard contains the key to 
answering this question.
+The FITS world coordinate system (WCS) metadata standard contains the key to 
answering this question.
 Run the following command to see all the FITS keywords (metadata) for one of 
the images (almost identical with the other images because they are scaled to 
the same region of Sky):
 
 @example
@@ -2346,7 +2358,7 @@ We can thus conclude that the value of @code{CDELT*} is 
in units of degrees-per-
 In the FITS standard the @code{CDELT} keywords are optional.
 When @code{CDELT} keywords are not present, the @code{PC} matrix is assumed to 
contain @emph{both} the coordinate rotation and scales.
 Note that not all FITS writers use the @code{CDELT} convention.
-So you might not find the @code{CDELT} keywords in the WCS meta data of some 
FITS files.
+So you might not find the @code{CDELT} keywords in the WCS metadata of some 
FITS files.
 However, all Gnuastro programs (which use the default FITS keyword writing 
format of WCSLIB) write their output WCS with the @code{CDELT} convention, even 
if the input does not have it.
 If your dataset does not use the @code{CDELT} convention, you can feed it to 
any (simple) Gnuastro program (for example, Arithmetic) and the output will 
have the @code{CDELT} keyword.
 See Section 8 of the 
@url{https://fits.gsfc.nasa.gov/standard40/fits_standard40aa-le.pdf, FITS 
standard} for more}.
@@ -7216,7 +7228,7 @@ Each image or dataset will have its own particularities 
that you will have to ta
 
 
 
-@node Sufi simulates a detection,  , Building the extended PSF, Tutorials
+@node Sufi simulates a detection, Detecting lines and extracting spectra in 3D 
data, Building the extended PSF, Tutorials
 @section Sufi simulates a detection
 
 @cindex Azophi
@@ -7774,12 +7786,886 @@ It was nearly sunset and they had to begin preparing 
for the night's measurement
 
 
 
+@node Detecting lines and extracting spectra in 3D data,  , Sufi simulates a 
detection, Tutorials
+@section Detecting lines and extracting spectra in 3D data
+
+@cindex IFU
+@cindex MUSE
+@cindex ACIS
+@cindex Pixel
+@cindex Voxel
+@cindex Spectrum
+@cindex 3D data cube
+@cindex Integral field unit
+@cindex Cube (3D) spectrums
+@cindex Hyperspectral imaging
+3D data cubes are an increasingly common format of data products in 
observational astronomy.
+As opposed to 2D images (where each 2D ``picture element'' or ``pixel'' covers 
an infinitesimal area on the surface of the sky), 3D data cubes contain 
``volume elements'' or ``voxels'' that are also connected in a third dimension.
+
+The most common case of 3D data in observational astrophysics is when the 
first two dimensions are spatial (RA and Dec on the sky), and the third 
dimension is wavelength.
+This type of data is generically (also outside of astronomy) known as 
Hyperspectral 
imaging@footnote{@url{https://en.wikipedia.org/wiki/Hyperspectral_imaging}}.
+For example high-level data products of Integral Field Units (IFUs) like 
MUSE@footnote{@url{https://en.wikipedia.org/wiki/Multi-unit_spectroscopic_explorer}}
 in the optical, 
ACIS@footnote{@url{https://en.wikipedia.org/wiki/Advanced_CCD_Imaging_Spectrometer}}
 in the X-ray, or in the radio where most data are 3D cubes.
+
+@cindex Abell 370 galaxy cluster
+In this tutorial, we'll use a small crop of a reduced deep MUSE cube centered 
on the @url{https://en.wikipedia.org/wiki/Abell_370, Abell 360} galaxy cluster 
from the Pilot-WINGS survey; see @url{https://arxiv.org/abs/2202.04663, 
Lagattuta et al. 2022}.
+Abell 360 has a spiral galaxy in its background that is stretched due to the 
cluster's gravitational potential to create a beautiful arch.
+If you haven't seen it yet, have a look at some of its images in the Wikipedia 
link above before continuing.
+
+The Pilot-WINGS survey data are available in its 
webpage@footnote{@url{https://astro.dur.ac.uk/~hbpn39/pilot-wings.html}}.
+The cube of the @emph{core} region is 10.2GBs.
+This can be prohibitivly large to download (and later process) on many 
networks and smaller computers.
+Therefore, in this demonstration we won't be using the full cube.
+We have prepared a small crop@footnote{You can download the full cube and 
create the crop your self with the commands below.
+Due to the decompression of the +10GB file that is necessary for the 
compressed downloaded file (note that its suffix is @file{.fits.gz}), the Crop 
command will take a little long.
+@example
+$ wget https://astro.dur.ac.uk/~hbpn39/pilotWINGS/A370_PilotWINGS_CORE.fits.gz
+$ astcrop A370_PilotWINGS_CORE.fits.gz -hDATA --mode=img \
+          --section=200:300,100:200 -oa370-crop.fits --metaname=DATA
+$ astcrop A370_PilotWINGS_CORE.fits.gz -hSTAT --mode=img --append \
+          --section=200:300,100:200 -oa370-crop.fits --metaname=STAT
+@end example
+} of the full cube that you can download with the first command below.
+The randomly selected crop is centered on (RA,Dec) of (39.96769,-1.58930), 
with a width of about 27 arcseconds.
+
+@example
+$ mkdir tutorial-3d
+$ cd tutorial-3d
+$ wget http://akhlaghi.org/data/a370-crop.fits    # Downloads 287 MB
+@end example
+
+In the sections below, we will first review how you can visually inspect a 3D 
datacube in DS9 and interactively see the spectra of any region.
+We will then subtract the continuum emission, detect the emission-lines within 
this cube and extract their spectra.
+We will finish with creating pseudo narrow-band images optimized for some of 
the emission lines.
+
+@menu
+* Viewing spectra and redshifted lines::  Interactively see the spectra of an 
object
+* Sky lines in optical IFUs::   How to see sky lines in a cube.
+* Continuum subtraction::       Removing the continuum from a data cube.
+* 3D detection with NoiseChisel::  Finding emission-lines and their spectra.
+* 3D measurements and spectra::  Measuring 3d properties including spectra.
+* Extracting a single spectrum and plotting it::  Extracting a single vector 
row.
+* Pseudo narrow-band images::   Collapsing the third dimension into a 2D image.
+@end menu
+
+@node Viewing spectra and redshifted lines, Sky lines in optical IFUs, 
Detecting lines and extracting spectra in 3D data, Detecting lines and 
extracting spectra in 3D data
+@subsection Viewing spectra and redshifted lines
+
+In @ref{Detecting lines and extracting spectra in 3D data} we downloaded a 
small crop from the Pilot-WINGS survey of Abell 370 cluster; observed with MUSE.
+In this section, we will review how you can visualize/inspect a datacube using 
that example.
+With the first command below, we'll open DS9 such that each 2D slice of the 
cube (at a fixed wavelength) is seen as a single image.
+If you move the slider in the ``Cube'' window (that also opens), you can view 
the same field at different wavelengths.
+We are ending the first command with a `@code{&}' so you can continue viewing 
DS9 while using the command-line (press one extra @code{ENTER} to see the 
prompt).
+With the second command, you can see that the spacing between each slice is 
@mymath{1.25\times10^{-10}} meters (or 1.25 Angstroms).
+
+@example
+$ astscript-fits-view a370-crop.fits -h1 --ds9scale="limits -5 20" &
+
+$ astfits a370-crop.fits --pixelscale
+Basic information for --pixelscale (remove info with '--quiet' or '-q')
+  Input: a370-crop.fits (hdu 1) has 3 dimensions.
+  Pixel scale in each FITS dimension:
+    1: 5.55556e-05 (deg/pixel) = 0.2 (arcsec/pixel)
+    2: 5.55556e-05 (deg/pixel) = 0.2 (arcsec/pixel)
+    3: 1.25e-10 (m/slice)
+  Pixel area (on each 2D slice) :
+    3.08642e-09 (deg^2) = 0.04 (arcsec^2)
+  Voxel volume:
+    3.85802e-19 (deg^2*m) = 5e-12 (arcsec^2*m) = 0.05 (arcsec^2*A)
+@end example
+
+In the DS9 ``Cube'' window, you will see two numbers on the two sides of the 
scroller.
+The left number is the wavelength in meters (WCS coordinate in 3rd dimension) 
and the right number is the slice number (slice number or array coordinates in 
3rd dimension).
+You can manually edit any of these numbers and press ENTER to go to that slice 
in any coordinate system.
+If you want to go one-by-one, simply press the ``Next'' button.
+The first few slides are very noisy, but in the rest the noise level decreases 
and the galaxies are more obvious.
+
+As you slide between the different wavelengths, you see that the noise-level 
is not constant and in some slices, the sky noise is very strong (for example, 
go to slice 3201 and press the ``Next'' button).
+We will discuss these issues below (in @ref{Sky lines in optical IFUs}).
+To view the spectra of a region in DS9 take the following steps:
+
+@enumerate
+@item
+Click somewhere on the image (to make sure DS9 receives your keyboard inputs), 
then press @code{Ctrl+R} to activate regions and click on the brighest galaxy 
of this cube (center-right, at RA, Dec of 39.9659175 and -1.5893075).
+@item
+A thin green circle will show up; this is called a ``region'' in DS9.
+@item
+Double-click on the region, and you will see a ``Circle'' window.
+@item
+Within the ``Circle'' window, click on the ``Analysis'' menu and select ``Plot 
3D''.
+@item
+A second ``Circle'' window will open that shows the spectra within your 
selected region.
+This is just the sum of values on each slice within the region.
+@item
+Don't close the second ``circle'' window (that shows the spectrum).
+Click and hold the region in DS9, and move it to other objects within the cube.
+You will see that the spectrum changes as you move the region, and you can see 
that different objects have very different spectra.
+You can even see the spectra of only one part of a galaxy, not the whole 
galaxy.
+@item
+Take the region back to the first (brightest) galaxy that we originally 
started with.
+@item
+Slide over different wavelengths in the ``Cube'' window, you will see the 
light-blue line moving through the spectrum as you slide to different 
wavelengths.
+This line shows the wavelength of the displayed image in the main window over 
the spectra.
+@cindex H-alpha
+@item
+The strongest emission line in this galaxy appears to be around 8500 Angstroms 
or @mymath{8.5\times10^{-7}} meters.
+From the position of the @url{https://en.wikipedia.org/wiki/Balmer_jump, 
Balmer break} (blue-ward of 5000 Angstroms for this galaxy), the strong seems 
to be H-alpha.
+@item
+To confirm that this is H-alpha, you can select the ``Edit'' menu in the 
spectrum window and select ``Zoom''.
+@item
+Double-click and hold (for next step also) somewhere before the strongest line 
and slightly above the continuum (for example at @code{8E-07} in the horizontal 
and @mymath{60\times10^{-20}}erg/Angstrom/cm@mymath{^2}/s on the vertical).
+As you move your cursor (while holding), you will see a rectangular box 
getting created.
+@item
+Move the bottom-left corner of the box to somewhere after the strongest line 
and below the continuum.
+For example at @code{9E-07} and 
@mymath{20\times10^{-20}}erg/Angstrom/cm@mymath{^2}/s.
+@item
+Once you remove your finger from the mouse/touchpad, it will zoom-in to that 
part of the spectrum.
+@item
+To zoom out to the full spectrum, just press the right mouse button over the 
spectra (or tap with two fingers on a touchpad).
+@item
+Select that zoom-box again to see the brightest line much more clearly.
+You can also see the two lines of the Nitrogen II doublet that sandwitch 
H-alpha.
+Beside its relative position to the Balmer break, this is further evidence 
that the strongest line is H-alpha.
+@item
+@cindex NII doublet
+Let's have a look at the galaxy in its best glory: right over the H-alpha line:
+Move the wavelength slider accurately (by pressing the ``Previous'' or 
``Next'' buttons) such that the blue line falls in the middle of the H-alpha 
line.
+We see that the wavelength at this slice is @code{8.56593e-07} meters or 
8565.93 Angstroms.
+Please compare the image of the galaxy at this wavelength with the wavelenghts 
before (by pressing ``Next'' or ``Previous'').
+You will also see that it is much more extended and brighter than other 
wavelengths!
+H-alpha shows the un-obscured star formation of the galaxy!
+@end enumerate
+
+@cartouche
+@noindent
+@strong{Automaticly going to next slice:} When you want to get a general 
feeling of the cube, pressing the ``Next'' button many times is annoying and 
slow.
+To automatically shift between the slices, you can press the ``Play'' button 
in the DS9 ``Cube'' window.
+You can adjust the time it stays on each slice by clicking on the ``Interval'' 
menu and selecting lower values.
+@end cartouche
+
+Knowing that this is H-alpha at 8565.93 Angstroms, you can get the redshift of 
the galaxy with the first command below and the location of all other expected 
lines in Gnuastro's spectral line database with the second command.
+Because there are many lines in the second command (more than 200!), with the 
third command, we'll only limit it to the Balmer series (that start with 
@code{H-}) using @command{grep}.
+The output of the second command prints the metadata on the top (that is not 
shown any more in the third command due to the @code{grep} call).
+To be complete, the first column is the observed wavelength of the given line 
in the given redshift and the second column is the name of the line.
+
+@example
+# Redshift where H-alpha falls on 8565.93.
+$ astcosmiccal --obsline=H-alpha,8565.93 --usedredshift
+0.305221
+
+# Wavelength of all lines in Gnuastro's database at this redshift
+$ astcosmiccal --obsline=H-alpha,8565.93 --listlinesatz
+
+# Only the Balmer series (Lines starting with 'H-'; given to Grep).
+$ astcosmiccal --obsline=H-alpha,8565.93 --listlinesatz | grep H-
+4812.13             H-19
+4818.29             H-18
+4825.61             H-17
+4834.36             H-16
+4844.95             H-15
+4857.96             H-14
+4874.18             H-13
+4894.79             H-12
+4921.52             H-11
+4957.1              H-10
+5006.03             H-9
+5076.09             H-8
+5181.83             H-epsilon
+5353.68             H-delta
+5665.27             H-gamma
+6345.11             H-beta
+8565.93             H-alpha
+4758.84             H-limit
+@end example
+
+@cindex H-beta
+Zoom-out to the full spectrum and move the displayed slice to the location of 
the first emission line that is blue-ward (at shorter wavelengths) of H-alpha 
(at around 6300 Angstroms) and follow the previous steps to confirm that you 
are on its center.
+You will see that it falls exactly on @mymath{6.34468\times10^{-7}} m or 
6344.68 Angstroms.
+Now, have a look at the balmer lines above.
+You have found the H-beta line!
+
+The rest of the @url{https://en.wikipedia.org/wiki/Balmer_series, Balmer 
series} that you see in the list above (like H-gamma, H-delta and H-epsilon) 
are visible only as absorption lines.
+Please check their location by moving the blue line on the wavelengths above 
and confirm the spectral absorption lines with the ones above.
+The Balmer break is caused by the fact that these stronger Balmer absorption 
lines become too close to each other.
+
+Looking back at the full spectrum, you can also confirm that the only other 
relatively strong emission line in this galaxy, that is on the blue side of the 
spectrum is the weakest OII line that is approximately located at 4864 
Angstroms in the observed spectra of this galaxy.
+The numbers after the various OII emission lines show their rest-frame 
wavelengths (``OII'' can correspond to many electron transitions, so we should 
be clear about which one we are talking about).
+
+@example
+$ astcosmiccal --obsline=H-alpha,8565.93 --listlinesatz | grep O-II-
+4863.3              O-II-3726
+4866.93             O-II-3728
+5634.82             O-II-4317
+5762.42             O-II-4414
+9554.21             O-II-7319
+9568.22             O-II-7330
+@end example
+
+Please stop here and spend some time on doing the exercise above on other 
galaxies in the this cube to get a feeling of types of galaxy spectral features 
(and later on the full/large cube).
+You will notice that only star-forming galaxies have such strong emission 
lines!
+If you enjoy it, go get the full non-cropped cube and investigate the spectra, 
redshifts and emission/absorption lines of many more galaxies.
+
+But going into those higher-level details of the physical meaning of the 
spectra (as intriguing as they are!) is beyond the scope of this tutorial.
+So we have to stop at this stage unfortuantely.
+Now that you have a relatively good feeling of this small cube, let's start 
doing some analysis to extract the spectra of the objects in this cube.
+
+@node Sky lines in optical IFUs, Continuum subtraction, Viewing spectra and 
redshifted lines, Detecting lines and extracting spectra in 3D data
+@subsection Sky lines in optical IFUs
+
+@cindex Sky emission-lines
+@cindex O-H lines (from atmosphere)
+As we were visually inspecting the cube in @ref{Viewing spectra and redshifted 
lines}, we noticed some slices with very bad noise.
+They will later affect our detection within the cube, so in this section let's 
have a fast look at them here.
+We'll start by looking at the two cubes within the downloaded FITS file:
+
+@example
+$ astscript-fits-view a370-crop.fits
+@end example
+
+The cube on the left is the same cube we studied before.
+The cube on the right (which is called @code{STAT}) shows the variance of each 
voxel.
+Go to slice 3195 and press ``Next'' to view the subsequent slices.
+Initially (for the first 5 or 6 slices), the noise looks reasonable.
+But as you pass slice 3206, you will see that the noise becomes very bad in 
both cubes.
+It stays like this until about slice 3238!
+As you go through the whole cube, you will notice that these slices are much 
more frequent in the reddest wavelengths.
+
+@cindex Sky
+@cindex Atmosphere emission lines
+These slices are affected by the emission lines from our own atmosphere!
+The atmosphere's emission in these wavelengths significantly raises the 
background level in these slices.
+As a result, the poisson noise also increases significantly (see @ref{Photon 
counting noise}).
+During the data reduction, the excess background flux of each slice is removed 
as the Sky (or the mean of undetected pixels, see @ref{Sky value}).
+However, the increased Poisson noise (scatter of pixel values) remains!
+
+To see spectrum of the sky emission lines, simply put a region somewhere in 
the @code{STAT} cube and generate its spectrum (as we did in @ref{Viewing 
spectra and redshifted lines}).
+You will clearly see the comb-like shape of atmospheric emission lines and can 
use this to know where to expect them.
+
+
+@node Continuum subtraction, 3D detection with NoiseChisel, Sky lines in 
optical IFUs, Detecting lines and extracting spectra in 3D data
+@subsection Continuum subtraction
+@cindex Continuum subtraction
+In @ref{Viewing spectra and redshifted lines}, we visually inspected some of 
the most prominent emission lines of the brightest galaxy of the demo MUSE cube 
(see @ref{Detecting lines and extracting spectra in 3D data}).
+Here, we will remove the ``continuum'' flux from under the emission lines to 
see them more distinctly.
+
+Within a spectra, the continuum is the local ``background'' flux in the 
third/wavelength dimension.
+In other words, it is the flux that would be present at that wavelength if the 
emission line didn't exist.
+Therefore, to accurately measure the flux of the emission line, we first need 
to subtract the continuum.
+One crude way of estimating the continuum flux at every slice is to use the 
sigma-clipped median value of that same pixel in the @mymath{\pm{N/2}} slides 
around it (for more on sigma-clipping, see @ref{Sigma clipping}).
+
+In this case, @mymath{N=100} should be a good first approximate (since it is 
much larger than any of the absorption or emission lines).
+With the first command below, let's use Arithmetic's filtering operators for 
estimating the sigma-clipped median only along the third dimension for every 
pixel in every slice (see @ref{Filtering operators}).
+With the second command, have a look at the filtered cube and spectra.
+Note that the first command is computationally expensive and may take a minute 
or so.
+
+@example
+$ astarithmetic a370-crop.fits set-i --output=filtered.fits \
+                3 0.2 1 1 100 i filter-sigclip-median
+
+$ astscript-fits-view filtered.fits -h1 --ds9scale="limits -5 20"
+@end example
+
+Looking at the filtered cube above, and sliding through the different 
wavelenths, you will see the noise in each slice has been significantly reduced!
+This is expected because each pixel's value is now calculated from 100 others 
(along the third dimension)!
+Using the same steps as @ref{Viewing spectra and redshifted lines}, plot the 
spectra of the brightest galaxy.
+Then, have a look at its spectra.
+You see that the emission lines have been significantly smoothed out to become 
almost@footnote{For more on why Sigma-clipping is only a crude solution to 
background removal, see @url{https://arxiv.org/abs/1505.01664, Akhlaghi and 
Ichikawa 2015}.} invisible.
+
+You can now subtract this ``continuum'' cube from the input cube to create the 
emission-line cube.
+Infact, as you see below, we can do it in a single Arithmetic command 
(blending the filtering and subtraction in one command).
+Note how the only difference with the previous Arithmetic command is that we 
added an @code{i} before the @code{3} and a @code{-} after 
@code{filter-sigclip-median}.
+For more on Arithmetic's powerful notation, see @ref{Reverse polish notation}.
+With the second command below, let's view the input @emph{and} 
continuum-subtracted cubes together:
+
+@example
+$ astarithmetic a370-crop.fits set-i --output=no-continuum.fits \
+                i 3 0.2 1 1 100 i filter-sigclip-median -
+
+$ astscript-fits-view a370-crop.fits no-continuum.fits -h1 \
+                      --ds9scale="limits -5 20"
+@end example
+
+Once the cubes are open, slide through the different wavelengths.
+Comparing the left (input) and right (continuum-subtracted) slices, you will 
rarely see any galaxy in the continuum-subtracted one!
+As its name suggests, the continuum flux is continuously present in all the 
wavelengths (with gradual change)!
+But the continuum has been subtracted now; so in the right-side image, you 
don't see anything on wavelengths that don't contain a spectral emission line.
+Some dark regions also appear; these are absorption lines!
+Please spend a few minutes sliding through the wavelenghts and seeing how the 
emission lines pop-up and disappear again.
+It is almost like skuba diving, with fish appearing out of nowhere and passing 
by you.
+
+@cindex Doppler effect
+@cindex Galaxy kinematics
+@cindex Kinematics (galaxies)
+Let's go to slice 3046 (corresponding to 8555.93 Angstroms; just before the 
H-alpha line for the brightest galaxy in @ref{Viewing spectra and redshifted 
lines}).
+Now press the ``Next'' button to change slices one by one until there is no 
more emission in the brightest galaxy.
+As you go to redder slices, you will see that not only does the brightness 
increase, but the position of the emission also changes.
+This is the @url{https://en.wikipedia.org/wiki/Doppler_effect, doppler effect} 
caused by the rotation of the galaxy: the side that rotating towards us gets 
blue-shifted to bluer slices and the one that is going away from us gets 
redshifted to redder slices.
+If you go to the emission lines of the other galaxies, you will see that they 
move with a different angle!
+We can use this to derive the galaxy's rotational properties and kinematics 
(Gnuastro doesn't have this feature yet).
+
+To see the Doppler shift in the spectrum, plot the spectrum over the top-side 
of the galaxy (which is visible in slice 3047).
+Then Zoom-in to the H-alpha line (as we did in @ref{Viewing spectra and 
redshifted lines}) and press ``Next'' until you reach the end of the H-alpha 
emission-line.
+You see that by the time H-alpha disappears in the spectrum, within the cube, 
the emission shifts in the vertical axis by about 15 pixels!
+Then, move the region across the same path that the emission passed.
+You will clearly see that the H-alpha and Nitrogen II lines also move with 
you, in the zoomed-in spectra.
+Again, try this for several other emission lines, and several other galaxies 
to get a good feeling of this important concept when using hyper-spectral 3D 
data.
+
+@node 3D detection with NoiseChisel, 3D measurements and spectra, Continuum 
subtraction, Detecting lines and extracting spectra in 3D data
+@subsection 3D detection with NoiseChisel
+
+In @ref{Continuum subtraction} we subtracted the continuum emission, leaving 
us with only noise and the absorption and emission lines.
+The absorption lines are negative and will be missed by detection methods that 
look for a positive skewness@footnote{But if you want to detect the absorption 
lines, just multiply the cube by @mymath{-1} and repeat the same steps here 
(the noise is symmetic around 0).} (like @ref{NoiseChisel}).
+So we will focus on the detection and extaction of emission lines here.
+
+The first step is to extract the voxels that contain emission signal.
+To do that, we will be using @ref{NoiseChisel}.
+NoiseChisel and @ref{Segment} operate on 2D images or 3D cubes.
+But by default, they are configured for 2D images (some parameters like tile 
size take a different number of values based on the dimensionality).
+Therefore, to do 3D detection, the first necessary step is to run NoiseChisel 
with the default 3D configuration file.
+
+To see where Gnuastro's programs are installed, you can run the following 
command (the printed output is the default location when you install Gnuastro 
from source, but if you used another installation method or manually set a 
different location, you will see a different output, just use that):
+
+@example
+$ which astnoisechisel
+/usr/local/bin/astnoisechisel
+@end example
+
+As you see, the compiled binary programs (like NoiseChisel) are installed in 
the @file{bin/} sub-directory of the install path (@file{/usr/local} in the 
example above, may be different on your system).
+The configuration files are in the @file{etc/} sub-directory of the install 
path (here only showing NoiseChisel's configuration files):
+
+@example
+$ ls /usr/local/etc/astnoisechisel*.conf
+/usr/local/etc/astnoisechisel-3d.conf
+/usr/local/etc/astnoisechisel.conf
+@end example
+
+@noindent
+We should therefore call NoiseChisel with the 3D configuraiton file like below 
(please change @file{/usr/local} to any directory that you find from the 
@code{which} command above):
+
+@example
+$ astnoisechisel --config=/usr/local/etc/astnoisechisel-3d.conf \
+                 no-continuum.fits --output=det.fits
+@end example
+
+But having to add this long @option{--config} option is annoying and makes the 
command hard to read!
+To simplify the calling of NoiseChisel in 3D, let's first make a shell alias 
called @command{astnoisechisel-3d} using the @command{alias} command.
+Afterwards, we can just use the alias.
+Afterwards (in the second command below), we are calling the alias, producing 
the same output as above.
+Finally (with the last command), let's have a look at NoiseChisel's output:
+
+@example
+$ alias astnoisechisel-3d="astnoisechisel \
+           --config=/usr/local/etc/astnoisechisel-3d.conf"
+
+$ astnoisechisel-3d no-continuum.fits --output=det.fits
+
+$ astscript-fits-view det.fits
+@end example
+
+Similar to its 2D outputs, NoiseChisel's output contains four extensions/HDUs 
(see @ref{NoiseChisel output}).
+For a multi-extension file with 3D data, @code{astscript-fits-view} shows each 
cube as a separate DS9 ``Frame''.
+In this way, as you slide through the wavelengths, you see the same slice in 
all the cubes.
+The third and fourth extensions are the Sky and Sky standard deviation, which 
are not relevant here, so you can close them.
+To do that, press on the ``Frame'' button (in the top row of buttons), then 
press ``delete'' two times in the second row of buttons.
+
+As a final preparation, manaully set the scale of @code{INPUT-NO-SKY} cube to 
a fixed range so the changing flux/noise in each slice doesn't interfer with 
visually comparing the data in the slices as you move around:
+@enumerate
+@item
+Click on the @code{INPUT-NO-SKY} cube, so it is selected.
+@item
+Click on the ``Scale'' menu, then the ``Scale Parameters''.
+@item
+For the ``Low'' value set -2 and for the ``High'' value set 5.
+@item
+In the ``Cube'' window, slide between the slices to confirm that the noise 
level is visually fixed.
+@item
+Go back to the first slice for the next steps.
+Note that the first and last couple of slices have much higher noise, don't 
worry about those.
+@end enumerate
+
+As you press the ``Next'' button in the first few slides, you will notice that 
the @code{DETECTION} cube is fully black: showing that nothing has been 
detected.
+The first detection pops up in the 55th slice for the galaxy on the top of 
this cube.
+As you press ``Next'' you will see that the detection fades away and other 
detections pop up.
+Spend a few minutes shifting between the different slices and comparing the 
detected voxels with the emission lines in the continuum-subtracted cube (the 
@code{INPUT-NO-SKY} extension).
+
+Go ahead to slice 2815 and press ``Next'' a few times.
+You will notice that the detections suddenly start covering the whole slice 
and until slice 2859 where the detection map becomes normal (no extra 
detections!).
+This is the effect of the sky lines we mentioned before in @ref{Sky lines in 
optical IFUs}.
+The increased noise makes the reduction very hard and as a result, a lot of 
artifacts appear.
+To reduce the effect of sky lines, we can divide the cube by its standard 
deviation (the square root of the variance or @code{STAT} extension; see  
@ref{Sky lines in optical IFUs}) and run NoiseChisel afterwards.
+
+@example
+$ astarithmetic no-continuum.fits -h1 a370-crop.fits -hSTAT sqrt / \
+                --output=sn.fits
+
+$ astnoisechisel-3d sn.fits --output=det.fits
+
+$ astscript-fits-view det.fits
+@end example
+
+After the new detection map opens have another look at the specific slices 
mentioned above (from slice 2851 to 2859).
+You will see that there are no more detection maps that cover the whole field 
of view.
+Scroll the slide counter across the whole cube, you will rarely see such 
effects by Sky lines any more.
+But this is just a crude solution and doesn't remove all sky line artifacts.
+For example go to slide 650 and press ``Next''.
+You will see that the artifacts caused by this sky line are so strong that the 
solution above wasn't successful.
+For these very strong emission lines, we need to improve the reduction.
+But generally, since the number of sky-line affected slices has significantly 
decreased, we can go ahead.
+
+@node 3D measurements and spectra, Extracting a single spectrum and plotting 
it, 3D detection with NoiseChisel, Detecting lines and extracting spectra in 3D 
data
+@subsection 3D measurements and spectra
+
+In the context of optical IFUs or radio IFUs in astronomy, a ``Spectum'' is 
defined as separate measurements on each 2D slice of the 3D cube.
+Each 2D slice is defined by the first two FITS dimensions: the first FITS 
dimension is the horizontal axis and the second is the vertical axis.
+As with the tutorial on 2D image analysis (in @ref{Segmentation and making a 
catalog}), let's run Segment to see how it works in 3D.
+Like NoiseChisel above, to simplify the commands, let's make an alias (@ref{3D 
detection with NoiseChisel}):
+
+@example
+$ alias astsegment-3d="astsegment \
+           --config=/usr/local/etc/astsegment-3d.conf"
+
+$ astsegment-3d det.fits --output=seg.fits
+
+$ astscript-fits-view seg.fits
+@end example
+
+You see that we now have 3D clumps and 3D objects.
+So we can go ahead to do measurements.
+MakeCatalog can do single-valued measurements (as in 2D) on 3D datasets also.
+For example, with the command below, let's get the flux-weighted center (in 
the three dimensions) and sum of pixel values.
+There isn't usually a standard name for the third WCS dimension (unlike 
Ra/Dec).
+So in Gnuastro, we just call it @option{--w3}.
+With the second command, we are having a look at the first 5 rows.
+Note that we are not using @option{-Y} with @command{asttable} anymore because 
it the wavelength column would only be shown as zero (since it is in meters!).
+
+@example
+$ astmkcatalog seg.fits --ids --ra --dec --w3 --sum --output=cat.fits
+
+$ asttable cat.fits -h1 -O --txtf64p=5 --head=5
+# Column 1: OBJ_ID [counter    ,i32,] Object identifier.
+# Column 2: RA     [deg        ,f64,] Flux weighted center (WCS axis 1).
+# Column 3: DEC    [deg        ,f64,] Flux weighted center (WCS axis 2).
+# Column 4: AWAV   [m          ,f64,] Flux weighted center (WCS axis 3).
+# Column 5: SUM    [input-units,f32,] Sum of sky subtracted values.
+1  3.99677e+01   -1.58660e+00   4.82994e-07   7.311189e+02
+2  3.99660e+01   -1.58927e+00   4.86411e-07   7.872681e+03
+3  3.99682e+01   -1.59141e+00   4.90609e-07   1.314548e+03
+4  3.99677e+01   -1.58666e+00   4.90816e-07   7.798024e+02
+5  3.99659e+01   -1.58930e+00   4.93657e-07   3.255210e+03
+@end example
+
+Besides the single-valued measurements above (that are shared with 2D inputs), 
on 3D cubes, MakeCatalog can also do per-slice measurements.
+The options for these measurements are formatted as @option{--*in-slice}.
+With the command below, you can check their list:
+
+@example
+$ astmkcatalog --help | grep in-slice
+   --area-in-slice        [3D input] Number of labeled in each slice.
+   --area-other-in-slice  [3D input] Area of other lab. in proj area.
+   --area-proj-in-slice   [3D input] Num. voxels in '--sumprojinslice'.
+   --sum-err-in-slice     [3D input] Error in '--suminslice'.
+   --sum-in-slice         [3D input] Sum of values in each slice.
+   --sum-other-err-in-slice [3D input] Area in '--sumotherinslice'.
+   --sum-other-in-slice   [3D input] Sum of other lab. in proj area.
+   --sum-proj-err-in-slice [3D input] Error of '--sumprojinslice'.
+   --sum-proj-in-slice    [3D input] Sum of proj. area in each slice.
+@end example
+
+For every label and measurement, these options will give many values in a 
vector column (see @ref{Vector columns}).
+Let's have a look by asking for the sum of values and area of each label in 
each slice associated to each label with the command below.
+There is just one important point: in @ref{3D detection with NoiseChisel}, we 
ran NoiseChisel on the signal-to-noise image, not the continuum-subtracted 
image!
+So the values to use for the measurement of each label should come from the 
@file{no-continuum.fits} file (not @file{seg.fits}).
+
+@example
+$ astmkcatalog seg.fits --ids --ra --dec --w3 --sum  \
+               --area-in-slice --sum-in-slice --output=cat.fits \
+               --valuesfile=no-continuum.fits
+
+$ asttable -i cat.fits
+--------
+seg_cat.fits (hdu: 1)
+-------          -----       ----          -------
+No.Name          Units       Type          Comment
+-------          -----       ----          -------
+1  OBJ_ID        counter     int32         Object identifier.
+2  RA            deg         float64       Flux wht center (WCS 1).
+3  DEC           deg         float64       Flux wht center (WCS 2).
+4  AWAV          m           float64       Flux wht center (WCS 3).
+5  SUM           input-units float32       Sum of sky-subed values.
+6  AREA-IN-SLICE counter     int32(3681)   Number of pix. in each slice.
+7  SUM-IN-SLICE  input-units float32(3681) Sum of values in each slice.
+--------
+Number of rows: 211
+--------
+@end example
+
+You can see that the new @code{AREA-IN-SLICE} and @code{SUM-IN-SLICE} columns 
have a @code{(3681)} in their types.
+This shows that unlike the single-valued columns before them, in these 
columns, each row has 3681 values (a ``vector'' column).
+If you are not already familiar with vector columns, please take a few minutes 
to read @ref{Vector columns}.
+Since a MUSE data cube has 3681 slices, this is effectively the spectrum of 
each object.
+
+Let's find the object that corresponds to the H-alpha emission of the 
brightest galaxy (that we found in @ref{Viewing spectra and redshifted lines}).
+That emission line was around 8565.93 Angstroms, so let's look for the objects 
within @mymath{\pm5} Angstroms of that value (between 8560 to 8570 Angstroms):
+
+@example
+$ asttable cat.fits --range=AWAV,8.560e-7,8.570e-7 -cobj_id,ra,dec -Y
+198    39.965897   -1.589279
+@end example
+
+From the command above, we see that at this wavelength, there was only one 
object.
+Let's extract its spectrum by asking for the @code{sum-in-slice} column:
+
+@example
+$ asttable cat.fits --range=AWAV,8.560e-7,8.570e-7 \
+           -carea-in-slice,sum-in-slice
+@end example
+
+If you look into the outputs, you will see that it is a single line!
+It contains a long list of 0 values at the start and @code{nan} values in the 
end.
+If you scroll slowly, in the middle of each you will see some non-zero and 
non-NaN numbers.
+To help interpret this more easily, let's transpose these vector columns (so 
each value of the vector column becomes a row in the output).
+We will use the @option{--transpose} option of Table for this (just note that 
since transposition changes the number of rows, it can only be used when your 
table only has vector columns and they all have the same number of elements (as 
in this case, for more):
+
+@example
+$ asttable cat.fits --range=AWAV,8.560e-7,8.570e-7 \
+           -carea-in-slice,sum-in-slice --transpose
+@end example
+
+We now see the measurements on each slice printed in a separate line (making 
it much more easier to visually read).
+However, without a counter, it is very hard to interpret them.
+Let's pipe the output to a new Table command and use column arithmetic's 
@code{counter} operator for displaying the slice number (see @ref{Size and 
position operators}).
+Note that since we are piping the output, we also added @option{-O} so the 
column metadata are also passed to the new instance of Table:
+
+@example
+$ asttable cat.fits --range=AWAV,8.560e-7,8.570e-7 -O \
+           -carea-in-slice,sum-in-slice --transpose \
+           | asttable -c'arith $1 counter swap',2
+...[[truncated]]...
+3040   0       nan
+3041   0       nan
+3042   0       nan
+3043   0       nan
+3044   1       4.311140e-01
+3045   18      3.936019e+00
+3046   161    -5.800080e+00
+3047   360     2.967184e+02
+3048   625     1.912855e+03
+3049   823     5.140487e+03
+3050   945     7.174101e+03
+3051   999     6.967604e+03
+3052   1046    6.468591e+03
+3053   1025    6.457354e+03
+3054   996     6.599119e+03
+3055   966     6.762280e+03
+3056   873     5.014052e+03
+3057   649     2.003334e+03
+3058   335     3.167579e+02
+3059   131     1.670975e+01
+3060   25     -2.953789e+00
+3061   0       nan
+3062   0       nan
+3063   0       nan
+3064   0       nan
+...[[truncated]]...
+
+$ astscript-fits-view seg.fits
+@end example
+
+After DS9 opens with the last command above, go to slice 3044 (which is the 
first non-NaN slice in the spectrum above).
+In the @code{OBJECTS} extension of this slice, you see several non-zero pixels.
+The few non-zero pixels on the bottom have a label of 197 and the single 
non-zero pixel at a higher Y axis position has a label of 198 (which as we saw 
above, was the label of the H-alpha emission of this galaxy).
+The few 197 labeled pixels in this slice are the last voxels of the NII 
emission that is just blue-ward of H-alpha.
+
+The single pixel you see in slice 3044 is why you see a value of 1 in the 
@code{AREA-IN-SLICE} column.
+As you go to the next slices, if you count the pixels, you will see they add 
up to the same number you see in that column.
+The values in the @code{SUM-IN-SLICE} are the sum of values in the 
continuum-subtracted cube for those same voxels.
+You should now be able to understand why the @option{--sum-in-slice} column 
has NaN values in all other slices: because this label doesn't exist in any 
other slice!
+Also, within slices that contain label 198, this column only uses the voxels 
that have the label.
+So as you see in the second column above, the area that is used in each 
changes.
+
+Therefore @option{--sum-in-slice} or @option{area-in-slice} are the raw 3D 
spectrum of each 3D emission-line.
+This is a different concept from the traditional ``spectrum'' where the same 
area is used over all the slices.
+To get that you should use the @option{--sumprojinslice} column of MakeCatalog.
+All the @option{--*in-slice} options that contain a @code{proj} in their name 
are measurements over the fixed ``projection'' of the 3D volume on the 2D 
surface of each slice.
+To see the effect, let's also ask MakeCatalog to measure this projected sum 
column:
+
+@example
+$ astmkcatalog seg.fits --ids --ra --dec --w3 --sum  \
+               --area-in-slice --sum-in-slice --sum-proj-in-slice \
+               --output=cat.fits --valuesfile=no-continuum.fits
+$ asttable cat.fits --range=AWAV,8.560e-7,8.570e-7 -O \
+           -carea-in-slice,sum-in-slice,sum-proj-in-slice \
+           --transpose \
+           | asttable -c'arith $1 counter swap',2,3
+...[[truncated]]...
+3040   0       nan            8.686357e+02
+3041   0       nan            4.384907e+02
+3042   0       nan            4.994813e+00
+3043   0       nan           -1.595918e+02
+3044   1       4.311140e-01  -2.793141e+02
+3045   18      3.936019e+00  -3.251023e+02
+3046   161    -5.800080e+00  -2.709914e+02
+3047   360     2.967184e+02   1.049625e+02
+3048   625     1.912855e+03   1.841315e+03
+3049   823     5.140487e+03   5.108451e+03
+3050   945     7.174101e+03   7.149740e+03
+3051   999     6.967604e+03   6.913166e+03
+3052   1046    6.468591e+03   6.442184e+03
+3053   1025    6.457354e+03   6.393185e+03
+3054   996     6.599119e+03   6.572642e+03
+3055   966     6.762280e+03   6.716916e+03
+3056   873     5.014052e+03   4.974084e+03
+3057   649     2.003334e+03   1.870787e+03
+3058   335     3.167579e+02   1.057906e+02
+3059   131     1.670975e+01  -2.415764e+02
+3060   25     -2.953789e+00  -3.534623e+02
+3061   0       nan           -3.745465e+02
+3062   0       nan           -2.532008e+02
+3063   0       nan           -2.372232e+02
+3064   0       nan           -2.153670e+02
+...[[truncated]]...
+@end example
+
+As you see, in the new @code{SUM-PROJ-IN-SLICE} column, we have a measurement 
in each slice: including slices that do not have the label of 198 at all.
+Also, the area used to measure this sum is the same in all slices (similar to 
a classical spectrometer's output).
+
+However, there is a big problem: have a look at the sums in slices 3040 and 
3041: the values are increasing!
+This is because of the emission in the NII line that also falls over the 
projected area of H-alpha.
+This shows the power of IFUs as opposed to classical spectrometers: we can 
distinguish between individual lines based on spatial position and do 
measurements in 3D!
+
+Finally, in case you want the spectrum with the continuum, you just have to 
change the file given to @option{--valuesfile}:
+
+@example
+$ astmkcatalog seg.fits --ids --ra --dec --w3 --sum  \
+               --area-in-slice --sum-in-slice --sum-proj-in-slice \
+               --valuesfile=a370-crop.fits \
+               --output=cat-with-continuum.fits
+@end example
+
+@node Extracting a single spectrum and plotting it, Pseudo narrow-band images, 
3D measurements and spectra, Detecting lines and extracting spectra in 3D data
+@subsection Extracting a single spectrum and plotting it
+
+In @ref{3D measurements and spectra} we measured the spectra of all the 
objects with the MUSE data cube of this demonstration tutorial.
+Let's now write the resulting spectra for our object 198 into a file to view 
our measured spectra in TOPCAT for a more visual inspection.
+But we don't want slice numbers (which are specific to MUSE), we want the 
horizontal axis to be in Angstroms.
+To do that, we can use the WCS information:
+
+@table @code
+@item CRPIX3
+The ``Coordinate Reference PIXel'' in the 3rd dimension (or slice number of 
reference)
+Let's call this @mymath{s_r}.
+@item CRVAL3
+The ``Coordinate Reference VALue'' in the 3rd dimension (the WCS coordinate of 
the slice in @code{CRPIX3}.
+Let's call this @mymath{\lambda_r}
+@item CDELT3
+The ``Coordinate DELTa'' in the 3rd dimension, or how much the WCS changes 
with every slice.
+Let's call this @mymath{\delta}.
+@end table
+
+@noindent
+To find the @mymath{\lambda} (wavelength) of any slice with number @mymath{s}, 
we can simply use this equation:
+
+@dispmath{\lambda=\lambda_r+\delta(s-s_r)}
+
+Let's extract these three values from the FITS WCS keywords as shell variables 
to automatically do this within Table's column arithmetic.
+Here we are using the technique that is described in @ref{Separate shell 
variables for multiple outputs}.
+
+@example
+$ eval $(astfits seg.fits --keyvalue=CRPIX3,CRVAL3,CDELT3 -q \
+                 | xargs printf "sr=%s; lr=%s; d=%s;")
+
+## Just for a check:
+$ echo $sr
+1.000000e+00
+$ echo $lr
+4.749679687500000e-07
+$ echo $d
+1.250000000000000e-10
+@end example
+
+Now that we have the necessary constants, we can simply convert the equation 
above into @ref{Reverse polish notation} and use column arithmetic to convert 
the slice counter into wavelength in the command of @ref{3D measurements and 
spectra}.
+
+@example
+$ asttable cat.fits --range=AWAV,8.560e-7,8.570e-7 -O \
+       -carea-in-slice,sum-in-slice,sum-proj-in-slice \
+       --transpose \
+       | asttable -c'arith $1 counter '$sr' - '$d' x '$lr' + f32 swap' \
+                  -c2,3 --output=spectrum-obj-198.fits \
+                  --colmetadata=1,WAVELENGTH,m,"Wavelength of slice." \
+                  --colmetadata=2,"AREA-IN-SLICE",voxel,"No. of voxels."
+
+$ astscript-fits-view spectrum-obj-198.fits
+@end example
+
+Once TOPCAT opens, take the following steps:
+
+@enumerate
+@item
+In the ``Graphics'' menu, select ``Plane plot''.
+@item
+Change @code{AREA-IN-SLICE} to @code{SUM-PROJ-IN-SLICE}.
+@item
+Select the ``Form'' tab.
+@item
+Click on the button with the large green ``+'' button and select ``Add line''.
+@item
+Un-select the ``Mark'' item that was originally selected.
+@end enumerate
+
+@noindent
+Of course, the table in @file{spectrum-obj-198.fits} can be plotted using any 
other plotting tool you prefer to use in your scientific papers.
+
+@node Pseudo narrow-band images,  , Extracting a single spectrum and plotting 
it, Detecting lines and extracting spectra in 3D data
+@subsection Pseudo narrow-band images
+
+In @ref{Continuum subtraction} we subtracted/separated the continuum from the 
emission/absorption lines of our galaxy in the MUSE cube.
+Let's visualize the morphology of the galaxy at some of the spectral lines to 
see how it looks.
+To do this, we will create pseudo narrow-band 2D images by collapsing the cube 
along the third dimension within a certain wavelength range that is optimized 
for that flux.
+
+Let's find the wavelength range that corresponds to H-alpha emission we 
studied in @ref{Extracting a single spectrum and plotting it}.
+Fortunately MakeCatalog can calculate the minimum and maximum position of each 
label along each dimension like the command below.
+If you always need these values, you can includ these columns in the same 
MakeCatalog with @option{--sum-proj-in-slice}.
+Here we are running it separately to help you follow the discussion there.
+
+@example
+$ astmkcatalog seg.fits --output=cat-ranges.fits \
+               --ids --min-x --max-x --min-y --max-y --min-z --max-z
+@end example
+
+Let's extract the minimum and maximum positions of this particular object with 
the first command and with the second, we'll write them into different shell 
variables.
+With the second command, we are writing those six values into a single string 
in the format of Crop's @ref{Crop section syntax}.
+For more on the @code{eval}-based shell trick we used here, see @ref{Separate 
shell variables for multiple outputs}.
+Finally, we are running Crop and viewing the cropped 3D cube.
+
+@example
+$ asttable cat-ranges.fits --equal=OBJ_ID,198 \
+                  -cMIN_X,MAX_X,MIN_Y,MAX_Y,MIN_Z,MAX_Z
+56     101    11     61     3044   3060
+
+$ eval $(asttable cat-ranges.fits --equal=OBJ_ID,198 \
+                  -cMIN_X,MAX_X,MIN_Y,MAX_Y,MIN_Z,MAX_Z \
+                  | xargs printf "section=%s:%s,%s:%s,%s:%s; ")
 
+$ astcrop no-continuum.fits --mode=img --section=$section \
+          --output=crop-no-continuum.fits
 
+$ astscript-fits-view crop-no-continuum.fits
+@end example
 
+Go through the slices and you will only see this particular region of the full 
cube.
+We can now collapse the third dimension of this image into a 2D pseudo-narrow 
band image with Arithmetic's @ref{Dimensionality changing operators}:
 
+@example
+$ astarithmetic crop-no-continuum.fits 3 collapse-sum \
+                --output=collapsed-all.fits
 
+$ astscript-fits-view collapsed-all.fits
+@end example
 
+During the collapse, used all the pixels in each slice.
+This is not good for the faint outskirts in the peak of the emission line: the 
noise of the slices with less signal decreases the over-all signal-to-noise 
ratio in the pseudo-narrow band image.
+So let's set all the pixels that aren't labeled with this object as NaN, then 
collapse.
+To do that, we first need to crop the @code{OBJECT} cube in @file{seg.fits}.
+With the second command, please have a look to confirm how the labels change 
as a function of wavelength.
+
+@example
+$ astcrop seg.fits -hOBJECTS --mode=img --section=$section \
+          --output=crop-obj.fits
+
+$ astscript-fits-view crop-obj.fits
+@end example
+
+Let's use Arithmetic to first set all the pixels that are not equal to 198 in 
@file{collapsed-obj.fits} to be NaN in @file{crop-no-continuum.fits}.
+With the second command, we are opening the two collapsed images together:
+
+@example
+$ astarithmetic crop-no-continuum.fits set-i \
+                crop-obj.fits          set-o \
+                i o 198 ne nan where 3 collapse-sum \
+                --output=collapsed-obj.fits
+
+$ astscript-fits-view collapsed-all.fits collapsed-obj.fits \
+                      --ds9extra="-lock scalelimits yes -blink"
+@end example
+
+Let it blink a few times and focus on the outskirts: you will see that the 
diffuse flux in the outskirts has indeed been preserved better in the 
object-based collapsed narrow-band image.
+But this is a little hard to appreciate in the 2D image.
+To see it better practice, let's get the two radial profiles.
+We will approximately assume a position angle of -80 and axis ratio of 
0.7@footnote{To derive the axis ratio and position angle automatically, you can 
take the following steps. Note that we are not using NoiseChisel because this 
crop has been intentionally selected to contain signal, so there is no raw 
noise inside of it.
+@example
+$ aststatistics collapsed-all.fits --sky --tilesize=5,5
+$ astarithmetic collapsed-all.fits -h1 collapsed-all_sky.fits -hSKY_STD / 5 gt 
\
+                -ocollapsed-lab.fits
+$ astmkcatalog collapsed-lab.fits -h1 --valuesfile=collapsed-all.fits \
+               --position-angle --axis-ratio
+$ asttable collapsed-all_arith_cat.fits -Y
+-78.817        0.694
+@end example
+}.
+With the final command below, we are opening both radial profiles in TOPCAT to 
visualize them.
+We are also undersampling the radial profile to have better signal-to-noise 
ratio in the outer radii:
+
+@example
+$ astscript-radial-profile collapsed-all.fits \
+           --position-angle=-80 --axis-ratio=0.7 \
+           --undersample=2 --output=collapsed-all-rad.fits
+
+$ astscript-radial-profile collapsed-obj.fits \
+           --position-angle=-80 --axis-ratio=0.7 \
+           --undersample=2 --output=collapsed-obj-rad.fits
+@end example
+
+To view the difference, let's merge the two profiles (the @code{MEAN} column) 
into one table and simply print the two profiles beside each other.
+We will then pipe the resulting table containing both columns to a second call 
to Gnuastro's Table and use column arithmetic to subtract the two mean values 
and divide them by the optimized one (to get the fractional difference):
+
+@example
+$ asttable collapsed-all-rad.fits --catcolumns=MEAN -O \
+           --catcolumnfile=collapsed-obj-rad.fits \
+           | asttable -c1,2,3 -c'arith $3 $2 - $3 /' \
+                      --colmetadata=2,MEAN-ALL \
+                      --colmetadata=3,MEAN-OBJ \
+                      --colmetadata=4,DIFF,frac,"Fractional diff." -YO
+# Column 1: RADIUS   [pix        ,f32,] Radial distance
+# Column 2: MEAN-ALL [input-units,f32,] Mean of sky subtracted values.
+# Column 3: MEAN-OBJ [input-units,f32,] Mean of sky subtracted values.
+# Column 4: DIFF     [frac       ,f32,] Fractional diff.
+0.000          436.737        450.256        0.030
+2.000          371.880        384.071        0.032
+4.000          313.429        320.138        0.021
+6.000          275.744        280.102        0.016
+8.000          152.214        154.470        0.015
+10.000         59.311         62.207         0.047
+12.000         18.466         20.396         0.095
+14.000         6.940          8.671          0.200
+16.000         3.052          4.256          0.283
+18.000         1.590          2.848          0.442
+20.000         1.430          2.550          0.439
+22.000         0.838          1.975          0.576
+@end example
+
+@noindent
+As you see, beyond a radius of 10, the last fractional difference column 
becomes very large, showing that a lot of signal is missing in the 
@code{MEAN-ALL} column.
+For a more visual comparison of the two profiles, you can use the command 
below to open both tables in TOPCAT:
+
+@example
+$ astscript-fits-view collapsed-all-rad.fits \
+                      collapsed-obj-rad.fits
+@end example
+
+Once TOPCAT has opened take the following steps:
+@enumerate
+@item
+Select @file{collapsed-all-rad.fits}
+@item
+In the ``Graphics'' menu, select ``Plane Plot''.
+@item
+Click on the ``Axes'' side-bar (by default, at the bottom half of the window), 
and click on ``Y Log'' to view the vertical axis in logarithmic scale.
+@item
+In the ``Layers'' menu, select ``Add Position Control''.
+You will see that at the bottom half, a new scatter plot information is 
displayed.
+@item
+Click on the scroll-down menu infront of ``Table'' and select @file{2: 
collapsed-obj-rad.fits}.
+Afterwards, you will see the optimized pseudo-narrow-band image radial profile 
as blue points.
+@end enumerate
 
 @node Installation, Common program behavior, Tutorials, Top
 @chapter Installation
@@ -8065,7 +8951,7 @@ Therefore its headers (and libraries) are not needed.
 @cindex Numpy
 @cindex Python3
 Python is a high-level programming language and Numpy is the most commonly 
used library within Python to add multi-dimensional arrays and matrices.
-If version 3 of Python is available with a corresponding Numpy Library, 
Gnuastro's library will be built with some Python-related helper functions.
+If you configure Gnuastro with @option{--with-python} @emph{and} version 3 of 
Python is available with a corresponding Numpy Library, Gnuastro's library will 
be built with some Python-related helper functions.
 Python wrappers for Gnuastro's library (for example, `pyGnuastro') can use 
these functions when being built from source.
 For more on Gnuastro's Python helper functions, see @ref{Python interface}.
 
@@ -10629,9 +11515,9 @@ Let's review the solution (in more detail):
 @item
 @cindex Standard input
 @cindex @command{xargs} (extended arguments)
-We pipe the output into the @option{xargs}@footnote{For more on 
@command{xargs}, see @url{https://en.wikipedia.org/wiki/Xargs}. In short 
@command{xargs} will take the standard input (from the pipe in this scenario) 
and put it as arguments of the next program.
-In other words, it is good for programs that don't take input from standard 
input (@command{printf} in this case; but also includes others like 
@command{cp}, @command{rm}, or @command{echo}).} (extended arguments).
-@command{xargs} puts the two numbers it gets from the pipe, as arguments for 
@command{printf} (formatted print) because @command{printf} doesn't take input 
from pipes.
+We pipe the output into @command{xargs}@footnote{For more on @command{xargs}, 
see @url{https://en.wikipedia.org/wiki/Xargs}.
+It will take the standard input (from the pipe in this scenario) and put it as 
arguments of the next program (@command{printf} in this scenario).
+In other words, it is good for programs that don't take input from standard 
input (@command{printf} in this case; but also includes others like 
@command{cp}, @command{rm}, or @command{echo}).} (extended arguments) which 
puts the two numbers it gets from the pipe, as arguments for @command{printf} 
(formatted print; because @command{printf} doesn't take input from pipes).
 @item
 Within the @command{printf} call, we write the values after putting a variable 
name and equal-sign, and in between them we put a @key{;} (as if it was a shell 
command).
 The @code{%s} tells @command{printf} to print each input as a string (not to 
interpret it as a number and loose precision).
@@ -10663,6 +11549,8 @@ $ echo $my_std
 This @command{eval}-based solution has been tested in in GNU Bash, Dash and 
Zsh and it works nicely in them (is ``portable'').
 This is because the constructs used here are pretty low-level (and widely 
available).
 
+For examples usages of this technique, see the following sections: 
@ref{Extracting a single spectrum and plotting it} and @ref{Pseudo narrow-band 
images}.
+
 @node Configuration files, Getting help, Command-line, Common program behavior
 @section Configuration files
 
@@ -12707,7 +13595,7 @@ To stop as soon as an error occurs, run with 
@option{--quitonerror}.
 
 @item -p
 @itemx --printallkeys
-Print the full meta data (keywords, values, units and comments) in the 
specified FITS extension (HDU).
+Print the full metadata (keywords, values, units and comments) in the 
specified FITS extension (HDU).
 If this option is called along with any of the other keyword editing commands, 
as described above, all other editing commands take precedence to this.
 Therefore, it will print the final keywords after all the editing has been 
done.
 
@@ -14462,13 +15350,13 @@ To address these problems, the FITS standard has 
defined the concept of ``vector
 Within each row of a single vector column, we can store any number of 
datapoints (like the MUSE spectra above or the full radial profile of each 
galaxy).
 All the values in a vector column have to have the same @ref{Numeric data 
types}, and the number of elements within each vector column is the same for 
all rows.
 
-By grouping conceptually similar data points (like a spectra) in one vector 
column, we can significantly reduce the number of columns and make it much more 
managable, without loosing any information!
+By grouping conceptually similar data points (like a spectrum) in one vector 
column, we can significantly reduce the number of columns and make it much more 
managable, without loosing any information!
 To demonstrate the vector column features of Gnuastro's Table program, let's 
start with a randomly generated small (5 rows and 3 columns) catalog.
 This will allows us to show the outputs of each step here, but you can apply 
the same concept to vectors with any number of colums.
 
 With the command below, we use @code{seq} to generate a single-column table 
that is piped to Gnuastro's Table program.
-Table then uses column arithmetic to generate three columns with random values 
from that base row (for more, see @ref{Column arithmetic}).
-Each column has with a larger noise sigma.
+Table then uses column arithmetic to generate three columns with random values 
from that column (for more, see @ref{Column arithmetic}).
+Each column becomes noisy, with standard deviations of 2, 5 and 10.
 Finally, we will add metadata to each column, giving each a different name 
(using names is always the best way to work with columns):
 
 @example
@@ -14486,18 +15374,18 @@ With the command below, let's have a look at the 
table.
 When you run it, you will have a different random number generator seed, so 
the numbers will be slightly different.
 For making reproducible random numbers, see @ref{Generating random numbers}.
 The @option{-Y} option is used for more easily readable numbers (without it, 
floating point numbers are written in scientific notation, for more see 
@ref{Printing floating point numbers}) and with the @option{-O} we are asking 
Table to also print the metadata.
-For more on Table's options, see @ref{Invoking asttable} and for seeing how 
the short options can be merged, see @ref{Options}.
+For more on Table's options, see @ref{Invoking asttable} and for seeing how 
the short options can be merged (such that @option{-Y -O} is identical to 
@option{-YO}), see @ref{Options}.
 
 @example
 $ asttable table.fits -YO
 # Column 1: abc [none,f32,] First column.
 # Column 2: def [none,f32,] Second column.
 # Column 3: ghi [none,f32,] Third column.
--2.694         -9.130         +6.865
-+3.166         +4.239         +18.386
-+4.709         +0.561         +1.817
--0.338         +4.927         -5.010
-+7.291         +5.541         +3.311
+1.074           5.535         -4.464
+0.606          -2.011          15.397
+1.475           1.811          5.687
+2.248           7.663         -7.789
+6.355           17.374         6.767
 @end example
 
 We see that indeed, it has three columns, with our given names.
@@ -14509,18 +15397,18 @@ As the name suggests, @option{--tovector} will merge 
the rows of the two columns
 $ asttable table.fits -YO --tovector=def,ghi
 # Column 1: abc        [none,f32   ,] First column.
 # Column 2: def-VECTOR [none,f32(2),] Vector by merging multiple cols.
--2.694         -9.130         +6.865
-+3.166         +4.239         +18.386
-+4.709         +0.561         +1.817
--0.338         +4.927         -5.010
-+7.291         +5.541         +3.311
+1.074           5.535         -4.464
+0.606          -2.011          15.397
+1.475           1.811          5.687
+2.248           7.663         -7.789
+6.355           17.374         6.767
 @end example
 
 @cindex Tokens
 If you ignore the metadata, this doesn't seem to have changed anything!
 You see that each line of numbers still has three ``tokens'' (to distinguish 
them from ``columns'').
 But once you look at the metadata, you only see metadata for two columns, not 
three.
-If you look closely, the numeric data type of the newly added fourth column is 
`@code{f32(2)}' (look above, previously it was @code{f32}).
+If you look closely, the numeric data type of the newly added fourth column is 
`@code{f32(2)}' (look above; previously it was @code{f32}).
 The @code{(2)} shows that the second column contains two numbers/tokens not 
one.
 If your vector column consisted of 3681 numbers, this would be 
@code{f32(3681)}.
 Looking again at the metadata, we see that @option{--tovector} has also 
created a new name and comments for the new column.
@@ -14533,7 +15421,7 @@ We can get a first confirmation by looking at the 
table's metadata in the second
 
 @example
 $ asttable table.fits -YO --tovector=def,ghi --output=vec.fits \
-           --colmetadata=2,defghi,nounits,"New vector column"
+           --colmetadata=2,vector,nounits,"New vector column."
 
 $ asttable vec.fits -i
 --------
@@ -14542,56 +15430,57 @@ vec.fits (hdu: 1)
 No.Name    Units    Type        Comment
 -------    -----    ----        -------
 1  abc     none     float32     First column.
-2  defghi  nounits  float32(2)  New vector column
+2  vector  nounits  float32(2)  New vector column.
 --------
 Number of rows: 5
+--------
 @end example
 
 @noindent
-A more robust confirmation would be to print the values in the newly added 
@code{defghi} column.
-As expected, asking for a single column with @option{--column} (or 
@option{-c}) will given us two numbers per row/line.
+A more robust confirmation would be to print the values in the newly added 
@code{vector} column.
+As expected, asking for a single column with @option{--column} (or 
@option{-c}) will given us two numbers per row/line (instead of one!).
 
 @example
-$ asttable vec.fits -c defghi -YO
-# Column 1: defghi [nounits,f32(2),] New vector column
--9.130         +6.865
-+4.239         +18.386
-+0.561         +1.817
-+4.927         -5.010
-+5.541         +3.311
+$ asttable vec.fits -c vector -YO
+# Column 1: vector [nounits,f32(2),] New vector column.
+ 5.535         -4.464
+-2.011          15.397
+ 1.811          5.687
+ 7.663         -7.789
+ 17.374         6.767
 @end example
 
 If you want to keep the original single-valued columns that went into the 
vector column, you can use the @code{--keepvectfin} option (read it as ``KEEP 
VECtor To/From Inputs''):
 
 @example
 $ asttable table.fits -YO --tovector=def,ghi --keepvectfin \
-           --colmetadata=4,defghi,nounits,"New vector column"
+           --colmetadata=4,vector,nounits,"New vector column."
 # Column 1: abc    [none   ,f32   ,] First column.
 # Column 2: def    [none   ,f32   ,] Second column.
 # Column 3: ghi    [none   ,f32   ,] Third column.
-# Column 4: defghi [nounits,f32(2),] New vector column
--2.694         -9.130         +6.865         -9.130         +6.865
-+3.166         +4.239         +18.386        +4.239         +18.386
-+4.709         +0.561         +1.817         +0.561         +1.817
--0.338         +4.927         -5.010         +4.927         -5.010
-+7.291         +5.541         +3.311         +5.541         +3.311
+# Column 4: vector [nounits,f32(2),] New vector column.
+1.074           5.535         -4.464          5.535         -4.464
+0.606          -2.011          15.397        -2.011          15.397
+1.475           1.811          5.687          1.811          5.687
+2.248           7.663         -7.789          7.663         -7.789
+6.355           17.374         6.767          17.374         6.767
 @end example
 
 Now that you know how to create vector columns, let's assume you have the 
inverse scenario: you want to extract one of the values of a vector column into 
a separate single-valued column.
 To do this, you can use the @option{--fromvector} option.
-The @option{--fromvector} option takes the name (or counter) of a vector 
column, followed by any number of integer counters.
+The @option{--fromvector} option takes the name (or counter) of a vector 
column, followed by any number of integer counters (counting from 1).
 It will extract those elements into separate single-valued columns.
 For example, let's assume you want to extract the second element of the 
@code{defghi} column in the file you made before:
 
 @example
-$ asttable vec.fits --fromvector=defghi,2 -YO
+$ asttable vec.fits --fromvector=vector,2 -YO
 # Column 1: abc      [none   ,f32,] First column.
-# Column 2: defghi-2 [nounits,f32,] New vector column
--2.694         +6.865
-+3.166         +18.386
-+4.709         +1.817
--0.338         -5.010
-+7.291         +3.311
+# Column 2: vector-2 [nounits,f32,] New vector column.
+1.074          -4.464
+0.606           15.397
+1.475           5.687
+2.248          -7.789
+6.355           6.767
 @end example
 
 @noindent
@@ -14601,11 +15490,13 @@ This feature is useful in scenarios where you want to 
select some rows based on
 @cartouche
 @noindent
 @strong{Vector columns and FITS ASCII tables:} As mentioned above, the FITS 
standard only recognizes vector columns in its Binary table format (the default 
FITS table format in Gnuastro).
-You can use the @option{--tableformat=fits-ascii} option to write your tables 
in the FITS ASCII format (see @ref{Input output options}).
+You can still use the @option{--tableformat=fits-ascii} option to write your 
tables in the FITS ASCII format (see @ref{Input output options}).
 In this case, if a vector column is present, it will be written as separate 
single-element columns to avoid loosing information (as if you run called 
@option{--fromvector} on all the elements of the vector column).
 A warning is printed if this occurs.
 @end cartouche
 
+For an application of the vector column concepts introduced here on MUSE data, 
see the 3D data cube tutorial and in paraticular these two sections: @ref{3D 
measurements and spectra} and @ref{Extracting a single spectrum and plotting 
it}.
+
 @node Column arithmetic, Operation precedence in Table, Vector columns, Table
 @subsection Column arithmetic
 
@@ -14663,9 +15554,9 @@ When the columns have descriptive names, the 
command/script actually becomes muc
 It is also independent of the low-level table structure: for the second 
command, the column numbers of the @code{AWAV} and @code{SPECTRUM} columns in 
@file{table.fits} is irrelevant.
 
 Column arithmetic changes the values of the data within the column.
-So the old column meta data cannot be used any more.
+So the old column metadata cannot be used any more.
 By default the output column of the arithmetic operation will be given a 
generic metadata (for example, its name will be @code{ARITH_1}, which is hardly 
useful!).
-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.
+But metadata 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}.
 
 Since the arithmetic expressions are a value to @option{--column}, it does not 
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).
@@ -14862,6 +15753,17 @@ The Table program can do many operations on the rows 
and columns of the input ta
 In this section we will describe which operation is done before/after which 
operation.
 Knowing this precedence table is important to avoid confusion when you ask for 
more than one operation.
 For a description of each option, please see @ref{Invoking asttable}.
+By default, column-based operations will be done first.
+You can ask for switching to row-based operations to be done first, using the 
@option{--rowfirst} option.
+
+@cartouche
+@noindent
+@strong{Pipes for different precedence:} It may happen that your desired 
series of operations cannot be done with the precedence mentioned below (in one 
command).
+In this case, you can pipe the output of one call to @command{asttable} to 
another @command{asttable}.
+Just don't forget to give @option{-O} (or @option{--colinfoinstdout}) to the 
first instance (so the column metadata are also passed to the next instance).
+Without metadata, all numbers will be read as double-precision (see 
@ref{Gnuastro text table format}; recall that piping is done in plain text 
format), vector columns will be broken into single-valued columns, and column 
names, units and comments will be lost.
+At the end of this section, there is an example of doing this.
+@end cartouche
 
 @table @asis
 @item Column information (@option{--information} or @option{-i})
@@ -14874,11 +15776,17 @@ This can therefore be called at the end of an 
arbitrarily long Table command onl
 When this option is given, only the columns given to this option (from the 
main input) will be used for all future steps.
 When @option{--column} (or @option{-c}) is not given, then all the main 
input's columns will be used in the next steps.
 
-@item Column(s) from other file(s) (@option{--catcolumnfile} and 
@option{--catcolumnhdu}, @option{--catcolumns})
-When column concatenation (addition) is requested, columns from other tables 
(in other files, or other HDUs of the same FITS file) will be added after the 
existing columns read from the main input.
-In one command, you can call these options multiple times to allow addition of 
columns from many files.
+@item Column-based operations
+By default the following column-based operations will be done before the 
row-based operations in the next item.
+If you need to give precedence to row-based operations, use 
@option{--rowfirst}.
+
+@table @asis
+
+@item Column(s) from other file(s): @option{--catcolumnfile}
+When column concatenation (addition) is requested, columns from other tables 
(in other files, or other HDUs of the same FITS file) will be added after the 
existing columns are read from the main input.
+In one command, you can call @option{--catcolumnfile} multiple times to allow 
addition of columns from many files.
 
-The rest of the operations below are done on the rows, therefore you can merge 
the columns of various tables into one table, then start adding/limiting the 
rows of the output.
+Therefore you can merge the columns of various tables into one table in this 
step (at the start), then start adding/limiting the rows, or building vector 
columns, .
 If any of the row-based operations below are requested in the same 
@code{asttable} command, they will also be applied to the rows of the added 
columns.
 However, the conditions to keep/reject rows can only be applied to the rows of 
the columns in main input table (not the columns that are added with these 
options).
 
@@ -14886,9 +15794,27 @@ However, the conditions to keep/reject rows can only 
be applied to the rows of t
 Once all the input columns are read into memory, if any of them are vectors, 
you can extract a single-valued column from the vector columns at this stage.
 For more on vector columns, see @ref{Vector columns}.
 
-@item Rows from other file(s) (@option{--catrowfile} and @option{--catrowhdu})
+@item Creating vector columns (@option{--tovector})
+After column arithmetic, there is no other way to add new columns so the 
@option{--tovector} operator is applied at this stage.
+You can use it to merge multiple columns that are available in this stage to a 
single vector column.
+For more, see @ref{Vector columns}.
+
+@item Column arithmetic
+Once the final rows are selected in the requested order, column arithmetic is 
done (if requested).
+For more on column arithmetic, see @ref{Column arithmetic}.
+
+@end table
+
+
+@item Row-based operations
+Row-based operations only work within the rows of existing columns when they 
are activated.
+By default row-based operations are activated after column-based operations 
(which are mentioned above).
+If you need to give precedence to row-based operations, use 
@option{--rowfirst}.
+
+@table @asis
+@item Rows from other file(s) (@option{--catrowfile})
 With this feature, you can import rows from other tables (in other files, or 
other HDUs of the same FITS file).
-The same column selection of @option{--column} is applied to the tables given 
here.
+The same column selection of @option{--column} is applied to the tables given 
to this option.
 The column metadata (name, units and comments) will be taken from the main 
input.
 Two conditions are mandatory for adding rows:
 @itemize
@@ -14896,37 +15822,42 @@ Two conditions are mandatory for adding rows:
 The number of columns used from the new tables must be equal to the number of 
columns in memory, by the time control reaches here.
 @item
 The data type of each column (see @ref{Numeric data types}) should be the same 
as the respective column in memory by the time control reaches here.
-If the data types are different, you can use the type conversion operators of 
Table's column arithmetic on the inputs in a separate command first (see 
@ref{Numerical type conversion operators} and @ref{Column arithmetic}).
+If the data types are different, you can use the type conversion operators of 
column arithmetic which has higher precedence (and will therefore be applied 
before this by default).
+For more on type conversion, see @ref{Numerical type conversion operators} and 
@ref{Column arithmetic}).
 @end itemize
 
 @item Row selection by value in a column
+The following operations select rows based on the values in them.
+A more complete description of each of these options is given in @ref{Invoking 
asttable}.
+
 @itemize
 @item
-@option{--range}: only keep rows within a certain interval in given column.
+@option{--range}: only keep rows where the value in the given column is within 
a certain interval.
 @item
-@option{--inpolygon}: only keep rows within the polygon of @option{--polygon}.
+@option{--inpolygon}: only keep rows where the value is within the polygon of 
@option{--polygon}.
 @item
 @option{--outpolygon}: only keep rows outside the polygon of 
@option{--polygon}.
 @item
-@option{--equal}: only keep rows with specified value in given column.
+@option{--equal}: only keep rows with an specified value in given column.
 @item
 @option{--notequal}: only keep rows without specified value in given column.
 @item
 @option{--noblank}: only keep rows that are not blank in the given column(s).
 @end itemize
-These options take certain column(s) as input and remove some rows from the 
full table (all columns), based on the given limitations.
-They can be called any number of times (to limit the final rows based on 
values in different columns for example).
+
+These options can be called any number of times (to limit the final rows based 
on values in different columns for example).
 Since these are row-rejection operations, their internal order is irrelevant.
 In other words, it makes no difference if @option{--equal} is called before or 
after @option{--range} for example.
 
 As a side-effect, because NaN/blank values are defined to fail on any 
condition, these operations will also remove rows with NaN/blank values in the 
specified column they are checking.
 Also, the columns that are used for these operations do not necessarily have 
to be in the final output table (you may not need the column after doing the 
selection based on it).
 
-Even though these options are applied after merging columns from other tables, 
currently their condition-columns can only come from the main input table.
-In other words, even though the rows of the added columns (from another file) 
will also be selected with these options, the condition to keep/reject rows 
cannot be taken from the newly added columns.
+By default, these options are applied after merging columns from other tables.
+However, currently, the column given to these options can only come from the 
main input table.
+If you need to apply these operations on columns from 
@option{--catcolumnfile}, pipe the output of one instance of Table with 
@option{--catcolumnfile} into another instance of Table as suggested in the box 
above this list.
 
-These options are applied first because the speed of later operations can be 
greatly affected by the number of rows.
-For example, if you also call the @option{--sort} option, and your row 
selection will result in 50 rows (from an input of 1000 rows), limiting the 
number of rows can greatly speed up the sorting in your final output.
+These row-based operations options are applied first because the speed of 
later operations can be greatly affected by the number of rows.
+For example, if you also call the @option{--sort} option, and your row 
selection will result in 50 rows (from an input of 10000 rows), limiting the 
number of rows first will greatly speed up the sorting in your final output.
 
 @item Sorting (@option{--sort})
 Sort of the rows based on values in a certain column.
@@ -14946,24 +15877,21 @@ The column to sort by can only come from the main 
input table columns (not colum
 
 These options limit/select rows based on their position within the table (not 
their value in any certain column).
 
-@item Column arithmetic
-Once the final rows are selected in the requested order, column arithmetic is 
done (if requested).
-For more on column arithmetic, see @ref{Column arithmetic}.
-
-@item Creating vector columns (@option{--tovector})
-After column arithmetic, there is no other way to add new columns so the 
@option{--tovector} operator is applied at this stage.
-You can use it to merge multiple columns that are available in this stage to a 
single vector column.
-For more, see @ref{Vector columns}.
+@item Transpose vector columns (@option{--transpose})
+Transposing vector columns will not affect the number or metadata of columns, 
it will just re-arrange them in their 2D structure.
+As a result, after transposing, the number of rows changes, as well as the 
number of elements in each vector column.
+See the description of this option in @ref{Invoking asttable} for more (with 
an example).
+@end table
 
 @item Column metadata (@option{--colmetadata})
-Changing column metadata is necessary after column arithmetic or adding new 
columns from other tables (that were done above).
+Once the structure of the final table is set, you can set the column metadata 
just before finishing.
 
 @item Output row selection (@option{--noblankend})
 Only keep the output rows that do not have a blank value in the given 
column(s).
 For example, you may need to apply arithmetic operations on the columns 
(through @ref{Column arithmetic}) before rejecting the undesired rows.
 After the arithmetic operation is done, you can use the @code{where} operator 
to set the non-desired columns to NaN/blank and use @option{--noblankend} 
option to remove them just before writing the output.
 In other scenarios, you may want to remove blank values based on columns in 
another table.
-You can also use the modified metadata of the previous steps to use updated 
names!
+To help in readability, you can also use the final column names that you set 
with @option{--colmetadata}!
 See the example below for applying any generic value-based row selection based 
on @option{--noblankend}.
 @end table
 
@@ -14971,9 +15899,9 @@ As an example, let's review how Table interprets the 
command below.
 We are assuming that @file{table.fits} contains at least three columns: 
@code{RA}, @code{DEC} and @code{PARAM} and you only want the RA and Dec of the 
rows where @mymath{p\times 2<5} (@mymath{p} is the value of each row in the 
@code{PARAM} column).
 
 @example
-asttable table.fits -cRA,DEC --noblankend=MULTIP \
-         -c'arith PARAM 2 x set-i i i 5 gt nan where' \
-         --colmetadata=3,MULTIP,unit,"Description of column"
+$ asttable table.fits -cRA,DEC --noblankend=MULTIP \
+           -c'arith PARAM 2 x set-i i i 5 gt nan where' \
+           --colmetadata=3,MULTIP,unit,"Description of column"
 @end example
 
 @noindent
@@ -14995,14 +15923,12 @@ The lowest precedence operation is 
@option{--noblankend=MULTIP}.
 So only rows that are not blank/NaN in the @code{MULTIP} column are kept.
 @item
 Finally, the output table (with three columns) is written to the command-line.
-If you also want to print the column metadata, you can use the 
@option{--colinfoinstdout} option.
+If you also want to print the column metadata, you can use the @option{-O} (or 
@option{--colinfoinstdout}) option.
 Alternatively, if you want the output in a file, you can use the 
@option{--output} option to save the table in FITS or plain-text format.
 @end enumerate
 
-@cartouche
-@noindent
-@strong{Out of precedence:} It may happen that your desired operation needs a 
separate precedence.
-In this case you can pipe the output of Table into another call of Table and 
use the @option{--colinfoinstdout} option to preserve the metadata between the 
two calls.
+It may happen that your desired operation needs a separate precedence.
+In this case you can pipe the output of Table into another call of Table and 
use the @option{-O} (or @option{--colinfoinstdout}) option to preserve the 
metadata between the two calls.
 
 For example, let's assume that you want to sort the output table from the 
example command above based on the new @code{MULTIP} column.
 Since sorting is done prior to column arithmetic, you cannot do it in one 
command, but you can circumvent this limitation by simply piping the output 
(including metadata) to another call to Table:
@@ -15013,7 +15939,6 @@ asttable table.fits -cRA,DEC --noblankend=MULTIP 
--colinfoinstdout \
          --colmetadata=3,MULTIP,unit,"Description of column" \
          | asttable --sort=MULTIP --output=selected.fits
 @end example
-@end cartouche
 
 @node Invoking asttable,  , Operation precedence in Table, Table
 @subsection Invoking Table
@@ -15209,6 +16134,30 @@ See @option{--catcolumnfile} for more.
 @item --catcolumnrawname
 Do Not modify the names of the concatenated (appended) columns, see 
description in @option{--catcolumnfile}.
 
+@item --transpose
+Transpose (as in a matrix) the given vector column(s) individually.
+When this operation is done (see @ref{Operation precedence in Table}), only 
vector columns of the same data type and with the same number of elements 
should exist in the table.
+A usage of this operator is presented in the IFU spectroscopy tutorial in 
@ref{Extracting a single spectrum and plotting it}.
+
+As a generic example, see the commands below.
+The @file{in.txt} table below has two vector columns (each with three 
elements) in two rows.
+After running @command{asttable} with @option{--transpose}, you can see how 
the vector columns have two elements per row (@code{u8(3)} has been replaced by 
@code{u8(2)}), and that the table now has three rows.
+
+@example
+$ cat in.txt
+# Column 1: abc [nounits,u8(3),] First vector colum
+# Column 2: def [nounits,u8(3),] Second vector colum
+111  112  113  211  212  213
+121  122  123  221  222  223
+
+$ asttable in.txt --transpose -O
+# Column 1: abc [nounits,u8(2),] First vector colum
+# Column 2: def [nounits,u8(2),] Second vector colum
+111    121    211    221
+112    122    212    222
+113    123    213    223
+@end example
+
 @item --fromvector=STR,INT[,INT[,INT]]
 Extract the given tokens/elements from the given vector column into separate 
single-valued columns.
 The input vector column can be identified by its name or counter, see 
@ref{Selecting table columns}.
@@ -16664,7 +17613,7 @@ When only one crop is desired, the value to 
@option{--output} will be read as a
 If no output is specified or if it is a directory, the output file name will 
follow the automatic output names of Gnuastro, see @ref{Automatic output}: The 
string given to @option{--suffix} will be replaced with the @file{.fits} suffix 
of the input.
 @end itemize
 
-By default, as suggested by the FITS standard and implemented in all Gnuastro 
programs, the first/primary extension of the output files will only contain 
meta data.
+By default, as suggested by the FITS standard and implemented in all Gnuastro 
programs, the first/primary extension of the output files will only contain 
metadata.
 The cropped images/cubes will be written into the 2nd HDU of their respective 
FITS file (which is actually counted as @code{1} because HDU counting starts 
from @code{0}).
 However, if you want the cropped data to be written into the primary (0-th) 
HDU, run Crop with the @option{--primaryimghdu} option.
 
@@ -16719,7 +17668,7 @@ If the output file doesn't exist, this option is 
redundant.
 
 @item --primaryimghdu
 Write the output into the primary (0-th) HDU/extension of the output.
-By default, like all Gnuastro's default outputs, no data is written in the 
primary extension because the FITS standard suggests keeping that extension 
free of data and only for meta data.
+By default, like all Gnuastro's default outputs, no data is written in the 
primary extension because the FITS standard suggests keeping that extension 
free of data and only for metadata.
 
 @item -t
 @itemx --oneelemstdout
@@ -25117,6 +26066,7 @@ When the object cannot be represented as an ellipse, 
this interpretation breaks
 
 
 
+
 @node Adding new columns to MakeCatalog, MakeCatalog measurements, Measuring 
elliptical parameters, MakeCatalog
 @subsection Adding new columns to MakeCatalog
 
@@ -25210,7 +26160,7 @@ Columns/options that are unique to one catalog (only 
objects, or only clumps), a
 * Surface brightness measurements::  Various ways to measure surface 
brightness.
 * Morphology measurements nonparametric::  Non-parametric morphology.
 * Morphology measurements elliptical::  Elliptical morphology measurements.
-* Spectra measurement in a cube::  How to get the value of a label across all 
slices.
+* Measurements per slice spectra::  Measurements on each slice (like spectra).
 @end menu
 
 @node Identifier columns, Position measurements in pixels, MakeCatalog 
measurements, MakeCatalog measurements
@@ -25761,7 +26711,7 @@ This is only available for 3-dimensional datasets.
 When working with Integral Field Unit (IFU) datasets, this projection onto the 
first two dimensions would be a narrow-band image.
 @end table
 
-@node Morphology measurements elliptical, Spectra measurement in a cube, 
Morphology measurements nonparametric, MakeCatalog measurements
+@node Morphology measurements elliptical, Measurements per slice spectra, 
Morphology measurements nonparametric, MakeCatalog measurements
 @subsubsection Morphology measurements (elliptical)
 
 When your target objects are sufficiently ellipse-like, you can use the 
measurements below to quantify the various parameters of the ellipse.
@@ -25795,33 +26745,89 @@ The geometric (ignoring pixel values) axis ratio of 
the profile, assuming it is
 The geometric (ignoring pixel values) angle of the semi-major axis with the 
first FITS axis in degrees.
 @end table
 
-@node Spectra measurement in a cube,  , Morphology measurements elliptical, 
MakeCatalog measurements
-@subsubsection Spectra measurement in a cube
+@node Measurements per slice spectra,  , Morphology measurements elliptical, 
MakeCatalog measurements
+@subsubsection Measurements per slice (spectra)
 
+@cindex Spectrum
 @cindex 3D data-cubes
 @cindex Cubes (3D data)
 @cindex IFU: Integral Field Unit
 @cindex Integral field unit (IFU)
 @cindex Spectrum (of astronomical source)
-MakeCatalog can also do multi-valued measurements per label.
-Currently the only such measurement is the creation of spectra from 3D data 
cubes as discussed below:
+When the input is a 3D data cube, MakeCatalog has the following multi-valued 
measurements per label.
+For a tutorial on how to use these options and interpret their values, see 
@ref{Detecting lines and extracting spectra in 3D data}.
+
+These options will do measurements on each 2D slice of the input 3D cube; 
hence the common the format of @code{--*-in-slice}.
+Each slice usually corresponds to a certain wavelength, you can also think of 
these measurements as spectra.
+
+For each row (input label), each of the columns described here will contain 
multiple values as a vector column.
+The number of measurements in each column is the number of slices in the cube, 
or the size of the cube along the third dimension.
+To learn more about vector columns and how to manipulate them, see @ref{Vector 
columns}.
+For example usage of these columns in the tutorial above, see @ref{3D 
measurements and spectra} and @ref{Extracting a single spectrum and plotting 
it}.
+
+@noindent
+There are two ways to do each measurement on a slice for each label:
+@table @asis
+@item Only label
+The measurement will only be done on the voxels in the slice that are 
assciated to that label.
+These types of per-slice measurement therefore have the following properties:
+@itemize
+@item
+This will only be a measurement of that label and will not be affected by any 
other label.
+@item
+The number of voxels used in each slice can be different (usually only one or 
two voxels at the two extremes of the label (along the third dimension), and 
many in the middle.
+@item
+Since most labels are localized along the third dimension (maybe only covering 
20 slices out of thousands!), many of the measurements (on slices where the 
label doesn't exist) will be NaN (for the sum measurements for example) or 0 
(for the area measurements).
+@end itemize
+@item Projected label
+MakeCatalog will first project the 3D label into a 2D surface (along the third 
dimension) to get its 2D footprint.
+Afterwards, all the voxels in that 2D footprint will be measured all slices.
+All these measurements will have a @option{-proj-} component in their name.
+These types of per-slice measurement therefore has the following properties:
+
+@itemize
+@item
+A measurement will be done on each slice of the cube.
+@item
+All measurements will be done on the same surface area.
+@item
+Labels can overlap when they are projected onto the first two FITS dimensions 
(the spatial coordinates, not spectral).
+As a result, other emission lines or objects may contaminate the resulting 
spectrum for each label.
+@end itemize
+
+To help separate other labels, MakeCatalog can do a third type of measurement 
on each slice: measurements on the voxels that belong to other labels but 
overlap with the 2D projection.
+This can be used to see how much your projected measurement is affected by 
other emission sources (on the projected spectra) and also if multiple lines 
(labeled regions) belong to the same physical object.
+These measurements contain @code{-other-} in their name.
+@end table
 
 @table @option
-@item --spectrum
-Generate a spectrum (measurement along the first two FITS dimensions) for each 
label when the input dataset is a 3D data cube.
-With this option, a seprate table/spectrum will be generated for every label.
-If the output is a FITS file, each label's spectrum will be written into an 
extension of that file with a standard name of @code{SPECTRUM_NN} (the label 
will be replaced with @code{NN}).
-If the output is a plain text file, each label's spectrum will be written into 
a separate file with the suffix @file{spec-NN.txt}.
-See @ref{MakeCatalog output} for more on specifying MakeCatalog's output file.
-
-The spectra will contain one row for every slice (third FITS dimension) of the 
cube.
-Since the physical nature of the third dimension is different, two types of 
spectra (along with their errors) are measured:
-1) Sum of values in each slice that only have the requested label.
-2) Sum of values on the 2D projection of the whole label (the area of this 
projection can be requested with the @option{--area-xy} column above).
-
-Labels can overlap when they are projected onto the first two FITS dimensions 
(the spatial domain).
-To help separate them, MakeCatalog does a third measurement on each slice: the 
area, sum of values and error of all pixels that belong to other labels but 
overlap with the 2D projection.
-This can be used to see how reliable the emission line measurement is (on the 
projected spectra) and also if multiple lines (labeled regions) belong to the 
same physical object.
+
+@item --sum-in-slice
+[Only label] Sum of values in each slice.
+
+@item --sum-err-in-slice
+[Only label] Error in '--sum-in-slice'.
+
+@item --area-in-slice
+[Only label] Number of labeled in each slice.
+
+@item --sum-proj-in-slice
+[Projected label] Sum of projected area in each slice.
+
+@item --area-proj-in-slice:
+[Projected label] Number of voxels that are used in 
@option{--sum-proj-in-slice}.
+
+@item --sum-proj-err-in-slice
+[Projected label] Error of @option{--sum-proj-in-slice}.
+
+@item --area-other-in-slice
+[Projected label] Area of other label in projected area on each slice.
+
+@item --sum-other-in-slice
+[Projected label] Sum of other label in projected area on each slice.
+
+@item --sum-other-err-in-slice:
+[Projected label] Area in @option{--sum-other-in-slice}.
 @end table
 
 
@@ -28168,9 +29174,9 @@ The focus here is obtaining a physical insight into 
these equations (mainly for
 There are many books thoroughly deriving and proving all the equations with 
all possible initial conditions and assumptions for any abstract universe, 
interested readers can study those books.
 
 @menu
-* Distance on a 2D curved space::  Distances in 2D for simplicity
+* Distance on a 2D curved space::  Distances in 2D for simplicity.
 * Extending distance concepts to 3D::  Going to 3D (our real universe).
-* Invoking astcosmiccal::       How to run CosmicCalculator
+* Invoking astcosmiccal::       How to run CosmicCalculator.
 @end menu
 
 @node Distance on a 2D curved space, Extending distance concepts to 3D, 
CosmicCalculator, CosmicCalculator
@@ -28389,7 +29395,7 @@ $ astcosmiccal --redshift=0.8 --volume
 
 ## Print redshift and age of universe when Lyman-alpha line is
 ## at 6000 angstrom (another way to specify redshift).
-$ astcosmiccal --obsline=lyalpha,6000 --age
+$ astcosmiccal --obsline=Ly-alpha,6000 --age
 
 ## Print luminosity distance, angular diameter distance and age
 ## of universe in one row at redshift 0.4
@@ -28401,7 +29407,7 @@ $ astcosmiccal -l0.7 -m0.3 -z2.1
 
 ## Print wavelength of all pre-defined spectral lines when
 ## Lyman-alpha is observed at 4000 Angstroms.
-$ astcosmiccal --obsline=lyalpha,4000 --listlinesatz
+$ astcosmiccal --obsline=Ly-alpha,4000 --listlinesatz
 @end example
 
 The input parameters (current matter density, etc.) can be given as 
command-line options or in the configuration files, see @ref{Configuration 
files}.
@@ -28467,177 +29473,18 @@ Radiation density divided by the critical density in 
the current Universe (@myma
 @cindex Wavelength, rest-frame
 Find the redshift to use in next steps based on the rest-frame and observed 
wavelengths of a line.
 This option is thus an alternative to @code{--redshift} or @code{--velocity}, 
it cannot be used with them.
-Wavelengths are assumed to be in Angstroms.
+
 The first argument identifies the line.
-It can be one of the standard names below, or any rest-frame wavelength in 
Angstroms.
+It can be one of the standard names, or any rest-frame wavelength in Angstroms.
 The second argument is the observed wavelength of that line.
-For example, @option{--obsline=lyalpha,6000} is the same as 
@option{--obsline=1215.64,6000}.
-
-The pre-defined names are listed below, sorted from red (longer wavelength) to 
blue (shorter wavelength).
-You can get this list on the command-line with the @option{--listlines}.
-
-@table @code
-@item siired
-[6731@AA{}] SII doublet's redder line.
-
-@item sii
-@cindex Doublet: SII
-@cindex SII doublet
-[6724@AA{}] SII doublet's mean center at .
-
-@item siiblue
-[6717@AA{}] SII doublet's bluer line.
-
-@item niired
-[6584@AA{}] NII doublet's redder line.
-
-@item nii
-@cindex Doublet: NII
-@cindex NII doublet
-[6566@AA{}] NII doublet's mean center.
-
-@item halpha
-@cindex H-alpha
-[6562.8@AA{}] H-@mymath{\alpha} line.
-
-@item niiblue
-[6548@AA{}] NII doublet's bluer line.
-
-@item oiiired-vis
-[5007@AA{}] OIII doublet's redder line in the visible.
-
-@item oiii-vis
-@cindex Doublet: OIII (visible)
-@cindex OIII doublet in visible
-[4983@AA{}] OIII doublet's mean center in the visible.
-
-@item oiiiblue-vis
-[4959@AA{}] OIII doublet's bluer line in the visible.
-
-@item hbeta
-@cindex H-beta
-[4861.36@AA{}] H-@mymath{\beta} line.
-
-@item heii-vis
-[4686@AA{}] HeII doublet's redder line in the visible.
-
-@item hgamma
-@cindex H-gamma
-[4340.46@AA{}] H-@mymath{\gamma} line.
-
-@item hdelta
-@cindex H-delta
-[4101.74@AA{}] H-@mymath{\delta} line.
+For example, @option{--obsline=Ly-alpha,6000} is the same as 
@option{--obsline=1215.64,6000}.
+Wavelengths are assumed to be in Angstroms by default (other units can be 
selected with @option{--lineunit}, see @ref{CosmicCalculator spectral line 
calculations}).
 
-@item hepsilon
-@cindex H-epsilon
-[3970.07@AA{}] H-@mymath{\epsilon} line.
-
-@item neiii
-[3869@AA{}] NEIII line.
-
-@item oiired
-[3729@AA{}] OII doublet's redder line.
-
-@item oii
-@cindex Doublet: OII
-@cindex OII doublet
-[3727.5@AA{}] OII doublet's mean center.
-
-@item oiiblue
-[3726@AA{}] OII doublet's bluer line.
-
-@item blimit
-@cindex Balmer limit
-[3646@AA{}] Balmer limit.
-
-@item mgiired
-[2803@AA{}] MgII doublet's redder line.
-
-@item mgii
-@cindex Doublet: MgII
-@cindex MgII doublet
-[2799.5@AA{}] MgII doublet's mean center.
-
-@item mgiiblue
-[2796@AA{}] MgII doublet's bluer line.
-
-@item ciiired
-[1909@AA{}] CIII doublet's redder line.
-
-@item ciii
-@cindex Doublet: CIII
-@cindex CIII doublet
-[1908@AA{}] CIII doublet's mean center.
-
-@item ciiiblue
-[1907@AA{}] CIII doublet's bluer line.
-
-@item si_iiired
-[1892@AA{}] SiIII doublet's redder line.
-
-@item si_iii
-@cindex Doublet: SiIII
-@cindex SiIII doublet
-[1887.5@AA{}] SiIII doublet's mean center.
-
-@item si_iiiblue
-[1883@AA{}] SiIII doublet's bluer line.
-
-@item oiiired-uv
-[1666@AA{}] OIII doublet's redder line in the ultra-violet.
-
-@item oiii-uv
-@cindex Doublet: OIII (in UV)
-@cindex OIII doublet in UV
-[1663.5@AA{}] OIII doublet's mean center in the ultra-violet.
-
-@item oiiiblue-uv
-[1661@AA{}] OIII doublet's bluer line in the ultra-violet.
-
-@item heii-uv
-[1640@AA{}] HeII doublet's bluer line in the ultra-violet.
-
-@item civred
-[1551@AA{}] CIV doublet's redder line.
-
-@item civ
-@cindex Doublet: CIV
-@cindex CIV doublet
-[1549@AA{}] CIV doublet's mean center.
-
-@item civblue
-[1548@AA{}] CIV doublet's bluer line.
-
-@item nv
-[1240@AA{}] NV (four times ionized Sodium).
-
-@item lyalpha
-@cindex Lyman-alpha
-[1215.67@AA{}] Lyman-@mymath{\alpha} line.
-
-@item lybeta
-@cindex Lyman-beta
-[1025.7@AA{}] Lyman-@mymath{\beta} line.
-
-@item lygamma
-@cindex Lyman-gamma
-[972.54@AA{}] Lyman-@mymath{\gamma} line.
-
-@item lydelta
-@cindex Lyman-delta
-[949.74@AA{}] Lyman-@mymath{\delta} line.
-
-@item lyepsilon
-@cindex Lyman-epsilon
-[937.80@AA{}] Lyman-@mymath{\epsilon} line.
-
-@item lylimit
-@cindex Lyman limit
-[912@AA{}] Lyman limit.
-
-@end table
+The list of pre-defined names for the lines in Gnuastro's database is 
available by running
 
+@example
+$ astcosmiccal --listlines
+@end example
 @end table
 
 
@@ -28782,6 +29629,8 @@ Note that @option{--obsline} is an input parameter, so 
it is discussed (with the
 
 @item --listlines
 List the pre-defined rest frame spectral line wavelengths and their names on 
standard output, then abort CosmicCalculator.
+The units of the displayed wavelengths for each line can be determined with 
@option{--lineunit} (see below).
+
 When this option is given, other operations on the command-line will be 
ignored.
 This is convenient when you forget the specific name of the spectral line used 
within Gnuastro, or when you forget the exact wavelength of a certain line.
 
@@ -28802,15 +29651,35 @@ And if you want to use the list later and have it as 
a table in a file, you can
 @item --listlinesatz
 Similar to @option{--listlines} (above), but the printed wavelength is not in 
the rest frame, but redshifted to the given redshift.
 Recall that the redshift can be specified by @option{--redshift} directly or 
by @option{--obsline}, see @ref{CosmicCalculator input options}.
+For an example usage of this option, see @ref{Viewing spectra and redshifted 
lines}.
 
 @item -i STR/FLT
 @itemx --lineatz=STR/FLT
 The wavelength of the specified line at the redshift given to CosmicCalculator.
 The line can be specified either by its name or directly as a number (its 
wavelength).
+The units of the displayed wavelengths for each line can be determined with 
@option{--lineunit} (see below).
+
 To get the list of pre-defined names for the lines and their wavelength, you 
can use the @option{--listlines} option, see @ref{CosmicCalculator input 
options}.
 In the former case (when a name is given), the returned number is in units of 
Angstroms.
 In the latter (when a number is given), the returned value is the same units 
of the input number (assuming it is a wavelength).
 
+@item --lineunit=STR
+The units to display line wavelengths above.
+It can take the following four values.
+If you need any other unit, please contact us at @code{bug-gnuastro@@gnu.org}.
+
+@table @code
+@item m
+Meter.
+@item micro-m
+Micrometer or @mymath{10^{-6}m}.
+@item nano-m
+Nanometer, or @mymath{10^{-9}m}.
+@item angstrom
+Angstrom or @mymath{10^{-10}m}; the default unit when this option is not 
called.
+@end table
+
+
 @end table
 
 
@@ -33403,7 +34272,7 @@ However (when necessary) @code{dsize} must not have any 
zero values (a dimension
 @deftypefun {gal_data_t *} gal_data_alloc_empty (size_t @code{ndim}, size_t 
@code{minmapsize}, int @code{quietmmap})
 Allocate an empty dataset with a certain number of dimensions, but no 'array' 
component.
 The @code{size} element will be set to zero and the @code{dsize} array will be 
properly allocated (based on the number of dimensions), but all elements will 
be zero.
-This is useful in scenarios where you just need a @code{gal_data_t} for meta 
data.
+This is useful in scenarios where you just need a @code{gal_data_t} for 
metadata.
 @end deftypefun
 
 
@@ -33908,11 +34777,11 @@ Extract space-separated components of the input 
string.
 If any space element should be kept (and not considered as a delimiter between 
two tokens), precede it with a back-slash (@code{\}).
 @end deftypefun
 
-@deftypefun {char *} gal_list_str_cat (gal_list_str_t @code{*list})
-Concatenate (append) the input list of strings into a single space-separated 
string.
+@deftypefun {char *} gal_list_str_cat (gal_list_str_t @code{*list}, char 
@code{delimiter})
+Concatenate (append) the input list of strings into a single string where each 
node is separated from the next with the given @code{delimiter}.
 The space for the output string is allocated by this function and should be 
freed when you have finished with it.
 
-If there is any SPACE characters in any of the elements, a back-slash 
(@code{\}) will be printed before the SPACE character.
+If there is any delimiter characters are present in any of the elements, a 
back-slash (@code{\}) will be printed before the SPACE character.
 This is necessary, otherwise, a function like @code{gal_list_str_extract} will 
not be able to extract the elements back into separate elements in a list.
 @end deftypefun
 
@@ -34695,7 +35564,7 @@ use these anywhere you see the @code{tableformat} 
variable.
 @deffnx Macro GAL_TABLE_SEARCH_COMMENT
 When the desired column is not a number, these values determine if the
 string to match, or regular expression to search, be in the @emph{name},
-@emph{units} or @emph{comments} of the column meta data. These values
+@emph{units} or @emph{comments} of the column metadata. These values
 should be used for the @code{searchin} variables of the functions.
 @end deffn
 
@@ -37990,48 +38859,38 @@ inverse:    AFTER[ perm[i] ] = BEFORE[ i       ]     
i = 0 .. N-1
 @end example
 
 @cindex GNU Scientific Library
-The functions here are a re-implementation of the GNU Scientific Library's
-@code{gsl_permute} function. The reason we did not use that function was
-that it uses system-specific types (like @code{long} and @code{int}) which
-can have different widths on different systems, hence are not easily
-convertible to Gnuastro's fixed width types (see @ref{Numeric data
-types}). There is also a separate function for each type, heavily using
-macros to allow a @code{base} function to work on all the types. Thus it is
-hard to read/understand. Hence, Gnuastro contains a re-write of their steps
-in a new type-agnostic method which is a single function that can work on
-any type.
-
-As described in GSL's source code and manual, this implementation comes
-from Donald Knuth's @emph{Art of computer programming} book, in the
-"Sorting and Searching" chapter of Volume 3 (3rd ed). Exercise 10 of
-Section 5.2 defines the problem and in the answers, Knuth describes the
-solution. So if you are interested, please have a look there for more.
-
-We are in contact with the GSL developers and in the
-future@footnote{Gnuastro's @url{http://savannah.gnu.org/task/?14497, Task
-14497}. If this task is still ``postponed'' when you are reading this and
-you are interested to help, your contributions would be very welcome. Both 
Gnuastro
-and GSL developers are very busy, hence both would appreciate your help.}
-we will submit these implementations to GSL. If they are finally
-incorporated there, we will delete this section in future versions.
+The functions here are a re-implementation of the GNU Scientific Library's 
@code{gsl_permute} function.
+The reason we did not use that function was that it uses system-specific types 
(like @code{long} and @code{int}) which can have different widths on different 
systems, hence are not easily convertible to Gnuastro's fixed width types (see 
@ref{Numeric data types}).
+There is also a separate function for each type, heavily using macros to allow 
a @code{base} function to work on all the types.
+Thus it is hard to read/understand.
+Hence, Gnuastro contains a re-write of their steps in a new type-agnostic 
method which is a single function that can work on any type.
+
+As described in GSL's source code and manual, this implementation comes from 
Donald Knuth's @emph{Art of computer programming} book, in the "Sorting and 
Searching" chapter of Volume 3 (3rd ed).
+Exercise 10 of Section 5.2 defines the problem and in the answers, Knuth 
describes the solution.
+So if you are interested, please have a look there for more.
+
+We are in contact with the GSL developers and in the 
future@footnote{Gnuastro's @url{http://savannah.gnu.org/task/?14497, Task 
14497}.
+If this task is still ``postponed'' when you are reading this and you are 
interested to help, your contributions would be very welcome.
+Both Gnuastro and GSL developers are very busy, hence both would appreciate 
your help.} we will submit these implementations to GSL.
+If they are finally incorporated there, we will delete this section in future 
versions.
 
 @deftypefun void gal_permutation_check (size_t @code{*permutation}, size_t 
@code{size})
-Print how @code{permutation} will re-order an array that has @code{size}
-elements for each element in one one line.
+Print how @code{permutation} will re-order an array that has @code{size} 
elements for each element in one one line.
 @end deftypefun
 
 @deftypefun void gal_permutation_apply (gal_data_t @code{*input}, size_t 
@code{*permutation})
-Apply @code{permutation} on the @code{input} dataset (can have any type),
-see above for the definition of permutation.
+Apply @code{permutation} on the @code{input} dataset (can have any type), see 
above for the definition of permutation.
 @end deftypefun
 
 @deftypefun void gal_permutation_apply_inverse (gal_data_t @code{*input}, 
size_t @code{*permutation})
-Apply the inverse of @code{permutation} on the @code{input} dataset (can
-have any type), see above for the definition of permutation.
+Apply the inverse of @code{permutation} on the @code{input} dataset (can have 
any type), see above for the definition of permutation.
 @end deftypefun
 
-
-
+@deftypefun void gal_permutation_transpose_2d (gal_data_t @code{*input})
+Transpose an input 2D matrix into a new dataset.
+If the input is not a square, this function will change the 
@code{input->array} element to a newly allocated array (the old one will be 
freed internally).
+Therefore, in case you have already stored @code{input->array} for other usage 
@emph{before} this function, and the input is not a square, be sure to update 
the previously stored pointer if the input is not a square.
+@end deftypefun
 
 
 @node Matching, Statistical operations, Permutations, Gnuastro library
@@ -38080,7 +38939,8 @@ If @code{aperture[1]==1}, the aperture will be a circle 
of radius @code{aperture
 When the aperture is an ellipse, distances between the points are also 
calculated in the respective elliptical distances (@mymath{r_{el}} in 
@ref{Defining an ellipse and ellipsoid}).
 
 @strong{Output permutations ignore internal sorting}: the output permutations 
will correspond to the initial inputs.
-Therefore, even when @code{inplace!=0} (and this function re-arranges the 
inputs in place), the output permutation will correspond to original (possibly 
non-sorted) inputs. The reason for this is that you rarely want to permute the 
actual positional columns after the match.
+Therefore, even when @code{inplace!=0} (and this function re-arranges the 
inputs in place), the output permutation will correspond to original (possibly 
non-sorted) inputs.
+The reason for this is that you rarely want to permute the actual positional 
columns after the match.
 Usually, you also have other columns (such as the magnitude and morphology) 
and you want to find how they differ between the objects that match.
 Once you have the permutations, they can be applied to those other columns 
(see @ref{Permutations}) and the higher-level processing can continue.
 So if you do not need the coordinate columns for the rest of your analysis, it 
is better to set @code{inplace=1}.
@@ -39939,40 +40799,246 @@ All these functions are declared in 
@file{gnuastro/spectra.h}.
 @cindex Doublet: MgII
 @cindex Doublet: CIII
 @deffn  Macro GAL_SPECLINES_INVALID
-@deffnx Macro GAL_SPECLINES_SIIRED
-@deffnx Macro GAL_SPECLINES_SII
-@deffnx Macro GAL_SPECLINES_SIIBLUE
-@deffnx Macro GAL_SPECLINES_NIIRED
-@deffnx Macro GAL_SPECLINES_NII
-@deffnx Macro GAL_SPECLINES_HALPHA
-@deffnx Macro GAL_SPECLINES_NIIBLUE
-@deffnx Macro GAL_SPECLINES_OIIIRED
-@deffnx Macro GAL_SPECLINES_OIII
-@deffnx Macro GAL_SPECLINES_OIIIBLUE
-@deffnx Macro GAL_SPECLINES_HBETA
-@deffnx Macro GAL_SPECLINES_HEIIRED
-@deffnx Macro GAL_SPECLINES_HGAMMA
-@deffnx Macro GAL_SPECLINES_HDELTA
-@deffnx Macro GAL_SPECLINES_HEPSILON
-@deffnx Macro GAL_SPECLINES_NEIII
-@deffnx Macro GAL_SPECLINES_OIIRED
-@deffnx Macro GAL_SPECLINES_OII
-@deffnx Macro GAL_SPECLINES_OIIBLUE
-@deffnx Macro GAL_SPECLINES_BLIMIT
-@deffnx Macro GAL_SPECLINES_MGIIRED
-@deffnx Macro GAL_SPECLINES_MGII
-@deffnx Macro GAL_SPECLINES_MGIIBLUE
-@deffnx Macro GAL_SPECLINES_CIIIRED
-@deffnx Macro GAL_SPECLINES_CIII
-@deffnx Macro GAL_SPECLINES_CIIIBLUE
-@deffnx Macro GAL_SPECLINES_HEIIBLUE
-@deffnx Macro GAL_SPECLINES_LYALPHA
-@deffnx Macro GAL_SPECLINES_LYLIMIT
-@deffnx Macro GAL_SPECLINES_INVALID_MAX
-Internal values/identifiers for specific spectral lines as is clear from
-their names.
-Note the first and last one, they can be used when parsing the lines 
automatically: both do not correspond to any line, but their integer values 
correspond to the two integers just before and after the first and last line 
identifier.
-
+@deffnx Macro GAL_SPECLINES_Ne_VIII_770
+@deffnx Macro GAL_SPECLINES_Ne_VIII_780
+@deffnx Macro GAL_SPECLINES_Ly_epsilon
+@deffnx Macro GAL_SPECLINES_Ly_delta
+@deffnx Macro GAL_SPECLINES_Ly_gamma
+@deffnx Macro GAL_SPECLINES_C_III_977
+@deffnx Macro GAL_SPECLINES_N_III_989
+@deffnx Macro GAL_SPECLINES_N_III_991_51
+@deffnx Macro GAL_SPECLINES_N_III_991_57
+@deffnx Macro GAL_SPECLINES_Ly_beta
+@deffnx Macro GAL_SPECLINES_O_VI_1031
+@deffnx Macro GAL_SPECLINES_O_VI_1037
+@deffnx Macro GAL_SPECLINES_Ar_I_1066
+@deffnx Macro GAL_SPECLINES_Ly_alpha
+@deffnx Macro GAL_SPECLINES_N_V_1238
+@deffnx Macro GAL_SPECLINES_N_V_1242
+@deffnx Macro GAL_SPECLINES_Si_II_1260
+@deffnx Macro GAL_SPECLINES_Si_II_1264
+@deffnx Macro GAL_SPECLINES_O_I_1302
+@deffnx Macro GAL_SPECLINES_C_II_1334
+@deffnx Macro GAL_SPECLINES_C_II_1335
+@deffnx Macro GAL_SPECLINES_Si_IV_1393
+@deffnx Macro GAL_SPECLINES_O_IV_1397
+@deffnx Macro GAL_SPECLINES_O_IV_1399
+@deffnx Macro GAL_SPECLINES_Si_IV_1402
+@deffnx Macro GAL_SPECLINES_N_IV_1486
+@deffnx Macro GAL_SPECLINES_C_IV_1548
+@deffnx Macro GAL_SPECLINES_C_IV_1550
+@deffnx Macro GAL_SPECLINES_He_II_1640
+@deffnx Macro GAL_SPECLINES_O_III_1660
+@deffnx Macro GAL_SPECLINES_O_III_1666
+@deffnx Macro GAL_SPECLINES_N_III_1746
+@deffnx Macro GAL_SPECLINES_N_III_1748
+@deffnx Macro GAL_SPECLINES_Al_III_1854
+@deffnx Macro GAL_SPECLINES_Al_III_1862
+@deffnx Macro GAL_SPECLINES_Si_III
+@deffnx Macro GAL_SPECLINES_C_III_1908
+@deffnx Macro GAL_SPECLINES_N_II_2142
+@deffnx Macro GAL_SPECLINES_O_III_2320
+@deffnx Macro GAL_SPECLINES_C_II_2323
+@deffnx Macro GAL_SPECLINES_C_II_2324
+@deffnx Macro GAL_SPECLINES_Fe_XI_2648
+@deffnx Macro GAL_SPECLINES_He_II_2733
+@deffnx Macro GAL_SPECLINES_Mg_V_2782
+@deffnx Macro GAL_SPECLINES_Mg_II_2795
+@deffnx Macro GAL_SPECLINES_Mg_II_2802
+@deffnx Macro GAL_SPECLINES_Fe_IV_2829
+@deffnx Macro GAL_SPECLINES_Fe_IV_2835
+@deffnx Macro GAL_SPECLINES_Ar_IV_2853
+@deffnx Macro GAL_SPECLINES_Ar_IV_2868
+@deffnx Macro GAL_SPECLINES_Mg_V_2928
+@deffnx Macro GAL_SPECLINES_He_I_2945
+@deffnx Macro GAL_SPECLINES_O_III_3132
+@deffnx Macro GAL_SPECLINES_He_I_3187
+@deffnx Macro GAL_SPECLINES_He_II_3203
+@deffnx Macro GAL_SPECLINES_O_III_3312
+@deffnx Macro GAL_SPECLINES_Ne_V_3345
+@deffnx Macro GAL_SPECLINES_Ne_V_3425
+@deffnx Macro GAL_SPECLINES_O_III_3444
+@deffnx Macro GAL_SPECLINES_N_I_3466_4
+@deffnx Macro GAL_SPECLINES_N_I_3466_5
+@deffnx Macro GAL_SPECLINES_He_I_3487
+@deffnx Macro GAL_SPECLINES_Fe_VII_3586
+@deffnx Macro GAL_SPECLINES_Fe_VI_3662
+@deffnx Macro GAL_SPECLINES_H_19
+@deffnx Macro GAL_SPECLINES_H_18
+@deffnx Macro GAL_SPECLINES_H_17
+@deffnx Macro GAL_SPECLINES_H_16
+@deffnx Macro GAL_SPECLINES_H_15
+@deffnx Macro GAL_SPECLINES_H_14
+@deffnx Macro GAL_SPECLINES_O_II_3726
+@deffnx Macro GAL_SPECLINES_O_II_3728
+@deffnx Macro GAL_SPECLINES_H_13
+@deffnx Macro GAL_SPECLINES_H_12
+@deffnx Macro GAL_SPECLINES_Fe_VII_3758
+@deffnx Macro GAL_SPECLINES_H_11
+@deffnx Macro GAL_SPECLINES_H_10
+@deffnx Macro GAL_SPECLINES_H_9
+@deffnx Macro GAL_SPECLINES_Fe_V_3839
+@deffnx Macro GAL_SPECLINES_Ne_III_3868
+@deffnx Macro GAL_SPECLINES_He_I_3888
+@deffnx Macro GAL_SPECLINES_H_8
+@deffnx Macro GAL_SPECLINES_Fe_V_3891
+@deffnx Macro GAL_SPECLINES_Fe_V_3911
+@deffnx Macro GAL_SPECLINES_Ne_III_3967
+@deffnx Macro GAL_SPECLINES_H_epsilon
+@deffnx Macro GAL_SPECLINES_He_I_4026
+@deffnx Macro GAL_SPECLINES_S_II_4068
+@deffnx Macro GAL_SPECLINES_Fe_V_4071
+@deffnx Macro GAL_SPECLINES_S_II_4076
+@deffnx Macro GAL_SPECLINES_H_delta
+@deffnx Macro GAL_SPECLINES_He_I_4143
+@deffnx Macro GAL_SPECLINES_Fe_II_4178
+@deffnx Macro GAL_SPECLINES_Fe_V_4180
+@deffnx Macro GAL_SPECLINES_Fe_II_4233
+@deffnx Macro GAL_SPECLINES_Fe_V_4227
+@deffnx Macro GAL_SPECLINES_Fe_II_4287
+@deffnx Macro GAL_SPECLINES_Fe_II_4304
+@deffnx Macro GAL_SPECLINES_O_II_4317
+@deffnx Macro GAL_SPECLINES_H_gamma
+@deffnx Macro GAL_SPECLINES_O_III_4363
+@deffnx Macro GAL_SPECLINES_Ar_XIV
+@deffnx Macro GAL_SPECLINES_O_II_4414
+@deffnx Macro GAL_SPECLINES_Fe_II_4416
+@deffnx Macro GAL_SPECLINES_Fe_II_4452
+@deffnx Macro GAL_SPECLINES_He_I_4471
+@deffnx Macro GAL_SPECLINES_Fe_II_4489
+@deffnx Macro GAL_SPECLINES_Fe_II_4491
+@deffnx Macro GAL_SPECLINES_N_III_4510
+@deffnx Macro GAL_SPECLINES_Fe_II_4522
+@deffnx Macro GAL_SPECLINES_Fe_II_4555
+@deffnx Macro GAL_SPECLINES_Fe_II_4582
+@deffnx Macro GAL_SPECLINES_Fe_II_4583
+@deffnx Macro GAL_SPECLINES_Fe_II_4629
+@deffnx Macro GAL_SPECLINES_N_III_4634
+@deffnx Macro GAL_SPECLINES_N_III_4640
+@deffnx Macro GAL_SPECLINES_N_III_4641
+@deffnx Macro GAL_SPECLINES_C_III_4647
+@deffnx Macro GAL_SPECLINES_C_III_4650
+@deffnx Macro GAL_SPECLINES_C_III_5651
+@deffnx Macro GAL_SPECLINES_Fe_III_4658
+@deffnx Macro GAL_SPECLINES_He_II_4685
+@deffnx Macro GAL_SPECLINES_Ar_IV_4711
+@deffnx Macro GAL_SPECLINES_Ar_IV_4740
+@deffnx Macro GAL_SPECLINES_H_beta
+@deffnx Macro GAL_SPECLINES_Fe_VII_4893
+@deffnx Macro GAL_SPECLINES_Fe_IV_4903
+@deffnx Macro GAL_SPECLINES_Fe_II_4923
+@deffnx Macro GAL_SPECLINES_O_III_4958
+@deffnx Macro GAL_SPECLINES_O_III_5006
+@deffnx Macro GAL_SPECLINES_Fe_II_5018
+@deffnx Macro GAL_SPECLINES_Fe_III_5084
+@deffnx Macro GAL_SPECLINES_Fe_VI_5145
+@deffnx Macro GAL_SPECLINES_Fe_VII_5158
+@deffnx Macro GAL_SPECLINES_Fe_II_5169
+@deffnx Macro GAL_SPECLINES_Fe_VI_5176
+@deffnx Macro GAL_SPECLINES_Fe_II_5197
+@deffnx Macro GAL_SPECLINES_N_I_5200
+@deffnx Macro GAL_SPECLINES_Fe_II_5234
+@deffnx Macro GAL_SPECLINES_Fe_IV_5236
+@deffnx Macro GAL_SPECLINES_Fe_III_5270
+@deffnx Macro GAL_SPECLINES_Fe_II_5276
+@deffnx Macro GAL_SPECLINES_Fe_VII_5276
+@deffnx Macro GAL_SPECLINES_Fe_XIV
+@deffnx Macro GAL_SPECLINES_Ca_V
+@deffnx Macro GAL_SPECLINES_Fe_II_5316_6
+@deffnx Macro GAL_SPECLINES_Fe_II_5316_7
+@deffnx Macro GAL_SPECLINES_Fe_VI_5335
+@deffnx Macro GAL_SPECLINES_Fe_VI_5424
+@deffnx Macro GAL_SPECLINES_Cl_III_5517
+@deffnx Macro GAL_SPECLINES_Cl_III_5537
+@deffnx Macro GAL_SPECLINES_Fe_VI_5637
+@deffnx Macro GAL_SPECLINES_Fe_VI_5677
+@deffnx Macro GAL_SPECLINES_C_III_5697
+@deffnx Macro GAL_SPECLINES_Fe_VII_5720
+@deffnx Macro GAL_SPECLINES_N_II_5754
+@deffnx Macro GAL_SPECLINES_C_IV_5801
+@deffnx Macro GAL_SPECLINES_C_IV_5811
+@deffnx Macro GAL_SPECLINES_He_I_5875
+@deffnx Macro GAL_SPECLINES_O_I_6046
+@deffnx Macro GAL_SPECLINES_Fe_VII_6087
+@deffnx Macro GAL_SPECLINES_O_I_6300
+@deffnx Macro GAL_SPECLINES_S_III_6312
+@deffnx Macro GAL_SPECLINES_Si_II_6347
+@deffnx Macro GAL_SPECLINES_O_I_6363
+@deffnx Macro GAL_SPECLINES_Fe_II_6369
+@deffnx Macro GAL_SPECLINES_Fe_X
+@deffnx Macro GAL_SPECLINES_Fe_II_6516
+@deffnx Macro GAL_SPECLINES_N_II_6548
+@deffnx Macro GAL_SPECLINES_H_alpha
+@deffnx Macro GAL_SPECLINES_N_II_6583
+@deffnx Macro GAL_SPECLINES_S_II_6716
+@deffnx Macro GAL_SPECLINES_S_II_6730
+@deffnx Macro GAL_SPECLINES_O_I_7002
+@deffnx Macro GAL_SPECLINES_Ar_V
+@deffnx Macro GAL_SPECLINES_He_I_7065
+@deffnx Macro GAL_SPECLINES_Ar_III_7135
+@deffnx Macro GAL_SPECLINES_Fe_II_7155
+@deffnx Macro GAL_SPECLINES_Ar_IV_7170
+@deffnx Macro GAL_SPECLINES_Fe_II_7172
+@deffnx Macro GAL_SPECLINES_C_II_7236
+@deffnx Macro GAL_SPECLINES_Ar_IV_7237
+@deffnx Macro GAL_SPECLINES_O_I_7254
+@deffnx Macro GAL_SPECLINES_Ar_IV_7262
+@deffnx Macro GAL_SPECLINES_He_I_7281
+@deffnx Macro GAL_SPECLINES_O_II_7319
+@deffnx Macro GAL_SPECLINES_O_II_7330
+@deffnx Macro GAL_SPECLINES_Ni_II_7377
+@deffnx Macro GAL_SPECLINES_Ni_II_7411
+@deffnx Macro GAL_SPECLINES_Fe_II_7452
+@deffnx Macro GAL_SPECLINES_N_I_7468
+@deffnx Macro GAL_SPECLINES_S_XII
+@deffnx Macro GAL_SPECLINES_Ar_III_7751
+@deffnx Macro GAL_SPECLINES_He_I_7816
+@deffnx Macro GAL_SPECLINES_Ar_I_7868
+@deffnx Macro GAL_SPECLINES_Ni_III
+@deffnx Macro GAL_SPECLINES_Fe_XI_7891
+@deffnx Macro GAL_SPECLINES_He_II_8236
+@deffnx Macro GAL_SPECLINES_Pa_20
+@deffnx Macro GAL_SPECLINES_Pa_19
+@deffnx Macro GAL_SPECLINES_Pa_18
+@deffnx Macro GAL_SPECLINES_O_I_8446
+@deffnx Macro GAL_SPECLINES_Pa_17
+@deffnx Macro GAL_SPECLINES_Ca_II_8498
+@deffnx Macro GAL_SPECLINES_Pa_16
+@deffnx Macro GAL_SPECLINES_Ca_II_8542
+@deffnx Macro GAL_SPECLINES_Pa_15
+@deffnx Macro GAL_SPECLINES_Cl_II
+@deffnx Macro GAL_SPECLINES_Pa_14
+@deffnx Macro GAL_SPECLINES_Fe_II_8616
+@deffnx Macro GAL_SPECLINES_Ca_II_8662
+@deffnx Macro GAL_SPECLINES_Pa_13
+@deffnx Macro GAL_SPECLINES_N_I_8680
+@deffnx Macro GAL_SPECLINES_N_I_8703
+@deffnx Macro GAL_SPECLINES_N_I_8711
+@deffnx Macro GAL_SPECLINES_Pa_12
+@deffnx Macro GAL_SPECLINES_Pa_11
+@deffnx Macro GAL_SPECLINES_Fe_II_8891
+@deffnx Macro GAL_SPECLINES_Pa_10
+@deffnx Macro GAL_SPECLINES_S_III_9068
+@deffnx Macro GAL_SPECLINES_Pa_9
+@deffnx Macro GAL_SPECLINES_S_III_9531
+@deffnx Macro GAL_SPECLINES_Pa_epsilon
+@deffnx Macro GAL_SPECLINES_C_I_9824
+@deffnx Macro GAL_SPECLINES_C_I_9850
+@deffnx Macro GAL_SPECLINES_S_VIII
+@deffnx Macro GAL_SPECLINES_He_I_10027
+@deffnx Macro GAL_SPECLINES_He_I_10031
+@deffnx Macro GAL_SPECLINES_Pa_delta
+@deffnx Macro GAL_SPECLINES_S_II_10286
+@deffnx Macro GAL_SPECLINES_S_II_10320
+@deffnx Macro GAL_SPECLINES_S_II_10336
+@deffnx Macro GAL_SPECLINES_Fe_XIII
+@deffnx Macro GAL_SPECLINES_He_I_10830
+@deffnx Macro GAL_SPECLINES_Pa_gamma
+@deffnx Macro GAL_SPECLINES_NUMBER
+Internal values/identifiers for recognized spectral lines as is clear from 
their names.
+They are based on the UV an optical table of galaxy emission lines of Drew 
Chojnowski@footnote{@url{http://astronomy.nmsu.edu/drewski/tableofemissionlines.html}}.
+
+Note the first and last macros, they can be used when parsing the lines 
automatically: both do not correspond to any line, but their integer values 
correspond to the two integers just before and after the first and last line 
identifier:
 @code{GAL_SPECLINES_INVALID} has a value of zero, and allows you to have a 
fixed integer which never corresponds to a line.
 @code{GAL_SPECLINES_INVALID_MAX} is the total number of pre-defined lines, 
plus one.
 So you can parse all the known lines with a @code{for} loop like this:
@@ -39981,70 +41047,14 @@ for(i=1;i<GAL_SPECLINES_INVALID_MAX;++i)
 @end example
 @end deffn
 
-@deffn  Macro GAL_SPECLINES_ANGSTROM_SIIRED
-@deffnx Macro GAL_SPECLINES_ANGSTROM_SII
-@deffnx Macro GAL_SPECLINES_ANGSTROM_SIIBLUE
-@deffnx Macro GAL_SPECLINES_ANGSTROM_NIIRED
-@deffnx Macro GAL_SPECLINES_ANGSTROM_NII
-@deffnx Macro GAL_SPECLINES_ANGSTROM_HALPHA
-@deffnx Macro GAL_SPECLINES_ANGSTROM_NIIBLUE
-@deffnx Macro GAL_SPECLINES_ANGSTROM_OIIIRED
-@deffnx Macro GAL_SPECLINES_ANGSTROM_OIII
-@deffnx Macro GAL_SPECLINES_ANGSTROM_OIIIBLUE
-@deffnx Macro GAL_SPECLINES_ANGSTROM_HBETA
-@deffnx Macro GAL_SPECLINES_ANGSTROM_HEIIRED
-@deffnx Macro GAL_SPECLINES_ANGSTROM_HGAMMA
-@deffnx Macro GAL_SPECLINES_ANGSTROM_HDELTA
-@deffnx Macro GAL_SPECLINES_ANGSTROM_HEPSILON
-@deffnx Macro GAL_SPECLINES_ANGSTROM_NEIII
-@deffnx Macro GAL_SPECLINES_ANGSTROM_OIIRED
-@deffnx Macro GAL_SPECLINES_ANGSTROM_OII
-@deffnx Macro GAL_SPECLINES_ANGSTROM_OIIBLUE
-@deffnx Macro GAL_SPECLINES_ANGSTROM_BLIMIT
-@deffnx Macro GAL_SPECLINES_ANGSTROM_MGIIRED
-@deffnx Macro GAL_SPECLINES_ANGSTROM_MGII
-@deffnx Macro GAL_SPECLINES_ANGSTROM_MGIIBLUE
-@deffnx Macro GAL_SPECLINES_ANGSTROM_CIIIRED
-@deffnx Macro GAL_SPECLINES_ANGSTROM_CIII
-@deffnx Macro GAL_SPECLINES_ANGSTROM_CIIIBLUE
-@deffnx Macro GAL_SPECLINES_ANGSTROM_HEIIBLUE
-@deffnx Macro GAL_SPECLINES_ANGSTROM_LYALPHA
-@deffnx Macro GAL_SPECLINES_ANGSTROM_LYLIMIT
+@deffn  Macro GAL_SPECLINES_ANGSTROM_*
 Wavelength (in Angstroms) of the named lines.
+The @code{*} can take any of the line names of the @code{GAL_SPECLINES_*} 
Macros above.
 @end deffn
 
-@deffn  Macro GAL_SPECLINES_NAME_SIIRED
-@deffnx Macro GAL_SPECLINES_NAME_SII
-@deffnx Macro GAL_SPECLINES_NAME_SIIBLUE
-@deffnx Macro GAL_SPECLINES_NAME_NIIRED
-@deffnx Macro GAL_SPECLINES_NAME_NII
-@deffnx Macro GAL_SPECLINES_NAME_HALPHA
-@deffnx Macro GAL_SPECLINES_NAME_NIIBLUE
-@deffnx Macro GAL_SPECLINES_NAME_OIIIRED
-@deffnx Macro GAL_SPECLINES_NAME_OIII
-@deffnx Macro GAL_SPECLINES_NAME_OIIIBLUE
-@deffnx Macro GAL_SPECLINES_NAME_HBETA
-@deffnx Macro GAL_SPECLINES_NAME_HEIIRED
-@deffnx Macro GAL_SPECLINES_NAME_HGAMMA
-@deffnx Macro GAL_SPECLINES_NAME_HDELTA
-@deffnx Macro GAL_SPECLINES_NAME_HEPSILON
-@deffnx Macro GAL_SPECLINES_NAME_NEIII
-@deffnx Macro GAL_SPECLINES_NAME_OIIRED
-@deffnx Macro GAL_SPECLINES_NAME_OII
-@deffnx Macro GAL_SPECLINES_NAME_OIIBLUE
-@deffnx Macro GAL_SPECLINES_NAME_BLIMIT
-@deffnx Macro GAL_SPECLINES_NAME_MGIIRED
-@deffnx Macro GAL_SPECLINES_NAME_MGII
-@deffnx Macro GAL_SPECLINES_NAME_MGIIBLUE
-@deffnx Macro GAL_SPECLINES_NAME_CIIIRED
-@deffnx Macro GAL_SPECLINES_NAME_CIII
-@deffnx Macro GAL_SPECLINES_NAME_CIIIBLUE
-@deffnx Macro GAL_SPECLINES_NAME_HEIIBLUE
-@deffnx Macro GAL_SPECLINES_NAME_LYALPHA
-@deffnx Macro GAL_SPECLINES_NAME_LYLIMIT
-Names (as literal stings without any space, all in small-caps) that can be
-used to refer to the lines in your program and converted to and from line
-identifiers using the functions below.
+@deffn  Macro GAL_SPECLINES_NAME_*
+Names (as literal stings without any space) that can be used to refer to the 
lines in your program and converted to and from line identifiers using the 
functions below.
+The @code{*} can take any of the line names of the @code{GAL_SPECLINES_*} 
Macros above.
 @end deffn
 
 @deftypefun {char *} gal_speclines_line_name (int @code{linecode})
@@ -40068,9 +41078,12 @@ emitted from (if its restframe wavelength was 
@code{restline}).
 @end deftypefun
 
 @deftypefun double gal_speclines_line_redshift_code (double @code{obsline}, 
int @code{linecode})
-Return the redshift where the observed wavelength (@code{obsline}) was
-emitted from (assuming its a specific spectra line, identified with
-@code{linecode}).
+Return the redshift where the observed wavelength (@code{obsline}) was emitted 
from a pre-defined spectral line in the macros above.
+For example, you want the redshift where the H-alpha line falls at a 
wavelength of 8000 Angsroms, you can call this function like this:
+
+@example
+gal_speclines_line_redshift_code(8000, GAL_SPECLINES_H_alpha);
+@end example
 @end deftypefun
 
 
diff --git a/lib/fits.c b/lib/fits.c
index 58e0aff8..db74727d 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -3979,23 +3979,24 @@ fits_table_prepare_arrays(gal_data_t *cols, size_t 
numcols,
           else
             {
               /* For vector columns, we need to give the number of elements
-                 in the vector. */
-              switch(col->ndim)
+                 in the vector. Note that a vector column with dsize[1]==1
+                 is just a single-valued column and shouldn't be treated
+                 like a vector.*/
+              if( col->ndim==1 || (col->ndim==2 && col->dsize[1]==1) )
                 {
-                case 1:
                   if( asprintf(&tform[i], "%c", fmt[0])<0 )
                     error(EXIT_FAILURE, 0, "%s: asprintf allocation",
                           __func__);
-                  break;
-                case 2:
+                }
+              else if(col->ndim==2) /* Vector column */
+                {
                   if(asprintf(&tform[i], "%zu%c", col->dsize[1], fmt[0])<0)
                     error(EXIT_FAILURE, 0, "%s: asprintf allocation",
                           __func__);
-                  break;
-                default:
-                  error(EXIT_FAILURE, 0, "%s: only 1D or 2D data can "
-                        "be written as a binary table", __func__);
                 }
+              else
+                error(EXIT_FAILURE, 0, "%s: only 1D or 2D data can "
+                      "be written as a binary table", __func__);
             }
           break;
 
@@ -4215,8 +4216,10 @@ fits_tab_write_col(fitsfile *fptr, gal_data_t *col, int 
tableformat,
 
   /* If this is a FITS ASCII table, and the column is vector, we need to
      write it as separate single-value columns and write those, then we can
-     safely return (no more need to continue). */
-  if(tableformat==GAL_TABLE_FORMAT_AFITS && col->ndim>1)
+     safely return (no more need to continue). It may happen that a 2D
+     column has a second dimension of 1! In this case, it should be saved
+     as a normal 1D column. */
+  if(tableformat==GAL_TABLE_FORMAT_AFITS && col->ndim==2 && col->dsize[1]>1)
     {
       *colind=fits_tab_write_colvec_ascii(fptr, col, *colind, tform,
                                           filename);
diff --git a/lib/gnuastro-internal/options.h b/lib/gnuastro-internal/options.h
index 0ccea4bb..794d32eb 100644
--- a/lib/gnuastro-internal/options.h
+++ b/lib/gnuastro-internal/options.h
@@ -301,9 +301,18 @@ gal_data_t *
 gal_options_parse_list_of_numbers(char *string, char *filename,
                                   size_t lineno, uint8_t type);
 
+gal_list_str_t *
+gal_options_parse_csv_strings_to_list(char *string, char *filename,
+                                      size_t lineno);
+
 gal_data_t *
-gal_options_parse_csv_strings_raw(char *string, char *filename,
-                                  size_t lineno);
+gal_options_parse_csv_strings_to_data(char *string, char *filename,
+                                      size_t lineno);
+
+void *
+gal_options_parse_csv_strings_append(struct argp_option *option, char *arg,
+                                     char *filename, size_t lineno,
+                                     void *junk);
 
 void *
 gal_options_parse_csv_strings(struct argp_option *option, char *arg,
diff --git a/lib/gnuastro/list.h b/lib/gnuastro/list.h
index 441ed419..fdb874dc 100644
--- a/lib/gnuastro/list.h
+++ b/lib/gnuastro/list.h
@@ -84,7 +84,7 @@ gal_list_str_t *
 gal_list_str_extract(char *string);
 
 char *
-gal_list_str_cat(gal_list_str_t *list);
+gal_list_str_cat(gal_list_str_t *list, char delimiter);
 
 
 
diff --git a/lib/gnuastro/permutation.h b/lib/gnuastro/permutation.h
index f0555b9a..2237ffac 100644
--- a/lib/gnuastro/permutation.h
+++ b/lib/gnuastro/permutation.h
@@ -67,7 +67,8 @@ gal_permutation_apply_onlydim0(gal_data_t *input, size_t 
*permutation);
 void
 gal_permutation_apply_inverse(gal_data_t *input, size_t *permutation);
 
-
+void
+gal_permutation_transpose_2d(gal_data_t *input);
 
 
 __END_C_DECLS    /* From C++ preparations */
diff --git a/lib/gnuastro/speclines.h b/lib/gnuastro/speclines.h
index f09bc4b6..85c9ac2d 100644
--- a/lib/gnuastro/speclines.h
+++ b/lib/gnuastro/speclines.h
@@ -46,158 +46,776 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 __BEGIN_C_DECLS  /* From C++ preparations */
 
 
-/* Spectral line internal codes (SORT BY WAVELENGTH). */
+/* Spectral line internal codes (SORT BY WAVELENGTH).
+   rb:  right bracket
+   lb:  left  bracket
+   rlb: left & right bracket
+
+   From: http://astronomy.nmsu.edu/drewski/tableofemissionlines.html
+   Added: Lyman-Gamma from Wikipeda
+*/
 enum gal_speclines_line_codes
 {
   /* Allowing '0' to be identied as a known-non-line. */
   GAL_SPECLINES_INVALID=0,
 
-  /* Main list of recognized lines. */
-  GAL_SPECLINES_SIIRED,
-  GAL_SPECLINES_SII,
-  GAL_SPECLINES_SIIBLUE,
-  GAL_SPECLINES_NIIRED,
-  GAL_SPECLINES_NII,
-  GAL_SPECLINES_HALPHA,
-  GAL_SPECLINES_NIIBLUE,
-  GAL_SPECLINES_OIIIRED_VIS,
-  GAL_SPECLINES_OIII_VIS,
-  GAL_SPECLINES_OIIIBLUE_VIS,
-  GAL_SPECLINES_HBETA,
-  GAL_SPECLINES_HEII_VIS,
-  GAL_SPECLINES_HGAMMA,
-  GAL_SPECLINES_HDELTA,
-  GAL_SPECLINES_HEPSILON,
-  GAL_SPECLINES_NEIII,
-  GAL_SPECLINES_OIIRED,
-  GAL_SPECLINES_OII,
-  GAL_SPECLINES_OIIBLUE,
-  GAL_SPECLINES_BLIMIT,
-  GAL_SPECLINES_MGIIRED,
-  GAL_SPECLINES_MGII,
-  GAL_SPECLINES_MGIIBLUE,
-  GAL_SPECLINES_CIIIRED,
-  GAL_SPECLINES_CIII,
-  GAL_SPECLINES_CIIIBLUE,
-  GAL_SPECLINES_SiIIIRED,
-  GAL_SPECLINES_SiIII,
-  GAL_SPECLINES_SiIIIBLUE,
-  GAL_SPECLINES_OIIIRED_UV,
-  GAL_SPECLINES_OIII_UV,
-  GAL_SPECLINES_OIIIBLUE_UV,
-  GAL_SPECLINES_HEII_UV,
-  GAL_SPECLINES_CIVRED,
-  GAL_SPECLINES_CIV,
-  GAL_SPECLINES_CIVBLUE,
-  GAL_SPECLINES_NV,
-  GAL_SPECLINES_LYALPHA,
-  GAL_SPECLINES_LYBETA,
-  GAL_SPECLINES_LYGAMMA,
-  GAL_SPECLINES_LYDELTA,
-  GAL_SPECLINES_LYEPSILON,
-  GAL_SPECLINES_LYLIMIT,
+  /* Spectral line names from blue to red. */
+  GAL_SPECLINES_Ne_VIII_770,
+  GAL_SPECLINES_Ne_VIII_780,
+  GAL_SPECLINES_Ly_epsilon,
+  GAL_SPECLINES_Ly_delta,
+  GAL_SPECLINES_Ly_gamma,
+  GAL_SPECLINES_C_III_977,
+  GAL_SPECLINES_N_III_989,
+  GAL_SPECLINES_N_III_991_51,
+  GAL_SPECLINES_N_III_991_57,
+  GAL_SPECLINES_Ly_beta,
+  GAL_SPECLINES_O_VI_1031,
+  GAL_SPECLINES_O_VI_1037,
+  GAL_SPECLINES_Ar_I_1066,
+  GAL_SPECLINES_Ly_alpha,
+  GAL_SPECLINES_N_V_1238,
+  GAL_SPECLINES_N_V_1242,
+  GAL_SPECLINES_Si_II_1260,
+  GAL_SPECLINES_Si_II_1264,
+  GAL_SPECLINES_O_I_1302,
+  GAL_SPECLINES_C_II_1334,
+  GAL_SPECLINES_C_II_1335,
+  GAL_SPECLINES_Si_IV_1393,
+  GAL_SPECLINES_O_IV_1397,
+  GAL_SPECLINES_O_IV_1399,
+  GAL_SPECLINES_Si_IV_1402,
+  GAL_SPECLINES_N_IV_1486,
+  GAL_SPECLINES_C_IV_1548,
+  GAL_SPECLINES_C_IV_1550,
+  GAL_SPECLINES_He_II_1640,
+  GAL_SPECLINES_O_III_1660,
+  GAL_SPECLINES_O_III_1666,
+  GAL_SPECLINES_N_III_1746,
+  GAL_SPECLINES_N_III_1748,
+  GAL_SPECLINES_Al_III_1854,
+  GAL_SPECLINES_Al_III_1862,
+  GAL_SPECLINES_Si_III,
+  GAL_SPECLINES_C_III_1908,
+  GAL_SPECLINES_N_II_2142,
+  GAL_SPECLINES_O_III_2320,
+  GAL_SPECLINES_C_II_2323,
+  GAL_SPECLINES_C_II_2324,
+  GAL_SPECLINES_Fe_XI_2648,
+  GAL_SPECLINES_He_II_2733,
+  GAL_SPECLINES_Mg_V_2782,
+  GAL_SPECLINES_Mg_II_2795,
+  GAL_SPECLINES_Mg_II_2802,
+  GAL_SPECLINES_Fe_IV_2829,
+  GAL_SPECLINES_Fe_IV_2835,
+  GAL_SPECLINES_Ar_IV_2853,
+  GAL_SPECLINES_Ar_IV_2868,
+  GAL_SPECLINES_Mg_V_2928,
+  GAL_SPECLINES_He_I_2945,
+  GAL_SPECLINES_O_III_3132,
+  GAL_SPECLINES_He_I_3187,
+  GAL_SPECLINES_He_II_3203,
+  GAL_SPECLINES_O_III_3312,
+  GAL_SPECLINES_Ne_V_3345,
+  GAL_SPECLINES_Ne_V_3425,
+  GAL_SPECLINES_O_III_3444,
+  GAL_SPECLINES_N_I_3466_4,
+  GAL_SPECLINES_N_I_3466_5,
+  GAL_SPECLINES_He_I_3487,
+  GAL_SPECLINES_Fe_VII_3586,
+  GAL_SPECLINES_Fe_VI_3662,
+  GAL_SPECLINES_H_19,
+  GAL_SPECLINES_H_18,
+  GAL_SPECLINES_H_17,
+  GAL_SPECLINES_H_16,
+  GAL_SPECLINES_H_15,
+  GAL_SPECLINES_H_14,
+  GAL_SPECLINES_O_II_3726,
+  GAL_SPECLINES_O_II_3728,
+  GAL_SPECLINES_H_13,
+  GAL_SPECLINES_H_12,
+  GAL_SPECLINES_Fe_VII_3758,
+  GAL_SPECLINES_H_11,
+  GAL_SPECLINES_H_10,
+  GAL_SPECLINES_H_9,
+  GAL_SPECLINES_Fe_V_3839,
+  GAL_SPECLINES_Ne_III_3868,
+  GAL_SPECLINES_He_I_3888,
+  GAL_SPECLINES_H_8,
+  GAL_SPECLINES_Fe_V_3891,
+  GAL_SPECLINES_Fe_V_3911,
+  GAL_SPECLINES_Ne_III_3967,
+  GAL_SPECLINES_H_epsilon,
+  GAL_SPECLINES_He_I_4026,
+  GAL_SPECLINES_S_II_4068,
+  GAL_SPECLINES_Fe_V_4071,
+  GAL_SPECLINES_S_II_4076,
+  GAL_SPECLINES_H_delta,
+  GAL_SPECLINES_He_I_4143,
+  GAL_SPECLINES_Fe_II_4178,
+  GAL_SPECLINES_Fe_V_4180,
+  GAL_SPECLINES_Fe_II_4233,
+  GAL_SPECLINES_Fe_V_4227,
+  GAL_SPECLINES_Fe_II_4287,
+  GAL_SPECLINES_Fe_II_4304,
+  GAL_SPECLINES_O_II_4317,
+  GAL_SPECLINES_H_gamma,
+  GAL_SPECLINES_O_III_4363,
+  GAL_SPECLINES_Ar_XIV,
+  GAL_SPECLINES_O_II_4414,
+  GAL_SPECLINES_Fe_II_4416,
+  GAL_SPECLINES_Fe_II_4452,
+  GAL_SPECLINES_He_I_4471,
+  GAL_SPECLINES_Fe_II_4489,
+  GAL_SPECLINES_Fe_II_4491,
+  GAL_SPECLINES_N_III_4510,
+  GAL_SPECLINES_Fe_II_4522,
+  GAL_SPECLINES_Fe_II_4555,
+  GAL_SPECLINES_Fe_II_4582,
+  GAL_SPECLINES_Fe_II_4583,
+  GAL_SPECLINES_Fe_II_4629,
+  GAL_SPECLINES_N_III_4634,
+  GAL_SPECLINES_N_III_4640,
+  GAL_SPECLINES_N_III_4641,
+  GAL_SPECLINES_C_III_4647,
+  GAL_SPECLINES_C_III_4650,
+  GAL_SPECLINES_C_III_5651,
+  GAL_SPECLINES_Fe_III_4658,
+  GAL_SPECLINES_He_II_4685,
+  GAL_SPECLINES_Ar_IV_4711,
+  GAL_SPECLINES_Ar_IV_4740,
+  GAL_SPECLINES_H_beta,
+  GAL_SPECLINES_Fe_VII_4893,
+  GAL_SPECLINES_Fe_IV_4903,
+  GAL_SPECLINES_Fe_II_4923,
+  GAL_SPECLINES_O_III_4958,
+  GAL_SPECLINES_O_III_5006,
+  GAL_SPECLINES_Fe_II_5018,
+  GAL_SPECLINES_Fe_III_5084,
+  GAL_SPECLINES_Fe_VI_5145,
+  GAL_SPECLINES_Fe_VII_5158,
+  GAL_SPECLINES_Fe_II_5169,
+  GAL_SPECLINES_Fe_VI_5176,
+  GAL_SPECLINES_Fe_II_5197,
+  GAL_SPECLINES_N_I_5200,
+  GAL_SPECLINES_Fe_II_5234,
+  GAL_SPECLINES_Fe_IV_5236,
+  GAL_SPECLINES_Fe_III_5270,
+  GAL_SPECLINES_Fe_II_5276,
+  GAL_SPECLINES_Fe_VII_5276,
+  GAL_SPECLINES_Fe_XIV,
+  GAL_SPECLINES_Ca_V,
+  GAL_SPECLINES_Fe_II_5316_6,
+  GAL_SPECLINES_Fe_II_5316_7,
+  GAL_SPECLINES_Fe_VI_5335,
+  GAL_SPECLINES_Fe_VI_5424,
+  GAL_SPECLINES_Cl_III_5517,
+  GAL_SPECLINES_Cl_III_5537,
+  GAL_SPECLINES_Fe_VI_5637,
+  GAL_SPECLINES_Fe_VI_5677,
+  GAL_SPECLINES_C_III_5697,
+  GAL_SPECLINES_Fe_VII_5720,
+  GAL_SPECLINES_N_II_5754,
+  GAL_SPECLINES_C_IV_5801,
+  GAL_SPECLINES_C_IV_5811,
+  GAL_SPECLINES_He_I_5875,
+  GAL_SPECLINES_O_I_6046,
+  GAL_SPECLINES_Fe_VII_6087,
+  GAL_SPECLINES_O_I_6300,
+  GAL_SPECLINES_S_III_6312,
+  GAL_SPECLINES_Si_II_6347,
+  GAL_SPECLINES_O_I_6363,
+  GAL_SPECLINES_Fe_II_6369,
+  GAL_SPECLINES_Fe_X,
+  GAL_SPECLINES_Fe_II_6516,
+  GAL_SPECLINES_N_II_6548,
+  GAL_SPECLINES_H_alpha,
+  GAL_SPECLINES_N_II_6583,
+  GAL_SPECLINES_S_II_6716,
+  GAL_SPECLINES_S_II_6730,
+  GAL_SPECLINES_O_I_7002,
+  GAL_SPECLINES_Ar_V,
+  GAL_SPECLINES_He_I_7065,
+  GAL_SPECLINES_Ar_III_7135,
+  GAL_SPECLINES_Fe_II_7155,
+  GAL_SPECLINES_Ar_IV_7170,
+  GAL_SPECLINES_Fe_II_7172,
+  GAL_SPECLINES_C_II_7236,
+  GAL_SPECLINES_Ar_IV_7237,
+  GAL_SPECLINES_O_I_7254,
+  GAL_SPECLINES_Ar_IV_7262,
+  GAL_SPECLINES_He_I_7281,
+  GAL_SPECLINES_O_II_7319,
+  GAL_SPECLINES_O_II_7330,
+  GAL_SPECLINES_Ni_II_7377,
+  GAL_SPECLINES_Ni_II_7411,
+  GAL_SPECLINES_Fe_II_7452,
+  GAL_SPECLINES_N_I_7468,
+  GAL_SPECLINES_S_XII,
+  GAL_SPECLINES_Ar_III_7751,
+  GAL_SPECLINES_He_I_7816,
+  GAL_SPECLINES_Ar_I_7868,
+  GAL_SPECLINES_Ni_III,
+  GAL_SPECLINES_Fe_XI_7891,
+  GAL_SPECLINES_He_II_8236,
+  GAL_SPECLINES_Pa_20,
+  GAL_SPECLINES_Pa_19,
+  GAL_SPECLINES_Pa_18,
+  GAL_SPECLINES_O_I_8446,
+  GAL_SPECLINES_Pa_17,
+  GAL_SPECLINES_Ca_II_8498,
+  GAL_SPECLINES_Pa_16,
+  GAL_SPECLINES_Ca_II_8542,
+  GAL_SPECLINES_Pa_15,
+  GAL_SPECLINES_Cl_II,
+  GAL_SPECLINES_Pa_14,
+  GAL_SPECLINES_Fe_II_8616,
+  GAL_SPECLINES_Ca_II_8662,
+  GAL_SPECLINES_Pa_13,
+  GAL_SPECLINES_N_I_8680,
+  GAL_SPECLINES_N_I_8703,
+  GAL_SPECLINES_N_I_8711,
+  GAL_SPECLINES_Pa_12,
+  GAL_SPECLINES_Pa_11,
+  GAL_SPECLINES_Fe_II_8891,
+  GAL_SPECLINES_Pa_10,
+  GAL_SPECLINES_S_III_9068,
+  GAL_SPECLINES_Pa_9,
+  GAL_SPECLINES_S_III_9531,
+  GAL_SPECLINES_Pa_epsilon,
+  GAL_SPECLINES_C_I_9824,
+  GAL_SPECLINES_C_I_9850,
+  GAL_SPECLINES_S_VIII,
+  GAL_SPECLINES_He_I_10027,
+  GAL_SPECLINES_He_I_10031,
+  GAL_SPECLINES_Pa_delta,
+  GAL_SPECLINES_S_II_10286,
+  GAL_SPECLINES_S_II_10320,
+  GAL_SPECLINES_S_II_10336,
+  GAL_SPECLINES_Fe_XIII,
+  GAL_SPECLINES_He_I_10830,
+  GAL_SPECLINES_Pa_gamma,
 
   /* This should be the last element (to keep the total number of
      lines). */
-  GAL_SPECLINES_INVALID_MAX,
+  GAL_SPECLINES_NUMBER
 };
 
 
-/* Spectral lines wavelengths in Angstroms (SORT BY WAVELENGTH). */
-#define GAL_SPECLINES_ANGSTROM_SIIRED    6731
-#define GAL_SPECLINES_ANGSTROM_SII       6724
-#define GAL_SPECLINES_ANGSTROM_SIIBLUE   6717
-#define GAL_SPECLINES_ANGSTROM_NIIRED    6584
-#define GAL_SPECLINES_ANGSTROM_NII       6566
-#define GAL_SPECLINES_ANGSTROM_HALPHA    6562.8
-#define GAL_SPECLINES_ANGSTROM_NIIBLUE   6548
-#define GAL_SPECLINES_ANGSTROM_OIIIRED_VIS 5007
-#define GAL_SPECLINES_ANGSTROM_OIII_VIS  4983
-#define GAL_SPECLINES_ANGSTROM_OIIIBLUE_VIS 4959
-#define GAL_SPECLINES_ANGSTROM_HBETA     4861.36
-#define GAL_SPECLINES_ANGSTROM_HEII_VIS  4686
-#define GAL_SPECLINES_ANGSTROM_HGAMMA    4340.46
-#define GAL_SPECLINES_ANGSTROM_HDELTA    4101.74
-#define GAL_SPECLINES_ANGSTROM_HEPSILON  3970.07
-#define GAL_SPECLINES_ANGSTROM_NEIII     3869
-#define GAL_SPECLINES_ANGSTROM_OIIRED    3729
-#define GAL_SPECLINES_ANGSTROM_OII       3727.5
-#define GAL_SPECLINES_ANGSTROM_OIIBLUE   3726
-#define GAL_SPECLINES_ANGSTROM_BLIMIT    3646
-#define GAL_SPECLINES_ANGSTROM_MGIIRED   2803
-#define GAL_SPECLINES_ANGSTROM_MGII      2799.5
-#define GAL_SPECLINES_ANGSTROM_MGIIBLUE  2796
-#define GAL_SPECLINES_ANGSTROM_CIIIRED   1909
-#define GAL_SPECLINES_ANGSTROM_CIII      1908
-#define GAL_SPECLINES_ANGSTROM_CIIIBLUE  1907
-#define GAL_SPECLINES_ANGSTROM_SiIIIRED  1892
-#define GAL_SPECLINES_ANGSTROM_SiIII     1887.5
-#define GAL_SPECLINES_ANGSTROM_SiIIIBLUE 1883
-#define GAL_SPECLINES_ANGSTROM_OIIIRED_UV 1666
-#define GAL_SPECLINES_ANGSTROM_OIII_UV   1663.5
-#define GAL_SPECLINES_ANGSTROM_OIIIBLUE_UV 1661
-#define GAL_SPECLINES_ANGSTROM_HEII_UV   1640
-#define GAL_SPECLINES_ANGSTROM_CIVRED    1551
-#define GAL_SPECLINES_ANGSTROM_CIV       1549.5
-#define GAL_SPECLINES_ANGSTROM_CIVBLUE   1548
-#define GAL_SPECLINES_ANGSTROM_NV        1240
-#define GAL_SPECLINES_ANGSTROM_LYALPHA   1215.67
-#define GAL_SPECLINES_ANGSTROM_LYBETA    1025.7
-#define GAL_SPECLINES_ANGSTROM_LYGAMMA   972.54
-#define GAL_SPECLINES_ANGSTROM_LYDELTA   949.74
-#define GAL_SPECLINES_ANGSTROM_LYEPSILON 937.80
-#define GAL_SPECLINES_ANGSTROM_LYLIMIT   912
 
 
-/* Spectral line name strings (SORT BY WAVELENGTH). */
-#define GAL_SPECLINES_NAME_SIIRED    "siired"
-#define GAL_SPECLINES_NAME_SII       "sii"
-#define GAL_SPECLINES_NAME_SIIBLUE   "siiblue"
-#define GAL_SPECLINES_NAME_NIIRED    "niired"
-#define GAL_SPECLINES_NAME_NII       "nii"
-#define GAL_SPECLINES_NAME_HALPHA    "halpha"
-#define GAL_SPECLINES_NAME_NIIBLUE   "niiblue"
-#define GAL_SPECLINES_NAME_OIIIRED_VIS "oiiired-vis"
-#define GAL_SPECLINES_NAME_OIII_VIS  "oiii-vis"
-#define GAL_SPECLINES_NAME_OIIIBLUE_VIS "oiiiblue-vis"
-#define GAL_SPECLINES_NAME_HBETA     "hbeta"
-#define GAL_SPECLINES_NAME_HEII_VIS  "heii-vis"
-#define GAL_SPECLINES_NAME_HGAMMA    "hgamma"
-#define GAL_SPECLINES_NAME_HDELTA    "hdelta"
-#define GAL_SPECLINES_NAME_HEPSILON  "hepsilon"
-#define GAL_SPECLINES_NAME_NEIII     "neiii"
-#define GAL_SPECLINES_NAME_OIIRED    "oiired"
-#define GAL_SPECLINES_NAME_OII       "oii"
-#define GAL_SPECLINES_NAME_OIIBLUE   "oiiblue"
-#define GAL_SPECLINES_NAME_BLIMIT    "blimit"
-#define GAL_SPECLINES_NAME_MGIIRED   "mgiired"
-#define GAL_SPECLINES_NAME_MGII      "mgii"
-#define GAL_SPECLINES_NAME_MGIIBLUE  "mgiiblue"
-#define GAL_SPECLINES_NAME_CIIIRED   "ciiired"
-#define GAL_SPECLINES_NAME_CIII      "ciii"
-#define GAL_SPECLINES_NAME_CIIIBLUE  "ciiiblue"
-#define GAL_SPECLINES_NAME_SiIIIRED  "si_iiired"
-#define GAL_SPECLINES_NAME_SiIII     "si_iii"
-#define GAL_SPECLINES_NAME_SiIIIBLUE "si_iiiblue"
-#define GAL_SPECLINES_NAME_OIIIRED_UV "oiiired-uv"
-#define GAL_SPECLINES_NAME_OIII_UV   "oiii-uv"
-#define GAL_SPECLINES_NAME_OIIIBLUE_UV "oiiiblue-uv"
-#define GAL_SPECLINES_NAME_HEII_UV   "heii-uv"
-#define GAL_SPECLINES_NAME_CIVRED    "civred"
-#define GAL_SPECLINES_NAME_CIV       "civ"
-#define GAL_SPECLINES_NAME_CIVBLUE   "civblue"
-#define GAL_SPECLINES_NAME_NV        "nv"
-#define GAL_SPECLINES_NAME_LYALPHA   "lyalpha"
-#define GAL_SPECLINES_NAME_LYBETA    "lybeta"
-#define GAL_SPECLINES_NAME_LYGAMMA   "lygamma"
-#define GAL_SPECLINES_NAME_LYDELTA   "lydelta"
-#define GAL_SPECLINES_NAME_LYEPSILON "lyepsilon"
-#define GAL_SPECLINES_NAME_LYLIMIT   "lylimit"
+
+enum gal_speclines_limit_codes
+{
+  /* Allowing '0' to be identied as a known-non-line. */
+  GAL_SPECLINES_LIMIT_INVALID=0,
+
+  GAL_SPECLINES_LIMIT_LYMAN=GAL_SPECLINES_NUMBER,
+  GAL_SPECLINES_LIMIT_BALMER,
+  GAL_SPECLINES_LIMIT_PASCHEN,
+
+  /* Total number of limits and lines+limits. */
+  GAL_SPECLINES_LIMIT_NUMBERWITHLINES,
+  GAL_SPECLINES_LIMIT_NUMBER = (GAL_SPECLINES_LIMIT_NUMBERWITHLINES
+                                - GAL_SPECLINES_LIMIT_LYMAN)
+};
 
 
 
 
 
+/* Spectral lines wavelengths in Angstroms (SORT BY WAVELENGTH).
+   Source: http://astronomy.nmsu.edu/drewski/tableofemissionlines.html
+
+   The following extra lines have been added:
+   - Ly-gamma (https://en.wikipedia.org/wiki/Lyman_series) */
+#define GAL_SPECLINES_ANGSTROM_Ne_VIII_770          770.409
+#define GAL_SPECLINES_ANGSTROM_Ne_VIII_780          780.324
+#define GAL_SPECLINES_ANGSTROM_Ly_epsilon           937.814
+#define GAL_SPECLINES_ANGSTROM_Ly_delta             949.742
+#define GAL_SPECLINES_ANGSTROM_Ly_gamma             972.536
+#define GAL_SPECLINES_ANGSTROM_C_III_977            977.030
+#define GAL_SPECLINES_ANGSTROM_N_III_989            989.790
+#define GAL_SPECLINES_ANGSTROM_N_III_991_51         991.514
+#define GAL_SPECLINES_ANGSTROM_N_III_991_57         991.579
+#define GAL_SPECLINES_ANGSTROM_Ly_beta              1025.722
+#define GAL_SPECLINES_ANGSTROM_O_VI_1031            1031.912
+#define GAL_SPECLINES_ANGSTROM_O_VI_1037            1037.613
+#define GAL_SPECLINES_ANGSTROM_Ar_I_1066            1066.660
+#define GAL_SPECLINES_ANGSTROM_Ly_alpha             1215.670
+#define GAL_SPECLINES_ANGSTROM_N_V_1238             1238.821
+#define GAL_SPECLINES_ANGSTROM_N_V_1242             1242.804
+#define GAL_SPECLINES_ANGSTROM_Si_II_1260           1260.422
+#define GAL_SPECLINES_ANGSTROM_Si_II_1264           1264.730
+#define GAL_SPECLINES_ANGSTROM_O_I_1302             1302.168
+#define GAL_SPECLINES_ANGSTROM_C_II_1334            1334.532
+#define GAL_SPECLINES_ANGSTROM_C_II_1335            1335.708
+#define GAL_SPECLINES_ANGSTROM_Si_IV_1393           1393.755
+#define GAL_SPECLINES_ANGSTROM_O_IV_1397            1397.232
+#define GAL_SPECLINES_ANGSTROM_O_IV_1399            1399.780
+#define GAL_SPECLINES_ANGSTROM_Si_IV_1402           1402.770
+#define GAL_SPECLINES_ANGSTROM_N_IV_1486            1486.496
+#define GAL_SPECLINES_ANGSTROM_C_IV_1548            1548.187
+#define GAL_SPECLINES_ANGSTROM_C_IV_1550            1550.772
+#define GAL_SPECLINES_ANGSTROM_He_II_1640           1640.420
+#define GAL_SPECLINES_ANGSTROM_O_III_1660           1660.809
+#define GAL_SPECLINES_ANGSTROM_O_III_1666           1666.150
+#define GAL_SPECLINES_ANGSTROM_N_III_1746           1746.823
+#define GAL_SPECLINES_ANGSTROM_N_III_1748           1748.656
+#define GAL_SPECLINES_ANGSTROM_Al_III_1854          1854.716
+#define GAL_SPECLINES_ANGSTROM_Al_III_1862          1862.790
+#define GAL_SPECLINES_ANGSTROM_Si_III               1892.030
+#define GAL_SPECLINES_ANGSTROM_C_III_1908           1908.734
+#define GAL_SPECLINES_ANGSTROM_N_II_2142            2142.780
+#define GAL_SPECLINES_ANGSTROM_O_III_2320           2320.951
+#define GAL_SPECLINES_ANGSTROM_C_II_2323            2323.500
+#define GAL_SPECLINES_ANGSTROM_C_II_2324            2324.690
+#define GAL_SPECLINES_ANGSTROM_Fe_XI_2648           2648.710
+#define GAL_SPECLINES_ANGSTROM_He_II_2733           2733.289
+#define GAL_SPECLINES_ANGSTROM_Mg_V_2782            2782.700
+#define GAL_SPECLINES_ANGSTROM_Mg_II_2795           2795.528
+#define GAL_SPECLINES_ANGSTROM_Mg_II_2802           2802.705
+#define GAL_SPECLINES_ANGSTROM_Fe_IV_2829           2829.360
+#define GAL_SPECLINES_ANGSTROM_Fe_IV_2835           2835.740
+#define GAL_SPECLINES_ANGSTROM_Ar_IV_2853           2853.670
+#define GAL_SPECLINES_ANGSTROM_Ar_IV_2868           2868.210
+#define GAL_SPECLINES_ANGSTROM_Mg_V_2928            2928.000
+#define GAL_SPECLINES_ANGSTROM_He_I_2945            2945.106
+#define GAL_SPECLINES_ANGSTROM_O_III_3132           3132.794
+#define GAL_SPECLINES_ANGSTROM_He_I_3187            3187.745
+#define GAL_SPECLINES_ANGSTROM_He_II_3203           3203.100
+#define GAL_SPECLINES_ANGSTROM_O_III_3312           3312.329
+#define GAL_SPECLINES_ANGSTROM_Ne_V_3345            3345.821
+#define GAL_SPECLINES_ANGSTROM_Ne_V_3425            3425.881
+#define GAL_SPECLINES_ANGSTROM_O_III_3444           3444.052
+#define GAL_SPECLINES_ANGSTROM_N_I_3466_4           3466.497
+#define GAL_SPECLINES_ANGSTROM_N_I_3466_5           3466.543
+#define GAL_SPECLINES_ANGSTROM_He_I_3487            3487.727
+#define GAL_SPECLINES_ANGSTROM_Fe_VII_3586          3586.320
+#define GAL_SPECLINES_ANGSTROM_Fe_VI_3662           3662.500
+#define GAL_SPECLINES_ANGSTROM_H_19                 3686.831
+#define GAL_SPECLINES_ANGSTROM_H_18                 3691.551
+#define GAL_SPECLINES_ANGSTROM_H_17                 3697.157
+#define GAL_SPECLINES_ANGSTROM_H_16                 3703.859
+#define GAL_SPECLINES_ANGSTROM_H_15                 3711.977
+#define GAL_SPECLINES_ANGSTROM_H_14                 3721.945
+#define GAL_SPECLINES_ANGSTROM_O_II_3726            3726.032
+#define GAL_SPECLINES_ANGSTROM_O_II_3728            3728.815
+#define GAL_SPECLINES_ANGSTROM_H_13                 3734.369
+#define GAL_SPECLINES_ANGSTROM_H_12                 3750.158
+#define GAL_SPECLINES_ANGSTROM_Fe_VII_3758          3758.920
+#define GAL_SPECLINES_ANGSTROM_H_11                 3770.637
+#define GAL_SPECLINES_ANGSTROM_H_10                 3797.904
+#define GAL_SPECLINES_ANGSTROM_H_9                  3835.391
+#define GAL_SPECLINES_ANGSTROM_Fe_V_3839            3839.270
+#define GAL_SPECLINES_ANGSTROM_Ne_III_3868          3868.760
+#define GAL_SPECLINES_ANGSTROM_He_I_3888            3888.647
+#define GAL_SPECLINES_ANGSTROM_H_8                  3889.064
+#define GAL_SPECLINES_ANGSTROM_Fe_V_3891            3891.280
+#define GAL_SPECLINES_ANGSTROM_Fe_V_3911            3911.330
+#define GAL_SPECLINES_ANGSTROM_Ne_III_3967          3967.470
+#define GAL_SPECLINES_ANGSTROM_H_epsilon            3970.079
+#define GAL_SPECLINES_ANGSTROM_He_I_4026            4026.190
+#define GAL_SPECLINES_ANGSTROM_S_II_4068            4068.600
+#define GAL_SPECLINES_ANGSTROM_Fe_V_4071            4071.240
+#define GAL_SPECLINES_ANGSTROM_S_II_4076            4076.349
+#define GAL_SPECLINES_ANGSTROM_H_delta              4101.742
+#define GAL_SPECLINES_ANGSTROM_He_I_4143            4143.761
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4178           4178.862
+#define GAL_SPECLINES_ANGSTROM_Fe_V_4180            4180.600
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4233           4233.172
+#define GAL_SPECLINES_ANGSTROM_Fe_V_4227            4227.190
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4287           4287.394
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4304           4303.176
+#define GAL_SPECLINES_ANGSTROM_O_II_4317            4317.139
+#define GAL_SPECLINES_ANGSTROM_H_gamma              4340.471
+#define GAL_SPECLINES_ANGSTROM_O_III_4363           4363.210
+#define GAL_SPECLINES_ANGSTROM_Ar_XIV               4412.300
+#define GAL_SPECLINES_ANGSTROM_O_II_4414            4414.899
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4416           4416.830
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4452           4452.098
+#define GAL_SPECLINES_ANGSTROM_He_I_4471            4471.479
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4489           4489.183
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4491           4491.405
+#define GAL_SPECLINES_ANGSTROM_N_III_4510           4510.910
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4522           4522.634
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4555           4555.893
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4582           4582.835
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4583           4583.837
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4629           4629.339
+#define GAL_SPECLINES_ANGSTROM_N_III_4634           4634.140
+#define GAL_SPECLINES_ANGSTROM_N_III_4640           4640.640
+#define GAL_SPECLINES_ANGSTROM_N_III_4641           4641.850
+#define GAL_SPECLINES_ANGSTROM_C_III_4647           4647.420
+#define GAL_SPECLINES_ANGSTROM_C_III_4650           4650.250
+#define GAL_SPECLINES_ANGSTROM_C_III_5651           4651.470
+#define GAL_SPECLINES_ANGSTROM_Fe_III_4658          4658.050
+#define GAL_SPECLINES_ANGSTROM_He_II_4685           4685.710
+#define GAL_SPECLINES_ANGSTROM_Ar_IV_4711           4711.260
+#define GAL_SPECLINES_ANGSTROM_Ar_IV_4740           4740.120
+#define GAL_SPECLINES_ANGSTROM_H_beta               4861.333
+#define GAL_SPECLINES_ANGSTROM_Fe_VII_4893          4893.370
+#define GAL_SPECLINES_ANGSTROM_Fe_IV_4903           4903.070
+#define GAL_SPECLINES_ANGSTROM_Fe_II_4923           4923.927
+#define GAL_SPECLINES_ANGSTROM_O_III_4958           4958.911
+#define GAL_SPECLINES_ANGSTROM_O_III_5006           5006.843
+#define GAL_SPECLINES_ANGSTROM_Fe_II_5018           5018.440
+#define GAL_SPECLINES_ANGSTROM_Fe_III_5084          5084.770
+#define GAL_SPECLINES_ANGSTROM_Fe_VI_5145           5145.750
+#define GAL_SPECLINES_ANGSTROM_Fe_VII_5158          5158.890
+#define GAL_SPECLINES_ANGSTROM_Fe_II_5169           5169.033
+#define GAL_SPECLINES_ANGSTROM_Fe_VI_5176           5176.040
+#define GAL_SPECLINES_ANGSTROM_Fe_II_5197           5197.577
+#define GAL_SPECLINES_ANGSTROM_N_I_5200             5200.257
+#define GAL_SPECLINES_ANGSTROM_Fe_II_5234           5234.625
+#define GAL_SPECLINES_ANGSTROM_Fe_IV_5236           5236.060
+#define GAL_SPECLINES_ANGSTROM_Fe_III_5270          5270.400
+#define GAL_SPECLINES_ANGSTROM_Fe_II_5276           5276.002
+#define GAL_SPECLINES_ANGSTROM_Fe_VII_5276          5276.380
+#define GAL_SPECLINES_ANGSTROM_Fe_XIV               5302.860
+#define GAL_SPECLINES_ANGSTROM_Ca_V                 5309.110
+#define GAL_SPECLINES_ANGSTROM_Fe_II_5316_6         5316.615
+#define GAL_SPECLINES_ANGSTROM_Fe_II_5316_7         5316.784
+#define GAL_SPECLINES_ANGSTROM_Fe_VI_5335           5335.180
+#define GAL_SPECLINES_ANGSTROM_Fe_VI_5424           5424.220
+#define GAL_SPECLINES_ANGSTROM_Cl_III_5517          5517.709
+#define GAL_SPECLINES_ANGSTROM_Cl_III_5537          5537.873
+#define GAL_SPECLINES_ANGSTROM_Fe_VI_5637           5637.600
+#define GAL_SPECLINES_ANGSTROM_Fe_VI_5677           5677.000
+#define GAL_SPECLINES_ANGSTROM_C_III_5697           5695.920
+#define GAL_SPECLINES_ANGSTROM_Fe_VII_5720          5720.700
+#define GAL_SPECLINES_ANGSTROM_N_II_5754            5754.590
+#define GAL_SPECLINES_ANGSTROM_C_IV_5801            5801.330
+#define GAL_SPECLINES_ANGSTROM_C_IV_5811            5811.980
+#define GAL_SPECLINES_ANGSTROM_He_I_5875            5875.624
+#define GAL_SPECLINES_ANGSTROM_O_I_6046             6046.440
+#define GAL_SPECLINES_ANGSTROM_Fe_VII_6087          6087.000
+#define GAL_SPECLINES_ANGSTROM_O_I_6300             6300.304
+#define GAL_SPECLINES_ANGSTROM_S_III_6312           6312.060
+#define GAL_SPECLINES_ANGSTROM_Si_II_6347           6347.100
+#define GAL_SPECLINES_ANGSTROM_O_I_6363             6363.776
+#define GAL_SPECLINES_ANGSTROM_Fe_II_6369           6369.462
+#define GAL_SPECLINES_ANGSTROM_Fe_X                 6374.510
+#define GAL_SPECLINES_ANGSTROM_Fe_II_6516           6516.081
+#define GAL_SPECLINES_ANGSTROM_N_II_6548            6548.050
+#define GAL_SPECLINES_ANGSTROM_H_alpha              6562.819
+#define GAL_SPECLINES_ANGSTROM_N_II_6583            6583.460
+#define GAL_SPECLINES_ANGSTROM_S_II_6716            6716.440
+#define GAL_SPECLINES_ANGSTROM_S_II_6730            6730.810
+#define GAL_SPECLINES_ANGSTROM_O_I_7002             7002.230
+#define GAL_SPECLINES_ANGSTROM_Ar_V                 7005.870
+#define GAL_SPECLINES_ANGSTROM_He_I_7065            7065.196
+#define GAL_SPECLINES_ANGSTROM_Ar_III_7135          7135.790
+#define GAL_SPECLINES_ANGSTROM_Fe_II_7155           7155.157
+#define GAL_SPECLINES_ANGSTROM_Ar_IV_7170           7170.620
+#define GAL_SPECLINES_ANGSTROM_Fe_II_7172           7172.000
+#define GAL_SPECLINES_ANGSTROM_C_II_7236            7236.420
+#define GAL_SPECLINES_ANGSTROM_Ar_IV_7237           7237.260
+#define GAL_SPECLINES_ANGSTROM_O_I_7254             7254.448
+#define GAL_SPECLINES_ANGSTROM_Ar_IV_7262           7262.760
+#define GAL_SPECLINES_ANGSTROM_He_I_7281            7281.349
+#define GAL_SPECLINES_ANGSTROM_O_II_7319            7319.990
+#define GAL_SPECLINES_ANGSTROM_O_II_7330            7330.730
+#define GAL_SPECLINES_ANGSTROM_Ni_II_7377           7377.830
+#define GAL_SPECLINES_ANGSTROM_Ni_II_7411           7411.160
+#define GAL_SPECLINES_ANGSTROM_Fe_II_7452           7452.538
+#define GAL_SPECLINES_ANGSTROM_N_I_7468             7468.310
+#define GAL_SPECLINES_ANGSTROM_S_XII                7611.000
+#define GAL_SPECLINES_ANGSTROM_Ar_III_7751          7751.060
+#define GAL_SPECLINES_ANGSTROM_He_I_7816            7816.136
+#define GAL_SPECLINES_ANGSTROM_Ar_I_7868            7868.194
+#define GAL_SPECLINES_ANGSTROM_Ni_III               7889.900
+#define GAL_SPECLINES_ANGSTROM_Fe_XI_7891           7891.800
+#define GAL_SPECLINES_ANGSTROM_He_II_8236           8236.790
+#define GAL_SPECLINES_ANGSTROM_Pa_20                8392.397
+#define GAL_SPECLINES_ANGSTROM_Pa_19                8413.318
+#define GAL_SPECLINES_ANGSTROM_Pa_18                8437.956
+#define GAL_SPECLINES_ANGSTROM_O_I_8446             8446.359
+#define GAL_SPECLINES_ANGSTROM_Pa_17                8467.254
+#define GAL_SPECLINES_ANGSTROM_Ca_II_8498           8498.020
+#define GAL_SPECLINES_ANGSTROM_Pa_16                8502.483
+#define GAL_SPECLINES_ANGSTROM_Ca_II_8542           8542.090
+#define GAL_SPECLINES_ANGSTROM_Pa_15                8545.383
+#define GAL_SPECLINES_ANGSTROM_Cl_II                8578.700
+#define GAL_SPECLINES_ANGSTROM_Pa_14                8598.392
+#define GAL_SPECLINES_ANGSTROM_Fe_II_8616           8616.950
+#define GAL_SPECLINES_ANGSTROM_Ca_II_8662           8662.140
+#define GAL_SPECLINES_ANGSTROM_Pa_13                8665.019
+#define GAL_SPECLINES_ANGSTROM_N_I_8680             8680.282
+#define GAL_SPECLINES_ANGSTROM_N_I_8703             8703.247
+#define GAL_SPECLINES_ANGSTROM_N_I_8711             8711.703
+#define GAL_SPECLINES_ANGSTROM_Pa_12                8750.472
+#define GAL_SPECLINES_ANGSTROM_Pa_11                8862.782
+#define GAL_SPECLINES_ANGSTROM_Fe_II_8891           8891.910
+#define GAL_SPECLINES_ANGSTROM_Pa_10                9014.909
+#define GAL_SPECLINES_ANGSTROM_S_III_9068           9068.600
+#define GAL_SPECLINES_ANGSTROM_Pa_9                 9229.014
+#define GAL_SPECLINES_ANGSTROM_S_III_9531           9531.100
+#define GAL_SPECLINES_ANGSTROM_Pa_epsilon           9545.969
+#define GAL_SPECLINES_ANGSTROM_C_I_9824             9824.130
+#define GAL_SPECLINES_ANGSTROM_C_I_9850             9850.260
+#define GAL_SPECLINES_ANGSTROM_S_VIII               9913.000
+#define GAL_SPECLINES_ANGSTROM_He_I_10027           10027.730
+#define GAL_SPECLINES_ANGSTROM_He_I_10031           10031.160
+#define GAL_SPECLINES_ANGSTROM_Pa_delta             10049.368
+#define GAL_SPECLINES_ANGSTROM_S_II_10286           10286.730
+#define GAL_SPECLINES_ANGSTROM_S_II_10320           10320.490
+#define GAL_SPECLINES_ANGSTROM_S_II_10336           10336.410
+#define GAL_SPECLINES_ANGSTROM_Fe_XIII              10746.800
+#define GAL_SPECLINES_ANGSTROM_He_I_10830           10830.340
+#define GAL_SPECLINES_ANGSTROM_Pa_gamma             10938.086
+
+/* Common limits of line series; from
+   https://en.wikipedia.org/wiki/Hydrogen_spectral_series */
+#define GAL_SPECLINES_ANGSTROM_LIMIT_LYMAN          912
+#define GAL_SPECLINES_ANGSTROM_LIMIT_BALMER         3646
+#define GAL_SPECLINES_ANGSTROM_LIMIT_PASCHEN        8204
+
+
+
+/* Spectral line name strings (SORT BY WAVELENGTH). */
+#define GAL_SPECLINES_NAME_Ne_VIII_770          "Ne-VIII-770"
+#define GAL_SPECLINES_NAME_Ne_VIII_780          "Ne-VIII-780"
+#define GAL_SPECLINES_NAME_Ly_epsilon           "Ly-epsilon"
+#define GAL_SPECLINES_NAME_Ly_delta             "Ly-delta"
+#define GAL_SPECLINES_NAME_Ly_gamma             "Ly-gamma"
+#define GAL_SPECLINES_NAME_C_III_977            "C-III-977"
+#define GAL_SPECLINES_NAME_N_III_989            "N-III-989"
+#define GAL_SPECLINES_NAME_N_III_991_51         "N-III-991.51"
+#define GAL_SPECLINES_NAME_N_III_991_57         "N-III-991.57"
+#define GAL_SPECLINES_NAME_Ly_beta              "Ly-beta"
+#define GAL_SPECLINES_NAME_O_VI_1031            "O-VI-1031"
+#define GAL_SPECLINES_NAME_O_VI_1037            "O-VI-1037"
+#define GAL_SPECLINES_NAME_Ar_I_1066            "Ar-I-1066"
+#define GAL_SPECLINES_NAME_Ly_alpha             "Ly-alpha"
+#define GAL_SPECLINES_NAME_N_V_1238             "N-V-1238"
+#define GAL_SPECLINES_NAME_N_V_1242             "N-V-1242"
+#define GAL_SPECLINES_NAME_Si_II_1260           "Si-II-1260"
+#define GAL_SPECLINES_NAME_Si_II_1264           "Si_II-1302"
+#define GAL_SPECLINES_NAME_O_I_1302             "O-I-1302"
+#define GAL_SPECLINES_NAME_C_II_1334            "C-II-1334"
+#define GAL_SPECLINES_NAME_C_II_1335            "C-II-1335"
+#define GAL_SPECLINES_NAME_Si_IV_1393           "Si-IV-1393"
+#define GAL_SPECLINES_NAME_O_IV_1397            "O-IV-1397"
+#define GAL_SPECLINES_NAME_O_IV_1399            "O-IV-1399"
+#define GAL_SPECLINES_NAME_Si_IV_1402           "Si-IV-1402"
+#define GAL_SPECLINES_NAME_N_IV_1486            "N-IV-1486"
+#define GAL_SPECLINES_NAME_C_IV_1548            "C-IV-1548"
+#define GAL_SPECLINES_NAME_C_IV_1550            "C-IV-1550"
+#define GAL_SPECLINES_NAME_He_II_1640           "He-II-1640"
+#define GAL_SPECLINES_NAME_O_III_1660           "O-III-1660"
+#define GAL_SPECLINES_NAME_O_III_1666           "O-III-1666"
+#define GAL_SPECLINES_NAME_N_III_1746           "N-III-1746"
+#define GAL_SPECLINES_NAME_N_III_1748           "N-III-1748"
+#define GAL_SPECLINES_NAME_Al_III_1854          "Al-III-1854"
+#define GAL_SPECLINES_NAME_Al_III_1862          "Al-III-1862"
+#define GAL_SPECLINES_NAME_Si_III               "Si-III"
+#define GAL_SPECLINES_NAME_C_III_1908           "C-III-1908"
+#define GAL_SPECLINES_NAME_N_II_2142            "N-II-2142"
+#define GAL_SPECLINES_NAME_O_III_2320           "O-III-2320"
+#define GAL_SPECLINES_NAME_C_II_2323            "C-II-2323"
+#define GAL_SPECLINES_NAME_C_II_2324            "C-II-2324"
+#define GAL_SPECLINES_NAME_Fe_XI_2648           "Fe-XI-2648"
+#define GAL_SPECLINES_NAME_He_II_2733           "He-II-2733"
+#define GAL_SPECLINES_NAME_Mg_V_2782            "Mg-V-2782"
+#define GAL_SPECLINES_NAME_Mg_II_2795           "Mg-II-2795"
+#define GAL_SPECLINES_NAME_Mg_II_2802           "Mg-II-2802"
+#define GAL_SPECLINES_NAME_Fe_IV_2829           "Fe-IV-2829"
+#define GAL_SPECLINES_NAME_Fe_IV_2835           "Fe-IV-2835"
+#define GAL_SPECLINES_NAME_Ar_IV_2853           "Ar-IV-2853"
+#define GAL_SPECLINES_NAME_Ar_IV_2868           "Ar-IV-2868"
+#define GAL_SPECLINES_NAME_Mg_V_2928            "Mg-V-2928"
+#define GAL_SPECLINES_NAME_He_I_2945            "He-I-2945"
+#define GAL_SPECLINES_NAME_O_III_3132           "O-III-3132"
+#define GAL_SPECLINES_NAME_He_I_3187            "He-I-3187"
+#define GAL_SPECLINES_NAME_He_II_3203           "He-II-3203"
+#define GAL_SPECLINES_NAME_O_III_3312           "O-III-3312"
+#define GAL_SPECLINES_NAME_Ne_V_3345            "Ne-V-3345"
+#define GAL_SPECLINES_NAME_Ne_V_3425            "Ne-V-3425"
+#define GAL_SPECLINES_NAME_O_III_3444           "O-III-3444"
+#define GAL_SPECLINES_NAME_N_I_3466_4           "N-I-3466-4"
+#define GAL_SPECLINES_NAME_N_I_3466_5           "N-I-3466-5"
+#define GAL_SPECLINES_NAME_He_I_3487            "He-I-3487"
+#define GAL_SPECLINES_NAME_Fe_VII_3586          "Fe-VII-3586"
+#define GAL_SPECLINES_NAME_Fe_VI_3662           "Fe-VI-3662"
+#define GAL_SPECLINES_NAME_H_19                 "H-19"
+#define GAL_SPECLINES_NAME_H_18                 "H-18"
+#define GAL_SPECLINES_NAME_H_17                 "H-17"
+#define GAL_SPECLINES_NAME_H_16                 "H-16"
+#define GAL_SPECLINES_NAME_H_15                 "H-15"
+#define GAL_SPECLINES_NAME_H_14                 "H-14"
+#define GAL_SPECLINES_NAME_O_II_3726            "O-II-3726"
+#define GAL_SPECLINES_NAME_O_II_3728            "O-II-3728"
+#define GAL_SPECLINES_NAME_H_13                 "H-13"
+#define GAL_SPECLINES_NAME_H_12                 "H-12"
+#define GAL_SPECLINES_NAME_Fe_VII_3758          "Fe-VII-3758"
+#define GAL_SPECLINES_NAME_H_11                 "H-11"
+#define GAL_SPECLINES_NAME_H_10                 "H-10"
+#define GAL_SPECLINES_NAME_H_9                  "H-9"
+#define GAL_SPECLINES_NAME_Fe_V_3839            "Fe-V-3839"
+#define GAL_SPECLINES_NAME_Ne_III_3868          "Ne-III-3868"
+#define GAL_SPECLINES_NAME_He_I_3888            "He-I-3888"
+#define GAL_SPECLINES_NAME_H_8                  "H-8"
+#define GAL_SPECLINES_NAME_Fe_V_3891            "Fe-V-3891"
+#define GAL_SPECLINES_NAME_Fe_V_3911            "Fe-V-3911"
+#define GAL_SPECLINES_NAME_Ne_III_3967          "Ne-III-3967"
+#define GAL_SPECLINES_NAME_H_epsilon            "H-epsilon"
+#define GAL_SPECLINES_NAME_He_I_4026            "He-I-4026"
+#define GAL_SPECLINES_NAME_S_II_4068            "S-II-4068"
+#define GAL_SPECLINES_NAME_Fe_V_4071            "Fe-V-4071"
+#define GAL_SPECLINES_NAME_S_II_4076            "S-II-4076"
+#define GAL_SPECLINES_NAME_H_delta              "H-delta"
+#define GAL_SPECLINES_NAME_He_I_4143            "He-I-4143"
+#define GAL_SPECLINES_NAME_Fe_II_4178           "Fe-II-4178"
+#define GAL_SPECLINES_NAME_Fe_V_4180            "Fe-V-4180"
+#define GAL_SPECLINES_NAME_Fe_II_4233           "Fe-II-4233"
+#define GAL_SPECLINES_NAME_Fe_V_4227            "Fe-V-4227"
+#define GAL_SPECLINES_NAME_Fe_II_4287           "Fe-II-4287"
+#define GAL_SPECLINES_NAME_Fe_II_4304           "Fe-II-4304"
+#define GAL_SPECLINES_NAME_O_II_4317            "O-II-4317"
+#define GAL_SPECLINES_NAME_H_gamma              "H-gamma"
+#define GAL_SPECLINES_NAME_O_III_4363           "O-III-4363"
+#define GAL_SPECLINES_NAME_Ar_XIV               "Ar-XIV"
+#define GAL_SPECLINES_NAME_O_II_4414            "O-II-4414"
+#define GAL_SPECLINES_NAME_Fe_II_4416           "Fe-II-4416"
+#define GAL_SPECLINES_NAME_Fe_II_4452           "Fe-II-4452"
+#define GAL_SPECLINES_NAME_He_I_4471            "He-I-4471"
+#define GAL_SPECLINES_NAME_Fe_II_4489           "Fe-II-4489"
+#define GAL_SPECLINES_NAME_Fe_II_4491           "Fe-II-4491"
+#define GAL_SPECLINES_NAME_N_III_4510           "N-III-4510"
+#define GAL_SPECLINES_NAME_Fe_II_4522           "Fe-II-4522"
+#define GAL_SPECLINES_NAME_Fe_II_4555           "Fe-II-4555"
+#define GAL_SPECLINES_NAME_Fe_II_4582           "Fe-II-4582"
+#define GAL_SPECLINES_NAME_Fe_II_4583           "Fe-II-4583"
+#define GAL_SPECLINES_NAME_Fe_II_4629           "Fe-II-4629"
+#define GAL_SPECLINES_NAME_N_III_4634           "N-III-4634"
+#define GAL_SPECLINES_NAME_N_III_4640           "N-III-4640"
+#define GAL_SPECLINES_NAME_N_III_4641           "N-III-4641"
+#define GAL_SPECLINES_NAME_C_III_4647           "C-III-4647"
+#define GAL_SPECLINES_NAME_C_III_4650           "C-III-4650"
+#define GAL_SPECLINES_NAME_C_III_5651           "C-III-5651"
+#define GAL_SPECLINES_NAME_Fe_III_4658          "Fe-III-4658"
+#define GAL_SPECLINES_NAME_He_II_4685           "He-II-4685"
+#define GAL_SPECLINES_NAME_Ar_IV_4711           "Ar-IV-4711"
+#define GAL_SPECLINES_NAME_Ar_IV_4740           "Ar-IV-4740"
+#define GAL_SPECLINES_NAME_H_beta               "H-beta"
+#define GAL_SPECLINES_NAME_Fe_VII_4893          "Fe-VII-4893"
+#define GAL_SPECLINES_NAME_Fe_IV_4903           "Fe-IV-4903"
+#define GAL_SPECLINES_NAME_Fe_II_4923           "Fe-II-4923"
+#define GAL_SPECLINES_NAME_O_III_4958           "O-III-4958"
+#define GAL_SPECLINES_NAME_O_III_5006           "O-III-5006"
+#define GAL_SPECLINES_NAME_Fe_II_5018           "Fe-II-5018"
+#define GAL_SPECLINES_NAME_Fe_III_5084          "Fe-III-5084"
+#define GAL_SPECLINES_NAME_Fe_VI_5145           "Fe-VI-5145"
+#define GAL_SPECLINES_NAME_Fe_VII_5158          "Fe-VII-5158"
+#define GAL_SPECLINES_NAME_Fe_II_5169           "Fe-II-5169"
+#define GAL_SPECLINES_NAME_Fe_VI_5176           "Fe-VI-5176"
+#define GAL_SPECLINES_NAME_Fe_II_5197           "Fe-II-5197"
+#define GAL_SPECLINES_NAME_N_I_5200             "N-I-5200"
+#define GAL_SPECLINES_NAME_Fe_II_5234           "Fe-II-5234"
+#define GAL_SPECLINES_NAME_Fe_IV_5236           "Fe-IV-5236"
+#define GAL_SPECLINES_NAME_Fe_III_5270          "Fe-III-5270"
+#define GAL_SPECLINES_NAME_Fe_II_5276           "Fe-II-5276"
+#define GAL_SPECLINES_NAME_Fe_VII_5276          "Fe-VII-5276"
+#define GAL_SPECLINES_NAME_Fe_XIV               "Fe-XIV"
+#define GAL_SPECLINES_NAME_Ca_V                 "Ca-V"
+#define GAL_SPECLINES_NAME_Fe_II_5316_6         "Fe-II-5316-6"
+#define GAL_SPECLINES_NAME_Fe_II_5316_7         "Fe-II-5316-7"
+#define GAL_SPECLINES_NAME_Fe_VI_5335           "Fe-VI-5335"
+#define GAL_SPECLINES_NAME_Fe_VI_5424           "Fe-VI-5424"
+#define GAL_SPECLINES_NAME_Cl_III_5517          "Cl-III-5517"
+#define GAL_SPECLINES_NAME_Cl_III_5537          "Cl-III-5537"
+#define GAL_SPECLINES_NAME_Fe_VI_5637           "Fe-VI-5637"
+#define GAL_SPECLINES_NAME_Fe_VI_5677           "Fe-VI-5677"
+#define GAL_SPECLINES_NAME_C_III_5697           "C-III-5697"
+#define GAL_SPECLINES_NAME_Fe_VII_5720          "Fe-VII-5720"
+#define GAL_SPECLINES_NAME_N_II_5754            "N-II-5754"
+#define GAL_SPECLINES_NAME_C_IV_5801            "C-IV-5801"
+#define GAL_SPECLINES_NAME_C_IV_5811            "C-IV-5811"
+#define GAL_SPECLINES_NAME_He_I_5875            "He-I-5875"
+#define GAL_SPECLINES_NAME_O_I_6046             "O-I-6046"
+#define GAL_SPECLINES_NAME_Fe_VII_6087          "Fe-VII-6087"
+#define GAL_SPECLINES_NAME_O_I_6300             "O-I-6300"
+#define GAL_SPECLINES_NAME_S_III_6312           "S-III-6312"
+#define GAL_SPECLINES_NAME_Si_II_6347           "Si-II-6347"
+#define GAL_SPECLINES_NAME_O_I_6363             "O-I-6363"
+#define GAL_SPECLINES_NAME_Fe_II_6369           "Fe-II-6369"
+#define GAL_SPECLINES_NAME_Fe_X                 "Fe-X"
+#define GAL_SPECLINES_NAME_Fe_II_6516           "Fe-II-6516"
+#define GAL_SPECLINES_NAME_N_II_6548            "N-II-6548"
+#define GAL_SPECLINES_NAME_H_alpha              "H-alpha"
+#define GAL_SPECLINES_NAME_N_II_6583            "N-II-6583"
+#define GAL_SPECLINES_NAME_S_II_6716            "S-II-6716"
+#define GAL_SPECLINES_NAME_S_II_6730            "S-II-6730"
+#define GAL_SPECLINES_NAME_O_I_7002             "O-I-7002"
+#define GAL_SPECLINES_NAME_Ar_V                 "Ar-V"
+#define GAL_SPECLINES_NAME_He_I_7065            "He-I-7065"
+#define GAL_SPECLINES_NAME_Ar_III_7135          "Ar-III-7135"
+#define GAL_SPECLINES_NAME_Fe_II_7155           "Fe-II-7155"
+#define GAL_SPECLINES_NAME_Ar_IV_7170           "Ar-IV-7170"
+#define GAL_SPECLINES_NAME_Fe_II_7172           "Fe-II-7172"
+#define GAL_SPECLINES_NAME_C_II_7236            "C-II-7236"
+#define GAL_SPECLINES_NAME_Ar_IV_7237           "Ar-IV-7237"
+#define GAL_SPECLINES_NAME_O_I_7254             "O-I-7254"
+#define GAL_SPECLINES_NAME_Ar_IV_7262           "Ar-IV-7262"
+#define GAL_SPECLINES_NAME_He_I_7281            "He-I-7281"
+#define GAL_SPECLINES_NAME_O_II_7319            "O-II-7319"
+#define GAL_SPECLINES_NAME_O_II_7330            "O-II-7330"
+#define GAL_SPECLINES_NAME_Ni_II_7377           "Ni-II-7377"
+#define GAL_SPECLINES_NAME_Ni_II_7411           "Ni-II-7411"
+#define GAL_SPECLINES_NAME_Fe_II_7452           "Fe-II-7452"
+#define GAL_SPECLINES_NAME_N_I_7468             "N-I-7468"
+#define GAL_SPECLINES_NAME_S_XII                "S-XII"
+#define GAL_SPECLINES_NAME_Ar_III_7751          "Ar-III-7751"
+#define GAL_SPECLINES_NAME_He_I_7816            "He-I-7816"
+#define GAL_SPECLINES_NAME_Ar_I_7868            "Ar-I-7868"
+#define GAL_SPECLINES_NAME_Ni_III               "Ni-III"
+#define GAL_SPECLINES_NAME_Fe_XI_7891           "Fe-XI-7891"
+#define GAL_SPECLINES_NAME_He_II_8236           "He-II-8236"
+#define GAL_SPECLINES_NAME_Pa_20                "Pa-20"
+#define GAL_SPECLINES_NAME_Pa_19                "Pa-19"
+#define GAL_SPECLINES_NAME_Pa_18                "Pa-18"
+#define GAL_SPECLINES_NAME_O_I_8446             "O-I-8446"
+#define GAL_SPECLINES_NAME_Pa_17                "Pa-17"
+#define GAL_SPECLINES_NAME_Ca_II_8498           "Ca-II-8498"
+#define GAL_SPECLINES_NAME_Pa_16                "Pa-16"
+#define GAL_SPECLINES_NAME_Ca_II_8542           "Ca-II-8542"
+#define GAL_SPECLINES_NAME_Pa_15                "Pa-15"
+#define GAL_SPECLINES_NAME_Cl_II                "Cl-II"
+#define GAL_SPECLINES_NAME_Pa_14                "Pa-14"
+#define GAL_SPECLINES_NAME_Fe_II_8616           "Fe-II-8616"
+#define GAL_SPECLINES_NAME_Ca_II_8662           "Ca-II-8662"
+#define GAL_SPECLINES_NAME_Pa_13                "Pa-13"
+#define GAL_SPECLINES_NAME_N_I_8680             "N-I-8680"
+#define GAL_SPECLINES_NAME_N_I_8703             "N-I-8703"
+#define GAL_SPECLINES_NAME_N_I_8711             "N-I-8711"
+#define GAL_SPECLINES_NAME_Pa_12                "Pa-12"
+#define GAL_SPECLINES_NAME_Pa_11                "Pa-11"
+#define GAL_SPECLINES_NAME_Fe_II_8891           "Fe-II-8891"
+#define GAL_SPECLINES_NAME_Pa_10                "Pa-10"
+#define GAL_SPECLINES_NAME_S_III_9068           "S-III-9068"
+#define GAL_SPECLINES_NAME_Pa_9                 "Pa-9"
+#define GAL_SPECLINES_NAME_S_III_9531           "S-III-9531"
+#define GAL_SPECLINES_NAME_Pa_epsilon           "Pa-epsilon"
+#define GAL_SPECLINES_NAME_C_I_9824             "C-I-9824"
+#define GAL_SPECLINES_NAME_C_I_9850             "C-I-9850"
+#define GAL_SPECLINES_NAME_S_VIII               "S-VIII"
+#define GAL_SPECLINES_NAME_He_I_10027           "He-I-10027"
+#define GAL_SPECLINES_NAME_He_I_10031           "He-I-10031"
+#define GAL_SPECLINES_NAME_Pa_delta             "Pa-delta"
+#define GAL_SPECLINES_NAME_S_II_10286           "S-II-10286"
+#define GAL_SPECLINES_NAME_S_II_10320           "S-II-10320"
+#define GAL_SPECLINES_NAME_S_II_10336           "S-II-10336"
+#define GAL_SPECLINES_NAME_Fe_XIII              "Fe-XIII"
+#define GAL_SPECLINES_NAME_He_I_10830           "He-I-10830"
+#define GAL_SPECLINES_NAME_Pa_gamma             "Pa-gamma"
+
+/* The limits. */
+#define GAL_SPECLINES_NAME_LIMIT_LYMAN          "Ly-limit"
+#define GAL_SPECLINES_NAME_LIMIT_BALMER         "H-limit"
+#define GAL_SPECLINES_NAME_LIMIT_PASCHEN        "Pa-limit"
+
+
 /*********************************************************************/
 /*************        Internal names and codes         ***************/
 /*********************************************************************/
diff --git a/lib/list.c b/lib/list.c
index 50b38061..0ee1b533 100644
--- a/lib/list.c
+++ b/lib/list.c
@@ -227,7 +227,7 @@ gal_list_str_extract(char *string)
 
 
 char *
-gal_list_str_cat(gal_list_str_t *list)
+gal_list_str_cat(gal_list_str_t *list, char delimiter)
 {
   size_t bsize=0;
   char *c, *o, *out;
@@ -242,7 +242,8 @@ gal_list_str_cat(gal_list_str_t *list)
     {
       /* Count the characters. If we have a SPACE, we need to add an extra
          count for the back slash.*/
-      c=tmp->v; do {++bsize; if(*c==' ') ++bsize;} while(*(++c)!='\0');
+      c=tmp->v;
+      do {++bsize; if(*c==delimiter) ++bsize;} while(*(++c)!='\0');
       ++bsize; /* For the extra space between characters */
     }
 
@@ -253,8 +254,8 @@ gal_list_str_cat(gal_list_str_t *list)
   for(tmp=list; tmp!=NULL; tmp=tmp->next)
     {
       c=tmp->v;
-      do {if(*c==' ') *o++='\\'; *o++=*c;} while(*(++c)!='\0');
-      *o++=' ';
+      do {if(*c==delimiter) *o++='\\'; *o++=*c;} while(*(++c)!='\0');
+      if(tmp->next) *o++=delimiter;
     }
   *o='\0';
 
diff --git a/lib/makeplugin.c b/lib/makeplugin.c
index c2ae1754..19b43d1d 100644
--- a/lib/makeplugin.c
+++ b/lib/makeplugin.c
@@ -126,7 +126,7 @@ makeplugin_text_contains_base(char **argv, int has1_not0)
   /* Write the list into one string, but first reverse it so it has the
      same order as the input. */
   gal_list_str_reverse(&outlist);
-  out=gal_list_str_cat(outlist);
+  out=gal_list_str_cat(outlist, ' ');
 
   /* Clean up and return. */
   gal_list_str_free(strings, 1);
@@ -243,7 +243,7 @@ makeplugin_fits_with_keyvalue(const char *caller, unsigned 
int argc,
   outlist=gal_fits_with_keyvalue(files, hdu, name, values);
 
   /* Write the output string */
-  out=gal_list_str_cat(outlist);
+  out=gal_list_str_cat(outlist, ' ');
 
   /* Clean up and return. */
   gal_list_str_free(files, 1);
@@ -279,7 +279,7 @@ makeplugin_fits_unique_keyvalues(const char *caller, 
unsigned int argc,
   outlist=gal_fits_unique_keyvalues(files, hdu, name);
 
   /* Write the output value. */
-  out=gal_list_str_cat(outlist);
+  out=gal_list_str_cat(outlist, ' ');
 
   /* Clean up and return. */
   gal_list_str_free(files, 1);
diff --git a/lib/options.c b/lib/options.c
index ad361c63..426444fe 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -966,7 +966,8 @@ gal_options_parse_list_of_numbers(char *string, char 
*filename,
 #define OPTIONS_COMMENTED_COMMA 14
 #define OPTIONS_COMMENTED_COLON 15
 gal_data_t *
-gal_options_parse_list_of_strings(char *string, char *filename, size_t lineno)
+gal_options_parse_list_of_strings(char *string, char *filename,
+                                  size_t lineno)
 {
   size_t num;
   gal_data_t *out;
@@ -1048,28 +1049,60 @@ gal_options_parse_list_of_strings(char *string, char 
*filename, size_t lineno)
 
 
 
-/* The input to this function is a string of any number of strings
-   separated by a comma (',') for example: 'a,abc,abcd'. The output
-   'gal_data_t' contains the array of given strings. You can read the
-   number of inputs from its 'size' element. */
-gal_data_t *
-gal_options_parse_csv_strings_raw(char *string, char *filename,
-                                  size_t lineno)
+static int
+options_string_has_space(char *string)
 {
-  size_t i, num;
-  gal_data_t *out;
-  char *c=string, *cc, *str=NULL;
-  gal_list_str_t *list=NULL, *tstrll=NULL;
+  char *c;
 
+  /* If a space character is present, just return. */
+  for(c=string;*c!='\0';++c) if(*c==' ' || *c=='\t') return 1;
 
-  /* The nature of the arrays/numbers read here is very small, so since
-     'p->cp.minmapsize' might not have been read yet, we will set it to -1
-     (largest size_t number), so the values are kept in memory. */
-  int quietmmap=1;
-  size_t minmapsize=-1;
+  /* If control reaches here, there was no space character. */
+  return 0;
+}
+
+
+
+
+#if 0
+static char *
+options_print_liststr_as_csv(void *inval)
+{
+  char *out=NULL;
+  gal_list_str_t *tmp, *values=*(gal_list_str_t **)(option->value);
+
+  for(tmp=values;tmp!=NULL;tmp=tmp->next)
+    printf("%s: %s\n", __func__, tmp->v);
+
+  /* Return output. */
+  return out;
+}
+#endif
+
+
+
+
+
+/* NOTE: output is REVERSED (since the option parsing automatically
+   reverses STRLLs at its end).. */
+gal_list_str_t *
+gal_options_parse_csv_strings_to_list(char *string, char *filename,
+                                      size_t lineno)
+{
+  char *str=NULL;
+  char *cc, *c=string;
+  gal_list_str_t *list=NULL;
 
+  /* Remove any possibly commented new-line where we have a backslash
+     followed by a new-line character (replace the two characters with two
+     single space characters). This can happen with the "--column='arith'"
+     feature in Table, when it gets long (bug #58371). But to be general in
+     other cases too, we'll just correct it here. */
+  for(c=string;*c!='\0';++c)
+    if(*c=='\\' && *(c+1)=='\n') { *c=' '; *(++c)=' '; }
 
   /* Go through the input character by character. */
+  c=string;
   while(string && *c!='\0')
     {
       switch(*c)
@@ -1077,7 +1110,7 @@ gal_options_parse_csv_strings_raw(char *string, char 
*filename,
         /* Comma marks the transition to the next string. */
         case ',':
 
-          /* The whole can't start with a comma. */
+          /* The whole string can't start with a comma. */
           if(str==NULL)
             {
               if(filename)
@@ -1112,11 +1145,80 @@ gal_options_parse_csv_strings_raw(char *string, char 
*filename,
       ++c;
     }
 
-
   /* If the last element wasn't a comma, the last string hasn't been added
      to the list yet. */
   if(str) gal_list_str_add(&list, str, 1);
 
+  /* Return the reversed list (the option parsing tools automatically
+     reverse STRLLs at the end). */
+  return list;
+}
+
+
+
+
+
+/* For options that can take multiple values multiple times:
+
+    --option=val1,val2 --option=val3,val4,val5 ...
+
+   We want to merge/append all the separate values into separate tokens of
+   a single 'gal_list_str_t'.
+ */
+void *
+gal_options_parse_csv_strings_append(struct argp_option *option, char *arg,
+                                     char *filename, size_t lineno,
+                                     void *junk)
+{
+  gal_list_str_t *olist, *alist;
+
+  /* We want to print the values. */
+  if(lineno==-1)
+    return gal_list_str_cat(*(gal_list_str_t **)(option->value), ',');
+
+  /* We want to read the values. */
+  else
+    {
+      /* Read all the values given to this instance of the option. */
+      alist=gal_options_parse_csv_strings_to_list(arg, filename, lineno);
+
+      /* Get the output list and update it by putting the new list before
+         it (note that the option parsing infrastructure will automatically
+         reverse STRLLs. */
+      olist=*(gal_list_str_t **)(option->value);
+      gal_list_str_last(alist)->next=olist;
+      *(gal_list_str_t **)(option->value)=alist;
+
+      /* Return a NULL pointer */
+      return NULL;
+    }
+}
+
+
+
+
+
+/* The input to this function is a string of any number of strings
+   separated by a comma (',') for example: 'a,abc,abcd'. The output
+   'gal_data_t' contains the array of given strings. You can read the
+   number of inputs from its 'size' element. */
+gal_data_t *
+gal_options_parse_csv_strings_to_data(char *string, char *filename,
+                                      size_t lineno)
+{
+  size_t i, num;
+  gal_data_t *out;
+  gal_list_str_t *list=NULL, *tstrll=NULL;
+
+
+  /* The nature of the arrays/numbers read here is very small, so since
+     'p->cp.minmapsize' might not have been read yet, we will set it to -1
+     (largest size_t number), so the values are kept in memory. */
+  int quietmmap=1;
+  size_t minmapsize=-1;
+
+  /* Extract the separate tokens in the CSV string. */
+  list=gal_options_parse_csv_strings_to_list(string, filename, lineno);
 
   /* Allocate the output data structure and fill it up. */
   if(list)
@@ -1160,7 +1262,7 @@ gal_options_parse_csv_strings(struct argp_option *option, 
char *arg,
                               char *filename, size_t lineno, void *junk)
 {
   size_t nc;
-  char *c, **strarr;
+  char **strarr;
   int i, has_space=0;
   gal_data_t *values;
   char *str, sstr[GAL_OPTIONS_STATIC_MEM_FOR_VALUES];
@@ -1174,22 +1276,13 @@ gal_options_parse_csv_strings(struct argp_option 
*option, char *arg,
       /* See if there are any space characters in the final string. */
       strarr=values->array;
       for(i=0;i<values->size;++i)
-        if(has_space==0)
-        {
-          for(c=strarr[i];*c!='\0';++c)
-            if(*c==' ' || *c=='\t')
-              {
-                has_space=1;
-                break;
-              }
-        }
+        if(has_space==0) has_space=options_string_has_space(strarr[i]);
 
       /* If there is a space, the string must start wth quotation marks. */
       nc = has_space ? 1 : 0;
       if(has_space) {sstr[0]='"'; sstr[1]='\0';}
 
-
-      /* Write each string into the output string */
+      /* Write each string into the output string. */
       for(i=0;i<values->size;++i)
         {
           if( nc > GAL_OPTIONS_STATIC_MEM_FOR_VALUES-100 )
@@ -1224,9 +1317,11 @@ gal_options_parse_csv_strings(struct argp_option 
*option, char *arg,
                       "given to '--%s'", option->name);
 
       /* Read the values. */
-      values=gal_options_parse_csv_strings_raw(arg, filename, lineno);
+      values=gal_options_parse_csv_strings_to_data(arg, filename, lineno);
 
-      /* Put the values into the option. */
+      /* Put the values into the option and return NULL (the return value
+         is only for cases where the user wants to see the values, not set
+         them). */
       *(gal_data_t **)(option->value) = values;
       return NULL;
     }
@@ -1265,7 +1360,7 @@ gal_options_merge_list_of_csv(gal_list_str_t **list)
 
       /* Read the different comma-separated strings into an array (within a
          'gal_data_t'). */
-      strs=gal_options_parse_csv_strings_raw(tmp->v, NULL, 0);
+      strs=gal_options_parse_csv_strings_to_data(tmp->v, NULL, 0);
       strarr=strs->array;
 
       /* Go through all the items and add the pointers to the output
@@ -2609,8 +2704,8 @@ options_parse_file(char *filename,  struct 
gal_options_common_params *cp,
             if( options_set_from_name(name, arg, cp->coptions, cp,
                                       filename, lineno) )
               error_at_line(EXIT_FAILURE, 0, filename, lineno,
-                            "unrecognized option '%s', for the full list of "
-                            "options, please run with '--help'", name);
+                            "unrecognized option '%s', for the full list "
+                            "of options, please run with '--help'", name);
         }
     }
 
diff --git a/lib/permutation.c b/lib/permutation.c
index a9bc1b65..0115692d 100644
--- a/lib/permutation.c
+++ b/lib/permutation.c
@@ -23,6 +23,8 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <config.h>
 
 #include <stdio.h>
+#include <errno.h>
+#include <error.h>
 #include <string.h>
 #include <stdlib.h>
 
@@ -208,3 +210,118 @@ gal_permutation_apply(gal_data_t *input, size_t 
*permutation)
 void
 gal_permutation_apply_onlydim0(gal_data_t *input, size_t *permutation)
 { permutation_apply_raw(input, permutation, 1); }
+
+
+
+
+
+/* Transpose square (2d) input. */
+static void
+permutation_transpose_2d_square(gal_data_t *input)
+{
+  void *a, *b, *swap;
+  size_t width=input->dsize[0];
+  size_t i, j, nbytes=gal_type_sizeof(input->type);
+
+  /* Allocate the SWAP space, we are just allocating an 64-bit integer for
+     its storage. */
+  swap=gal_pointer_allocate(GAL_TYPE_UINT64, 1, 0, __func__, "swap");
+
+  /* Go over the elements. */
+  for(i=0;i<width;++i)
+    for(j=i+1;j<width;++j)
+      {
+        /* For easy reading. */
+        a=gal_pointer_increment(input->array, i*width+j, input->type);
+        b=gal_pointer_increment(input->array, j*width+i, input->type);
+
+        /* Copy the "to" value into the swap, then copy the "from" value
+           into "to" and finally copy swap into "from". */
+        memcpy(swap, a,    nbytes);
+        memcpy(a,    b,    nbytes);
+        memcpy(b,    swap, nbytes);
+      }
+
+  /* Clean up. */
+  free(swap);
+}
+
+
+
+
+
+/* Transpose square (2d) input. */
+static void
+permutation_transpose_2d_rectangle(gal_data_t *input)
+{
+  void *a, *b;
+  size_t i, j, nbytes;
+  gal_data_t *out=NULL;
+  size_t *id=input->dsize, od[2]={id[1], id[0]};
+
+  /* Moving values in memory is only necessary when the 0-th dimension has
+     more than one element. */
+  if(input->dsize[0]>1)
+    {
+      /* Allocate the output array. */
+      out=gal_data_alloc(NULL, input->type, 2, od, NULL, 0,
+                         input->minmapsize, input->quietmmap,
+                         NULL, NULL, NULL);
+
+      /* Go over the elements and put them in the proper place of the
+         output. */
+      nbytes=gal_type_sizeof(input->type);
+      for(i=0;i<id[0];++i)
+        for(j=0;j<id[1];++j)
+          {
+            /* For easy reading. */
+            a=gal_pointer_increment(input->array, i*id[1]+j, input->type);
+            b=gal_pointer_increment(out->array,   j*od[1]+i, input->type);
+
+            /* Copy the input ('a' pointer) to output ('b') pointer. */
+            memcpy(b, a, nbytes);
+          }
+
+      /* Free the original input pointer and replace it with the output
+         array, then free the output. */
+      free(input->array);
+      input->array=out->array;
+      out->array=NULL;
+      gal_data_free(out);
+    }
+
+  /* Update the dimesions */
+  input->dsize[0]=od[0];
+  input->dsize[1]=od[1];
+}
+
+
+
+
+
+/* Transpose a 2D dataset. */
+void
+gal_permutation_transpose_2d(gal_data_t *input)
+{
+  uint8_t type;
+  size_t nbytes;
+
+  /* Sanity checks, see the comment below. */
+  type=input->type;
+  nbytes=gal_type_sizeof(type);
+  if(nbytes>8)
+    error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at '%s' to "
+          "find the cause and fix this problem. This function currently "
+          "assumes the largest possible type size is 8 bytes, but the "
+          "requested '%s' type needs %zu bytes", __func__,
+          PACKAGE_BUGREPORT, gal_type_name(type, 1), nbytes);
+  if(input->ndim!=2)
+    error(EXIT_FAILURE, 0, "%s: only 2D inputs are supported", __func__);
+
+  /* A square array can be transposed much more easier and faster than a
+     non-square array. */
+  if(input->dsize[0]==input->dsize[1])
+    permutation_transpose_2d_square(input);
+  else
+    permutation_transpose_2d_rectangle(input);
+}
diff --git a/lib/speclines.c b/lib/speclines.c
index 6fca0955..151f2d7d 100644
--- a/lib/speclines.c
+++ b/lib/speclines.c
@@ -41,49 +41,246 @@ gal_speclines_line_name(int linecode)
 {
   switch(linecode)
     {
-    case GAL_SPECLINES_SIIRED:           return GAL_SPECLINES_NAME_SIIRED;
-    case GAL_SPECLINES_SII:              return GAL_SPECLINES_NAME_SII;
-    case GAL_SPECLINES_SIIBLUE:          return GAL_SPECLINES_NAME_SIIBLUE;
-    case GAL_SPECLINES_NIIRED:           return GAL_SPECLINES_NAME_NIIRED;
-    case GAL_SPECLINES_NII:              return GAL_SPECLINES_NAME_NII;
-    case GAL_SPECLINES_HALPHA:           return GAL_SPECLINES_NAME_HALPHA;
-    case GAL_SPECLINES_NIIBLUE:          return GAL_SPECLINES_NAME_NIIBLUE;
-    case GAL_SPECLINES_OIIIRED_VIS:      return GAL_SPECLINES_NAME_OIIIRED_VIS;
-    case GAL_SPECLINES_OIII_VIS:         return GAL_SPECLINES_NAME_OIII_VIS;
-    case GAL_SPECLINES_OIIIBLUE_VIS:     return 
GAL_SPECLINES_NAME_OIIIBLUE_VIS;
-    case GAL_SPECLINES_HBETA:            return GAL_SPECLINES_NAME_HBETA;
-    case GAL_SPECLINES_HEII_VIS:         return GAL_SPECLINES_NAME_HEII_VIS;
-    case GAL_SPECLINES_HGAMMA:           return GAL_SPECLINES_NAME_HGAMMA;
-    case GAL_SPECLINES_HDELTA:           return GAL_SPECLINES_NAME_HDELTA;
-    case GAL_SPECLINES_HEPSILON:         return GAL_SPECLINES_NAME_HEPSILON;
-    case GAL_SPECLINES_NEIII:            return GAL_SPECLINES_NAME_NEIII;
-    case GAL_SPECLINES_OIIRED:           return GAL_SPECLINES_NAME_OIIRED;
-    case GAL_SPECLINES_OII:              return GAL_SPECLINES_NAME_OII;
-    case GAL_SPECLINES_OIIBLUE:          return GAL_SPECLINES_NAME_OIIBLUE;
-    case GAL_SPECLINES_BLIMIT:           return GAL_SPECLINES_NAME_BLIMIT;
-    case GAL_SPECLINES_MGIIRED:          return GAL_SPECLINES_NAME_MGIIRED;
-    case GAL_SPECLINES_MGII:             return GAL_SPECLINES_NAME_MGII;
-    case GAL_SPECLINES_MGIIBLUE:         return GAL_SPECLINES_NAME_MGIIBLUE;
-    case GAL_SPECLINES_CIIIRED:          return GAL_SPECLINES_NAME_CIIIRED;
-    case GAL_SPECLINES_CIII:             return GAL_SPECLINES_NAME_CIII;
-    case GAL_SPECLINES_CIIIBLUE:         return GAL_SPECLINES_NAME_CIIIBLUE;
-    case GAL_SPECLINES_SiIIIRED:         return GAL_SPECLINES_NAME_SiIIIRED;
-    case GAL_SPECLINES_SiIII:            return GAL_SPECLINES_NAME_SiIII;
-    case GAL_SPECLINES_SiIIIBLUE:        return GAL_SPECLINES_NAME_SiIIIBLUE;
-    case GAL_SPECLINES_OIIIRED_UV:       return GAL_SPECLINES_NAME_OIIIRED_UV;
-    case GAL_SPECLINES_OIII_UV:          return GAL_SPECLINES_NAME_OIII_UV;
-    case GAL_SPECLINES_OIIIBLUE_UV:      return GAL_SPECLINES_NAME_OIIIBLUE_UV;
-    case GAL_SPECLINES_HEII_UV:          return GAL_SPECLINES_NAME_HEII_UV;
-    case GAL_SPECLINES_CIVRED:           return GAL_SPECLINES_NAME_CIVRED;
-    case GAL_SPECLINES_CIV:              return GAL_SPECLINES_NAME_CIV;
-    case GAL_SPECLINES_CIVBLUE:          return GAL_SPECLINES_NAME_CIVBLUE;
-    case GAL_SPECLINES_NV:               return GAL_SPECLINES_NAME_NV;
-    case GAL_SPECLINES_LYALPHA:          return GAL_SPECLINES_NAME_LYALPHA;
-    case GAL_SPECLINES_LYBETA:           return GAL_SPECLINES_NAME_LYBETA;
-    case GAL_SPECLINES_LYGAMMA:          return GAL_SPECLINES_NAME_LYGAMMA;
-    case GAL_SPECLINES_LYDELTA:          return GAL_SPECLINES_NAME_LYDELTA;
-    case GAL_SPECLINES_LYEPSILON:        return GAL_SPECLINES_NAME_LYEPSILON;
-    case GAL_SPECLINES_LYLIMIT:          return GAL_SPECLINES_NAME_LYLIMIT;
+    case GAL_SPECLINES_Ne_VIII_770:    return GAL_SPECLINES_NAME_Ne_VIII_770;
+    case GAL_SPECLINES_Ne_VIII_780:    return GAL_SPECLINES_NAME_Ne_VIII_780;
+    case GAL_SPECLINES_Ly_epsilon:     return GAL_SPECLINES_NAME_Ly_epsilon;
+    case GAL_SPECLINES_Ly_delta:       return GAL_SPECLINES_NAME_Ly_delta;
+    case GAL_SPECLINES_Ly_gamma:       return GAL_SPECLINES_NAME_Ly_gamma;
+    case GAL_SPECLINES_C_III_977:      return GAL_SPECLINES_NAME_C_III_977;
+    case GAL_SPECLINES_N_III_989:      return GAL_SPECLINES_NAME_N_III_989;
+    case GAL_SPECLINES_N_III_991_51:   return GAL_SPECLINES_NAME_N_III_991_51;
+    case GAL_SPECLINES_N_III_991_57:   return GAL_SPECLINES_NAME_N_III_991_57;
+    case GAL_SPECLINES_Ly_beta:        return GAL_SPECLINES_NAME_Ly_beta;
+    case GAL_SPECLINES_O_VI_1031:      return GAL_SPECLINES_NAME_O_VI_1031;
+    case GAL_SPECLINES_O_VI_1037:      return GAL_SPECLINES_NAME_O_VI_1037;
+    case GAL_SPECLINES_Ar_I_1066:      return GAL_SPECLINES_NAME_Ar_I_1066;
+    case GAL_SPECLINES_Ly_alpha:       return GAL_SPECLINES_NAME_Ly_alpha;
+    case GAL_SPECLINES_N_V_1238:       return GAL_SPECLINES_NAME_N_V_1238;
+    case GAL_SPECLINES_N_V_1242:       return GAL_SPECLINES_NAME_N_V_1242;
+    case GAL_SPECLINES_Si_II_1260:     return GAL_SPECLINES_NAME_Si_II_1260;
+    case GAL_SPECLINES_Si_II_1264:     return GAL_SPECLINES_NAME_Si_II_1264;
+    case GAL_SPECLINES_O_I_1302:       return GAL_SPECLINES_NAME_O_I_1302;
+    case GAL_SPECLINES_C_II_1334:      return GAL_SPECLINES_NAME_C_II_1334;
+    case GAL_SPECLINES_C_II_1335:      return GAL_SPECLINES_NAME_C_II_1335;
+    case GAL_SPECLINES_Si_IV_1393:     return GAL_SPECLINES_NAME_Si_IV_1393;
+    case GAL_SPECLINES_O_IV_1397:      return GAL_SPECLINES_NAME_O_IV_1397;
+    case GAL_SPECLINES_O_IV_1399:      return GAL_SPECLINES_NAME_O_IV_1399;
+    case GAL_SPECLINES_Si_IV_1402:     return GAL_SPECLINES_NAME_Si_IV_1402;
+    case GAL_SPECLINES_N_IV_1486:      return GAL_SPECLINES_NAME_N_IV_1486;
+    case GAL_SPECLINES_C_IV_1548:      return GAL_SPECLINES_NAME_C_IV_1548;
+    case GAL_SPECLINES_C_IV_1550:      return GAL_SPECLINES_NAME_C_IV_1550;
+    case GAL_SPECLINES_He_II_1640:     return GAL_SPECLINES_NAME_He_II_1640;
+    case GAL_SPECLINES_O_III_1660:     return GAL_SPECLINES_NAME_O_III_1660;
+    case GAL_SPECLINES_O_III_1666:     return GAL_SPECLINES_NAME_O_III_1666;
+    case GAL_SPECLINES_N_III_1746:     return GAL_SPECLINES_NAME_N_III_1746;
+    case GAL_SPECLINES_N_III_1748:     return GAL_SPECLINES_NAME_N_III_1748;
+    case GAL_SPECLINES_Al_III_1854:    return GAL_SPECLINES_NAME_Al_III_1854;
+    case GAL_SPECLINES_Al_III_1862:    return GAL_SPECLINES_NAME_Al_III_1862;
+    case GAL_SPECLINES_Si_III:         return GAL_SPECLINES_NAME_Si_III;
+    case GAL_SPECLINES_C_III_1908:     return GAL_SPECLINES_NAME_C_III_1908;
+    case GAL_SPECLINES_N_II_2142:      return GAL_SPECLINES_NAME_N_II_2142;
+    case GAL_SPECLINES_O_III_2320:     return GAL_SPECLINES_NAME_O_III_2320;
+    case GAL_SPECLINES_C_II_2323:      return GAL_SPECLINES_NAME_C_II_2323;
+    case GAL_SPECLINES_C_II_2324:      return GAL_SPECLINES_NAME_C_II_2324;
+    case GAL_SPECLINES_Fe_XI_2648:     return GAL_SPECLINES_NAME_Fe_XI_2648;
+    case GAL_SPECLINES_He_II_2733:     return GAL_SPECLINES_NAME_He_II_2733;
+    case GAL_SPECLINES_Mg_V_2782:      return GAL_SPECLINES_NAME_Mg_V_2782;
+    case GAL_SPECLINES_Mg_II_2795:     return GAL_SPECLINES_NAME_Mg_II_2795;
+    case GAL_SPECLINES_Mg_II_2802:     return GAL_SPECLINES_NAME_Mg_II_2802;
+    case GAL_SPECLINES_Fe_IV_2829:     return GAL_SPECLINES_NAME_Fe_IV_2829;
+    case GAL_SPECLINES_Fe_IV_2835:     return GAL_SPECLINES_NAME_Fe_IV_2835;
+    case GAL_SPECLINES_Ar_IV_2853:     return GAL_SPECLINES_NAME_Ar_IV_2853;
+    case GAL_SPECLINES_Ar_IV_2868:     return GAL_SPECLINES_NAME_Ar_IV_2868;
+    case GAL_SPECLINES_Mg_V_2928:      return GAL_SPECLINES_NAME_Mg_V_2928;
+    case GAL_SPECLINES_He_I_2945:      return GAL_SPECLINES_NAME_He_I_2945;
+    case GAL_SPECLINES_O_III_3132:     return GAL_SPECLINES_NAME_O_III_3132;
+    case GAL_SPECLINES_He_I_3187:      return GAL_SPECLINES_NAME_He_I_3187;
+    case GAL_SPECLINES_He_II_3203:     return GAL_SPECLINES_NAME_He_II_3203;
+    case GAL_SPECLINES_O_III_3312:     return GAL_SPECLINES_NAME_O_III_3312;
+    case GAL_SPECLINES_Ne_V_3345:      return GAL_SPECLINES_NAME_Ne_V_3345;
+    case GAL_SPECLINES_Ne_V_3425:      return GAL_SPECLINES_NAME_Ne_V_3425;
+    case GAL_SPECLINES_O_III_3444:     return GAL_SPECLINES_NAME_O_III_3444;
+    case GAL_SPECLINES_N_I_3466_4:     return GAL_SPECLINES_NAME_N_I_3466_4;
+    case GAL_SPECLINES_N_I_3466_5:     return GAL_SPECLINES_NAME_N_I_3466_5;
+    case GAL_SPECLINES_He_I_3487:      return GAL_SPECLINES_NAME_He_I_3487;
+    case GAL_SPECLINES_Fe_VII_3586:    return GAL_SPECLINES_NAME_Fe_VII_3586;
+    case GAL_SPECLINES_Fe_VI_3662:     return GAL_SPECLINES_NAME_Fe_VI_3662;
+    case GAL_SPECLINES_H_19:           return GAL_SPECLINES_NAME_H_19;
+    case GAL_SPECLINES_H_18:           return GAL_SPECLINES_NAME_H_18;
+    case GAL_SPECLINES_H_17:           return GAL_SPECLINES_NAME_H_17;
+    case GAL_SPECLINES_H_16:           return GAL_SPECLINES_NAME_H_16;
+    case GAL_SPECLINES_H_15:           return GAL_SPECLINES_NAME_H_15;
+    case GAL_SPECLINES_H_14:           return GAL_SPECLINES_NAME_H_14;
+    case GAL_SPECLINES_O_II_3726:      return GAL_SPECLINES_NAME_O_II_3726;
+    case GAL_SPECLINES_O_II_3728:      return GAL_SPECLINES_NAME_O_II_3728;
+    case GAL_SPECLINES_H_13:           return GAL_SPECLINES_NAME_H_13;
+    case GAL_SPECLINES_H_12:           return GAL_SPECLINES_NAME_H_12;
+    case GAL_SPECLINES_Fe_VII_3758:    return GAL_SPECLINES_NAME_Fe_VII_3758;
+    case GAL_SPECLINES_H_11:           return GAL_SPECLINES_NAME_H_11;
+    case GAL_SPECLINES_H_10:           return GAL_SPECLINES_NAME_H_10;
+    case GAL_SPECLINES_H_9:            return GAL_SPECLINES_NAME_H_9;
+    case GAL_SPECLINES_Fe_V_3839:      return GAL_SPECLINES_NAME_Fe_V_3839;
+    case GAL_SPECLINES_Ne_III_3868:    return GAL_SPECLINES_NAME_Ne_III_3868;
+    case GAL_SPECLINES_He_I_3888:      return GAL_SPECLINES_NAME_He_I_3888;
+    case GAL_SPECLINES_H_8:            return GAL_SPECLINES_NAME_H_8;
+    case GAL_SPECLINES_Fe_V_3891:      return GAL_SPECLINES_NAME_Fe_V_3891;
+    case GAL_SPECLINES_Fe_V_3911:      return GAL_SPECLINES_NAME_Fe_V_3911;
+    case GAL_SPECLINES_Ne_III_3967:    return GAL_SPECLINES_NAME_Ne_III_3967;
+    case GAL_SPECLINES_H_epsilon:      return GAL_SPECLINES_NAME_H_epsilon;
+    case GAL_SPECLINES_He_I_4026:      return GAL_SPECLINES_NAME_He_I_4026;
+    case GAL_SPECLINES_S_II_4068:      return GAL_SPECLINES_NAME_S_II_4068;
+    case GAL_SPECLINES_Fe_V_4071:      return GAL_SPECLINES_NAME_Fe_V_4071;
+    case GAL_SPECLINES_S_II_4076:      return GAL_SPECLINES_NAME_S_II_4076;
+    case GAL_SPECLINES_H_delta:        return GAL_SPECLINES_NAME_H_delta;
+    case GAL_SPECLINES_He_I_4143:      return GAL_SPECLINES_NAME_He_I_4143;
+    case GAL_SPECLINES_Fe_II_4178:     return GAL_SPECLINES_NAME_Fe_II_4178;
+    case GAL_SPECLINES_Fe_V_4180:      return GAL_SPECLINES_NAME_Fe_V_4180;
+    case GAL_SPECLINES_Fe_II_4233:     return GAL_SPECLINES_NAME_Fe_II_4233;
+    case GAL_SPECLINES_Fe_V_4227:      return GAL_SPECLINES_NAME_Fe_V_4227;
+    case GAL_SPECLINES_Fe_II_4287:     return GAL_SPECLINES_NAME_Fe_II_4287;
+    case GAL_SPECLINES_Fe_II_4304:     return GAL_SPECLINES_NAME_Fe_II_4304;
+    case GAL_SPECLINES_O_II_4317:      return GAL_SPECLINES_NAME_O_II_4317;
+    case GAL_SPECLINES_H_gamma:        return GAL_SPECLINES_NAME_H_gamma;
+    case GAL_SPECLINES_O_III_4363:     return GAL_SPECLINES_NAME_O_III_4363;
+    case GAL_SPECLINES_Ar_XIV:         return GAL_SPECLINES_NAME_Ar_XIV;
+    case GAL_SPECLINES_O_II_4414:      return GAL_SPECLINES_NAME_O_II_4414;
+    case GAL_SPECLINES_Fe_II_4416:     return GAL_SPECLINES_NAME_Fe_II_4416;
+    case GAL_SPECLINES_Fe_II_4452:     return GAL_SPECLINES_NAME_Fe_II_4452;
+    case GAL_SPECLINES_He_I_4471:      return GAL_SPECLINES_NAME_He_I_4471;
+    case GAL_SPECLINES_Fe_II_4489:     return GAL_SPECLINES_NAME_Fe_II_4489;
+    case GAL_SPECLINES_Fe_II_4491:     return GAL_SPECLINES_NAME_Fe_II_4491;
+    case GAL_SPECLINES_N_III_4510:     return GAL_SPECLINES_NAME_N_III_4510;
+    case GAL_SPECLINES_Fe_II_4522:     return GAL_SPECLINES_NAME_Fe_II_4522;
+    case GAL_SPECLINES_Fe_II_4555:     return GAL_SPECLINES_NAME_Fe_II_4555;
+    case GAL_SPECLINES_Fe_II_4582:     return GAL_SPECLINES_NAME_Fe_II_4582;
+    case GAL_SPECLINES_Fe_II_4583:     return GAL_SPECLINES_NAME_Fe_II_4583;
+    case GAL_SPECLINES_Fe_II_4629:     return GAL_SPECLINES_NAME_Fe_II_4629;
+    case GAL_SPECLINES_N_III_4634:     return GAL_SPECLINES_NAME_N_III_4634;
+    case GAL_SPECLINES_N_III_4640:     return GAL_SPECLINES_NAME_N_III_4640;
+    case GAL_SPECLINES_N_III_4641:     return GAL_SPECLINES_NAME_N_III_4641;
+    case GAL_SPECLINES_C_III_4647:     return GAL_SPECLINES_NAME_C_III_4647;
+    case GAL_SPECLINES_C_III_4650:     return GAL_SPECLINES_NAME_C_III_4650;
+    case GAL_SPECLINES_C_III_5651:     return GAL_SPECLINES_NAME_C_III_5651;
+    case GAL_SPECLINES_Fe_III_4658:    return GAL_SPECLINES_NAME_Fe_III_4658;
+    case GAL_SPECLINES_He_II_4685:     return GAL_SPECLINES_NAME_He_II_4685;
+    case GAL_SPECLINES_Ar_IV_4711:     return GAL_SPECLINES_NAME_Ar_IV_4711;
+    case GAL_SPECLINES_Ar_IV_4740:     return GAL_SPECLINES_NAME_Ar_IV_4740;
+    case GAL_SPECLINES_H_beta:         return GAL_SPECLINES_NAME_H_beta;
+    case GAL_SPECLINES_Fe_VII_4893:    return GAL_SPECLINES_NAME_Fe_VII_4893;
+    case GAL_SPECLINES_Fe_IV_4903:     return GAL_SPECLINES_NAME_Fe_IV_4903;
+    case GAL_SPECLINES_Fe_II_4923:     return GAL_SPECLINES_NAME_Fe_II_4923;
+    case GAL_SPECLINES_O_III_4958:     return GAL_SPECLINES_NAME_O_III_4958;
+    case GAL_SPECLINES_O_III_5006:     return GAL_SPECLINES_NAME_O_III_5006;
+    case GAL_SPECLINES_Fe_II_5018:     return GAL_SPECLINES_NAME_Fe_II_5018;
+    case GAL_SPECLINES_Fe_III_5084:    return GAL_SPECLINES_NAME_Fe_III_5084;
+    case GAL_SPECLINES_Fe_VI_5145:     return GAL_SPECLINES_NAME_Fe_VI_5145;
+    case GAL_SPECLINES_Fe_VII_5158:    return GAL_SPECLINES_NAME_Fe_VII_5158;
+    case GAL_SPECLINES_Fe_II_5169:     return GAL_SPECLINES_NAME_Fe_II_5169;
+    case GAL_SPECLINES_Fe_VI_5176:     return GAL_SPECLINES_NAME_Fe_VI_5176;
+    case GAL_SPECLINES_Fe_II_5197:     return GAL_SPECLINES_NAME_Fe_II_5197;
+    case GAL_SPECLINES_N_I_5200:       return GAL_SPECLINES_NAME_N_I_5200;
+    case GAL_SPECLINES_Fe_II_5234:     return GAL_SPECLINES_NAME_Fe_II_5234;
+    case GAL_SPECLINES_Fe_IV_5236:     return GAL_SPECLINES_NAME_Fe_IV_5236;
+    case GAL_SPECLINES_Fe_III_5270:    return GAL_SPECLINES_NAME_Fe_III_5270;
+    case GAL_SPECLINES_Fe_II_5276:     return GAL_SPECLINES_NAME_Fe_II_5276;
+    case GAL_SPECLINES_Fe_VII_5276:    return GAL_SPECLINES_NAME_Fe_VII_5276;
+    case GAL_SPECLINES_Fe_XIV:         return GAL_SPECLINES_NAME_Fe_XIV;
+    case GAL_SPECLINES_Ca_V:           return GAL_SPECLINES_NAME_Ca_V;
+    case GAL_SPECLINES_Fe_II_5316_6:   return GAL_SPECLINES_NAME_Fe_II_5316_6;
+    case GAL_SPECLINES_Fe_II_5316_7:   return GAL_SPECLINES_NAME_Fe_II_5316_7;
+    case GAL_SPECLINES_Fe_VI_5335:     return GAL_SPECLINES_NAME_Fe_VI_5335;
+    case GAL_SPECLINES_Fe_VI_5424:     return GAL_SPECLINES_NAME_Fe_VI_5424;
+    case GAL_SPECLINES_Cl_III_5517:    return GAL_SPECLINES_NAME_Cl_III_5517;
+    case GAL_SPECLINES_Cl_III_5537:    return GAL_SPECLINES_NAME_Cl_III_5537;
+    case GAL_SPECLINES_Fe_VI_5637:     return GAL_SPECLINES_NAME_Fe_VI_5637;
+    case GAL_SPECLINES_Fe_VI_5677:     return GAL_SPECLINES_NAME_Fe_VI_5677;
+    case GAL_SPECLINES_C_III_5697:     return GAL_SPECLINES_NAME_C_III_5697;
+    case GAL_SPECLINES_Fe_VII_5720:    return GAL_SPECLINES_NAME_Fe_VII_5720;
+    case GAL_SPECLINES_N_II_5754:      return GAL_SPECLINES_NAME_N_II_5754;
+    case GAL_SPECLINES_C_IV_5801:      return GAL_SPECLINES_NAME_C_IV_5801;
+    case GAL_SPECLINES_C_IV_5811:      return GAL_SPECLINES_NAME_C_IV_5811;
+    case GAL_SPECLINES_He_I_5875:      return GAL_SPECLINES_NAME_He_I_5875;
+    case GAL_SPECLINES_O_I_6046:       return GAL_SPECLINES_NAME_O_I_6046;
+    case GAL_SPECLINES_Fe_VII_6087:    return GAL_SPECLINES_NAME_Fe_VII_6087;
+    case GAL_SPECLINES_O_I_6300:       return GAL_SPECLINES_NAME_O_I_6300;
+    case GAL_SPECLINES_S_III_6312:     return GAL_SPECLINES_NAME_S_III_6312;
+    case GAL_SPECLINES_Si_II_6347:     return GAL_SPECLINES_NAME_Si_II_6347;
+    case GAL_SPECLINES_O_I_6363:       return GAL_SPECLINES_NAME_O_I_6363;
+    case GAL_SPECLINES_Fe_II_6369:     return GAL_SPECLINES_NAME_Fe_II_6369;
+    case GAL_SPECLINES_Fe_X:           return GAL_SPECLINES_NAME_Fe_X;
+    case GAL_SPECLINES_Fe_II_6516:     return GAL_SPECLINES_NAME_Fe_II_6516;
+    case GAL_SPECLINES_N_II_6548:      return GAL_SPECLINES_NAME_N_II_6548;
+    case GAL_SPECLINES_H_alpha:        return GAL_SPECLINES_NAME_H_alpha;
+    case GAL_SPECLINES_N_II_6583:      return GAL_SPECLINES_NAME_N_II_6583;
+    case GAL_SPECLINES_S_II_6716:      return GAL_SPECLINES_NAME_S_II_6716;
+    case GAL_SPECLINES_S_II_6730:      return GAL_SPECLINES_NAME_S_II_6730;
+    case GAL_SPECLINES_O_I_7002:       return GAL_SPECLINES_NAME_O_I_7002;
+    case GAL_SPECLINES_Ar_V:           return GAL_SPECLINES_NAME_Ar_V;
+    case GAL_SPECLINES_He_I_7065:      return GAL_SPECLINES_NAME_He_I_7065;
+    case GAL_SPECLINES_Ar_III_7135:    return GAL_SPECLINES_NAME_Ar_III_7135;
+    case GAL_SPECLINES_Fe_II_7155:     return GAL_SPECLINES_NAME_Fe_II_7155;
+    case GAL_SPECLINES_Ar_IV_7170:     return GAL_SPECLINES_NAME_Ar_IV_7170;
+    case GAL_SPECLINES_Fe_II_7172:     return GAL_SPECLINES_NAME_Fe_II_7172;
+    case GAL_SPECLINES_C_II_7236:      return GAL_SPECLINES_NAME_C_II_7236;
+    case GAL_SPECLINES_Ar_IV_7237:     return GAL_SPECLINES_NAME_Ar_IV_7237;
+    case GAL_SPECLINES_O_I_7254:       return GAL_SPECLINES_NAME_O_I_7254;
+    case GAL_SPECLINES_Ar_IV_7262:     return GAL_SPECLINES_NAME_Ar_IV_7262;
+    case GAL_SPECLINES_He_I_7281:      return GAL_SPECLINES_NAME_He_I_7281;
+    case GAL_SPECLINES_O_II_7319:      return GAL_SPECLINES_NAME_O_II_7319;
+    case GAL_SPECLINES_O_II_7330:      return GAL_SPECLINES_NAME_O_II_7330;
+    case GAL_SPECLINES_Ni_II_7377:     return GAL_SPECLINES_NAME_Ni_II_7377;
+    case GAL_SPECLINES_Ni_II_7411:     return GAL_SPECLINES_NAME_Ni_II_7411;
+    case GAL_SPECLINES_Fe_II_7452:     return GAL_SPECLINES_NAME_Fe_II_7452;
+    case GAL_SPECLINES_N_I_7468:       return GAL_SPECLINES_NAME_N_I_7468;
+    case GAL_SPECLINES_S_XII:          return GAL_SPECLINES_NAME_S_XII;
+    case GAL_SPECLINES_Ar_III_7751:    return GAL_SPECLINES_NAME_Ar_III_7751;
+    case GAL_SPECLINES_He_I_7816:      return GAL_SPECLINES_NAME_He_I_7816;
+    case GAL_SPECLINES_Ar_I_7868:      return GAL_SPECLINES_NAME_Ar_I_7868;
+    case GAL_SPECLINES_Ni_III:         return GAL_SPECLINES_NAME_Ni_III;
+    case GAL_SPECLINES_Fe_XI_7891:     return GAL_SPECLINES_NAME_Fe_XI_7891;
+    case GAL_SPECLINES_He_II_8236:     return GAL_SPECLINES_NAME_He_II_8236;
+    case GAL_SPECLINES_Pa_20:          return GAL_SPECLINES_NAME_Pa_20;
+    case GAL_SPECLINES_Pa_19:          return GAL_SPECLINES_NAME_Pa_19;
+    case GAL_SPECLINES_Pa_18:          return GAL_SPECLINES_NAME_Pa_18;
+    case GAL_SPECLINES_O_I_8446:       return GAL_SPECLINES_NAME_O_I_8446;
+    case GAL_SPECLINES_Pa_17:          return GAL_SPECLINES_NAME_Pa_17;
+    case GAL_SPECLINES_Ca_II_8498:     return GAL_SPECLINES_NAME_Ca_II_8498;
+    case GAL_SPECLINES_Pa_16:          return GAL_SPECLINES_NAME_Pa_16;
+    case GAL_SPECLINES_Ca_II_8542:     return GAL_SPECLINES_NAME_Ca_II_8542;
+    case GAL_SPECLINES_Pa_15:          return GAL_SPECLINES_NAME_Pa_15;
+    case GAL_SPECLINES_Cl_II:          return GAL_SPECLINES_NAME_Cl_II;
+    case GAL_SPECLINES_Pa_14:          return GAL_SPECLINES_NAME_Pa_14;
+    case GAL_SPECLINES_Fe_II_8616:     return GAL_SPECLINES_NAME_Fe_II_8616;
+    case GAL_SPECLINES_Ca_II_8662:     return GAL_SPECLINES_NAME_Ca_II_8662;
+    case GAL_SPECLINES_Pa_13:          return GAL_SPECLINES_NAME_Pa_13;
+    case GAL_SPECLINES_N_I_8680:       return GAL_SPECLINES_NAME_N_I_8680;
+    case GAL_SPECLINES_N_I_8703:       return GAL_SPECLINES_NAME_N_I_8703;
+    case GAL_SPECLINES_N_I_8711:       return GAL_SPECLINES_NAME_N_I_8711;
+    case GAL_SPECLINES_Pa_12:          return GAL_SPECLINES_NAME_Pa_12;
+    case GAL_SPECLINES_Pa_11:          return GAL_SPECLINES_NAME_Pa_11;
+    case GAL_SPECLINES_Fe_II_8891:     return GAL_SPECLINES_NAME_Fe_II_8891;
+    case GAL_SPECLINES_Pa_10:          return GAL_SPECLINES_NAME_Pa_10;
+    case GAL_SPECLINES_S_III_9068:     return GAL_SPECLINES_NAME_S_III_9068;
+    case GAL_SPECLINES_Pa_9:           return GAL_SPECLINES_NAME_Pa_9;
+    case GAL_SPECLINES_S_III_9531:     return GAL_SPECLINES_NAME_S_III_9531;
+    case GAL_SPECLINES_Pa_epsilon:     return GAL_SPECLINES_NAME_Pa_epsilon;
+    case GAL_SPECLINES_C_I_9824:       return GAL_SPECLINES_NAME_C_I_9824;
+    case GAL_SPECLINES_C_I_9850:       return GAL_SPECLINES_NAME_C_I_9850;
+    case GAL_SPECLINES_S_VIII:         return GAL_SPECLINES_NAME_S_VIII;
+    case GAL_SPECLINES_He_I_10027:     return GAL_SPECLINES_NAME_He_I_10027;
+    case GAL_SPECLINES_He_I_10031:     return GAL_SPECLINES_NAME_He_I_10031;
+    case GAL_SPECLINES_Pa_delta:       return GAL_SPECLINES_NAME_Pa_delta;
+    case GAL_SPECLINES_S_II_10286:     return GAL_SPECLINES_NAME_S_II_10286;
+    case GAL_SPECLINES_S_II_10320:     return GAL_SPECLINES_NAME_S_II_10320;
+    case GAL_SPECLINES_S_II_10336:     return GAL_SPECLINES_NAME_S_II_10336;
+    case GAL_SPECLINES_Fe_XIII:        return GAL_SPECLINES_NAME_Fe_XIII;
+    case GAL_SPECLINES_He_I_10830:     return GAL_SPECLINES_NAME_He_I_10830;
+    case GAL_SPECLINES_Pa_gamma:       return GAL_SPECLINES_NAME_Pa_gamma;
+
+    /* Limits */
+    case GAL_SPECLINES_LIMIT_LYMAN:    return GAL_SPECLINES_NAME_LIMIT_LYMAN;
+    case GAL_SPECLINES_LIMIT_BALMER:   return GAL_SPECLINES_NAME_LIMIT_BALMER;
+    case GAL_SPECLINES_LIMIT_PASCHEN:  return GAL_SPECLINES_NAME_LIMIT_PASCHEN;
     default: return NULL;
     }
   return NULL;
@@ -97,92 +294,486 @@ gal_speclines_line_name(int linecode)
 int
 gal_speclines_line_code(char *name)
 {
-  if( !strcmp(name, GAL_SPECLINES_NAME_SIIRED) )
-    return GAL_SPECLINES_SIIRED;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_SII) )
-    return GAL_SPECLINES_SII;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_SIIBLUE) )
-    return GAL_SPECLINES_SIIBLUE;
-  if( !strcmp(name, GAL_SPECLINES_NAME_NIIRED) )
-    return GAL_SPECLINES_NIIRED;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_NII) )
-    return GAL_SPECLINES_NII;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_HALPHA) )
-    return GAL_SPECLINES_HALPHA;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_NIIBLUE) )
-    return GAL_SPECLINES_NIIBLUE;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_OIIIRED_VIS) )
-    return GAL_SPECLINES_OIIIRED_VIS;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_OIII_VIS) )
-    return GAL_SPECLINES_OIII_VIS;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_OIIIBLUE_VIS) )
-    return GAL_SPECLINES_OIIIBLUE_VIS;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_HBETA) )
-    return GAL_SPECLINES_HBETA;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_HEII_VIS) )
-    return GAL_SPECLINES_HEII_VIS;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_HGAMMA) )
-    return GAL_SPECLINES_HGAMMA;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_HDELTA) )
-    return GAL_SPECLINES_HDELTA;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_HEPSILON) )
-    return GAL_SPECLINES_HEPSILON;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_NEIII) )
-    return GAL_SPECLINES_NEIII;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_OIIRED) )
-    return GAL_SPECLINES_OIIRED;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_OII) )
-    return GAL_SPECLINES_OII;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_OIIBLUE) )
-    return GAL_SPECLINES_OIIBLUE;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_BLIMIT) )
-    return GAL_SPECLINES_BLIMIT;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_MGIIRED) )
-    return GAL_SPECLINES_MGIIRED;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_MGII) )
-    return GAL_SPECLINES_MGII;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_MGIIBLUE) )
-    return GAL_SPECLINES_MGIIBLUE;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_CIIIRED) )
-    return GAL_SPECLINES_CIIIRED;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_CIII) )
-    return GAL_SPECLINES_CIII;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_CIIIBLUE) )
-    return GAL_SPECLINES_CIIIBLUE;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_SiIIIRED) )
-    return GAL_SPECLINES_SiIIIRED;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_SiIII) )
-    return GAL_SPECLINES_SiIII;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_SiIIIBLUE) )
-    return GAL_SPECLINES_SiIIIBLUE;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_OIIIRED_UV) )
-    return GAL_SPECLINES_OIIIRED_UV;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_OIII_UV) )
-    return GAL_SPECLINES_OIII_UV;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_OIIIBLUE_UV) )
-    return GAL_SPECLINES_OIIIBLUE_UV;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_HEII_UV) )
-    return GAL_SPECLINES_HEII_UV;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_CIVRED) )
-    return GAL_SPECLINES_CIVRED;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_CIV) )
-    return GAL_SPECLINES_CIV;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_CIVBLUE) )
-    return GAL_SPECLINES_CIVBLUE;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_NV) )
-    return GAL_SPECLINES_NV;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_LYALPHA) )
-    return GAL_SPECLINES_LYALPHA;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_LYBETA) )
-    return GAL_SPECLINES_LYBETA;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_LYGAMMA) )
-    return GAL_SPECLINES_LYGAMMA;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_LYDELTA) )
-    return GAL_SPECLINES_LYDELTA;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_LYEPSILON) )
-    return GAL_SPECLINES_LYEPSILON;
-  else if( !strcmp(name, GAL_SPECLINES_NAME_LYLIMIT) )
-    return GAL_SPECLINES_LYLIMIT;
+  if( !strcmp(name, GAL_SPECLINES_NAME_Ne_VIII_770) )
+    return GAL_SPECLINES_Ne_VIII_770;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ne_VIII_780) )
+    return GAL_SPECLINES_Ne_VIII_780;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ly_epsilon) )
+    return GAL_SPECLINES_Ly_epsilon;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ly_delta) )
+    return GAL_SPECLINES_Ly_delta;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ly_gamma) )
+    return GAL_SPECLINES_Ly_gamma;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_III_977) )
+    return GAL_SPECLINES_C_III_977;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_III_989) )
+    return GAL_SPECLINES_N_III_989;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_III_991_51) )
+    return GAL_SPECLINES_N_III_991_51;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_III_991_57) )
+    return GAL_SPECLINES_N_III_991_57;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ly_beta) )
+    return GAL_SPECLINES_Ly_beta;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_VI_1031) )
+    return GAL_SPECLINES_O_VI_1031;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_VI_1037) )
+    return GAL_SPECLINES_O_VI_1037;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_I_1066) )
+    return GAL_SPECLINES_Ar_I_1066;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ly_alpha) )
+    return GAL_SPECLINES_Ly_alpha;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_V_1238) )
+    return GAL_SPECLINES_N_V_1238;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_V_1242) )
+    return GAL_SPECLINES_N_V_1242;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Si_II_1260) )
+    return GAL_SPECLINES_Si_II_1260;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Si_II_1264) )
+    return GAL_SPECLINES_Si_II_1264;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_I_1302) )
+    return GAL_SPECLINES_O_I_1302;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_II_1334) )
+    return GAL_SPECLINES_C_II_1334;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_II_1335) )
+    return GAL_SPECLINES_C_II_1335;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Si_IV_1393) )
+    return GAL_SPECLINES_Si_IV_1393;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_IV_1397) )
+    return GAL_SPECLINES_O_IV_1397;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_IV_1399) )
+    return GAL_SPECLINES_O_IV_1399;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Si_IV_1402) )
+    return GAL_SPECLINES_Si_IV_1402;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_IV_1486) )
+    return GAL_SPECLINES_N_IV_1486;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_IV_1548) )
+    return GAL_SPECLINES_C_IV_1548;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_IV_1550) )
+    return GAL_SPECLINES_C_IV_1550;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_II_1640) )
+    return GAL_SPECLINES_He_II_1640;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_III_1660) )
+    return GAL_SPECLINES_O_III_1660;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_III_1666) )
+    return GAL_SPECLINES_O_III_1666;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_III_1746) )
+    return GAL_SPECLINES_N_III_1746;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_III_1748) )
+    return GAL_SPECLINES_N_III_1748;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Al_III_1854) )
+    return GAL_SPECLINES_Al_III_1854;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Al_III_1862) )
+    return GAL_SPECLINES_Al_III_1862;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Si_III) )
+    return GAL_SPECLINES_Si_III;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_III_1908) )
+    return GAL_SPECLINES_C_III_1908;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_II_2142) )
+    return GAL_SPECLINES_N_II_2142;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_III_2320) )
+    return GAL_SPECLINES_O_III_2320;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_II_2323) )
+    return GAL_SPECLINES_C_II_2323;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_II_2324) )
+    return GAL_SPECLINES_C_II_2324;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_XI_2648) )
+    return GAL_SPECLINES_Fe_XI_2648;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_II_2733) )
+    return GAL_SPECLINES_He_II_2733;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Mg_V_2782) )
+    return GAL_SPECLINES_Mg_V_2782;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Mg_II_2795) )
+    return GAL_SPECLINES_Mg_II_2795;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Mg_II_2802) )
+    return GAL_SPECLINES_Mg_II_2802;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_IV_2829) )
+    return GAL_SPECLINES_Fe_IV_2829;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_IV_2835) )
+    return GAL_SPECLINES_Fe_IV_2835;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_IV_2853) )
+    return GAL_SPECLINES_Ar_IV_2853;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_IV_2868) )
+    return GAL_SPECLINES_Ar_IV_2868;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Mg_V_2928) )
+    return GAL_SPECLINES_Mg_V_2928;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_2945) )
+    return GAL_SPECLINES_He_I_2945;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_III_3132) )
+    return GAL_SPECLINES_O_III_3132;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_3187) )
+    return GAL_SPECLINES_He_I_3187;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_II_3203) )
+    return GAL_SPECLINES_He_II_3203;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_III_3312) )
+    return GAL_SPECLINES_O_III_3312;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ne_V_3345) )
+    return GAL_SPECLINES_Ne_V_3345;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ne_V_3425) )
+    return GAL_SPECLINES_Ne_V_3425;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_III_3444) )
+    return GAL_SPECLINES_O_III_3444;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_I_3466_4) )
+    return GAL_SPECLINES_N_I_3466_4;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_I_3466_5) )
+    return GAL_SPECLINES_N_I_3466_5;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_3487) )
+    return GAL_SPECLINES_He_I_3487;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VII_3586) )
+    return GAL_SPECLINES_Fe_VII_3586;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VI_3662) )
+    return GAL_SPECLINES_Fe_VI_3662;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_19) )
+    return GAL_SPECLINES_H_19;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_18) )
+    return GAL_SPECLINES_H_18;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_17) )
+    return GAL_SPECLINES_H_17;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_16) )
+    return GAL_SPECLINES_H_16;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_15) )
+    return GAL_SPECLINES_H_15;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_14) )
+    return GAL_SPECLINES_H_14;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_II_3726) )
+    return GAL_SPECLINES_O_II_3726;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_II_3728) )
+    return GAL_SPECLINES_O_II_3728;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_13) )
+    return GAL_SPECLINES_H_13;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_12) )
+    return GAL_SPECLINES_H_12;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VII_3758) )
+    return GAL_SPECLINES_Fe_VII_3758;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_11) )
+    return GAL_SPECLINES_H_11;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_10) )
+    return GAL_SPECLINES_H_10;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_9) )
+    return GAL_SPECLINES_H_9;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_V_3839) )
+    return GAL_SPECLINES_Fe_V_3839;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ne_III_3868) )
+    return GAL_SPECLINES_Ne_III_3868;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_3888) )
+    return GAL_SPECLINES_He_I_3888;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_8) )
+    return GAL_SPECLINES_H_8;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_V_3891) )
+    return GAL_SPECLINES_Fe_V_3891;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_V_3911) )
+    return GAL_SPECLINES_Fe_V_3911;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ne_III_3967) )
+    return GAL_SPECLINES_Ne_III_3967;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_epsilon) )
+    return GAL_SPECLINES_H_epsilon;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_4026) )
+    return GAL_SPECLINES_He_I_4026;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_II_4068) )
+    return GAL_SPECLINES_S_II_4068;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_V_4071) )
+    return GAL_SPECLINES_Fe_V_4071;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_II_4076) )
+    return GAL_SPECLINES_S_II_4076;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_delta) )
+    return GAL_SPECLINES_H_delta;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_4143) )
+    return GAL_SPECLINES_He_I_4143;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4178) )
+    return GAL_SPECLINES_Fe_II_4178;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_V_4180) )
+    return GAL_SPECLINES_Fe_V_4180;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4233) )
+    return GAL_SPECLINES_Fe_II_4233;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_V_4227) )
+    return GAL_SPECLINES_Fe_V_4227;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4287) )
+    return GAL_SPECLINES_Fe_II_4287;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4304) )
+    return GAL_SPECLINES_Fe_II_4304;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_II_4317) )
+    return GAL_SPECLINES_O_II_4317;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_gamma) )
+    return GAL_SPECLINES_H_gamma;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_III_4363) )
+    return GAL_SPECLINES_O_III_4363;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_XIV) )
+    return GAL_SPECLINES_Ar_XIV;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_II_4414) )
+    return GAL_SPECLINES_O_II_4414;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4416) )
+    return GAL_SPECLINES_Fe_II_4416;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4452) )
+    return GAL_SPECLINES_Fe_II_4452;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_4471) )
+    return GAL_SPECLINES_He_I_4471;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4489) )
+    return GAL_SPECLINES_Fe_II_4489;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4491) )
+    return GAL_SPECLINES_Fe_II_4491;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_III_4510) )
+    return GAL_SPECLINES_N_III_4510;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4522) )
+    return GAL_SPECLINES_Fe_II_4522;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4555) )
+    return GAL_SPECLINES_Fe_II_4555;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4582) )
+    return GAL_SPECLINES_Fe_II_4582;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4583) )
+    return GAL_SPECLINES_Fe_II_4583;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4629) )
+    return GAL_SPECLINES_Fe_II_4629;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_III_4634) )
+    return GAL_SPECLINES_N_III_4634;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_III_4640) )
+    return GAL_SPECLINES_N_III_4640;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_III_4641) )
+    return GAL_SPECLINES_N_III_4641;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_III_4647) )
+    return GAL_SPECLINES_C_III_4647;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_III_4650) )
+    return GAL_SPECLINES_C_III_4650;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_III_5651) )
+    return GAL_SPECLINES_C_III_5651;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_III_4658) )
+    return GAL_SPECLINES_Fe_III_4658;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_II_4685) )
+    return GAL_SPECLINES_He_II_4685;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_IV_4711) )
+    return GAL_SPECLINES_Ar_IV_4711;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_IV_4740) )
+    return GAL_SPECLINES_Ar_IV_4740;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_beta) )
+    return GAL_SPECLINES_H_beta;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VII_4893) )
+    return GAL_SPECLINES_Fe_VII_4893;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_IV_4903) )
+    return GAL_SPECLINES_Fe_IV_4903;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_4923) )
+    return GAL_SPECLINES_Fe_II_4923;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_III_4958) )
+    return GAL_SPECLINES_O_III_4958;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_III_5006) )
+    return GAL_SPECLINES_O_III_5006;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_5018) )
+    return GAL_SPECLINES_Fe_II_5018;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_III_5084) )
+    return GAL_SPECLINES_Fe_III_5084;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VI_5145) )
+    return GAL_SPECLINES_Fe_VI_5145;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VII_5158) )
+    return GAL_SPECLINES_Fe_VII_5158;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_5169) )
+    return GAL_SPECLINES_Fe_II_5169;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VI_5176) )
+    return GAL_SPECLINES_Fe_VI_5176;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_5197) )
+    return GAL_SPECLINES_Fe_II_5197;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_I_5200) )
+    return GAL_SPECLINES_N_I_5200;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_5234) )
+    return GAL_SPECLINES_Fe_II_5234;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_IV_5236) )
+    return GAL_SPECLINES_Fe_IV_5236;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_III_5270) )
+    return GAL_SPECLINES_Fe_III_5270;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_5276) )
+    return GAL_SPECLINES_Fe_II_5276;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VII_5276) )
+    return GAL_SPECLINES_Fe_VII_5276;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_XIV) )
+    return GAL_SPECLINES_Fe_XIV;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ca_V) )
+    return GAL_SPECLINES_Ca_V;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_5316_6) )
+    return GAL_SPECLINES_Fe_II_5316_6;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_5316_7) )
+    return GAL_SPECLINES_Fe_II_5316_7;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VI_5335) )
+    return GAL_SPECLINES_Fe_VI_5335;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VI_5424) )
+    return GAL_SPECLINES_Fe_VI_5424;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Cl_III_5517) )
+    return GAL_SPECLINES_Cl_III_5517;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Cl_III_5537) )
+    return GAL_SPECLINES_Cl_III_5537;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VI_5637) )
+    return GAL_SPECLINES_Fe_VI_5637;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VI_5677) )
+    return GAL_SPECLINES_Fe_VI_5677;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_III_5697) )
+    return GAL_SPECLINES_C_III_5697;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VII_5720) )
+    return GAL_SPECLINES_Fe_VII_5720;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_II_5754) )
+    return GAL_SPECLINES_N_II_5754;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_IV_5801) )
+    return GAL_SPECLINES_C_IV_5801;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_IV_5811) )
+    return GAL_SPECLINES_C_IV_5811;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_5875) )
+    return GAL_SPECLINES_He_I_5875;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_I_6046) )
+    return GAL_SPECLINES_O_I_6046;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_VII_6087) )
+    return GAL_SPECLINES_Fe_VII_6087;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_I_6300) )
+    return GAL_SPECLINES_O_I_6300;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_III_6312) )
+    return GAL_SPECLINES_S_III_6312;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Si_II_6347) )
+    return GAL_SPECLINES_Si_II_6347;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_I_6363) )
+    return GAL_SPECLINES_O_I_6363;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_6369) )
+    return GAL_SPECLINES_Fe_II_6369;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_X) )
+    return GAL_SPECLINES_Fe_X;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_6516) )
+    return GAL_SPECLINES_Fe_II_6516;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_II_6548) )
+    return GAL_SPECLINES_N_II_6548;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_H_alpha) )
+    return GAL_SPECLINES_H_alpha;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_II_6583) )
+    return GAL_SPECLINES_N_II_6583;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_II_6716) )
+    return GAL_SPECLINES_S_II_6716;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_II_6730) )
+    return GAL_SPECLINES_S_II_6730;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_I_7002) )
+    return GAL_SPECLINES_O_I_7002;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_V) )
+    return GAL_SPECLINES_Ar_V;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_7065) )
+    return GAL_SPECLINES_He_I_7065;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_III_7135) )
+    return GAL_SPECLINES_Ar_III_7135;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_7155) )
+    return GAL_SPECLINES_Fe_II_7155;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_IV_7170) )
+    return GAL_SPECLINES_Ar_IV_7170;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_7172) )
+    return GAL_SPECLINES_Fe_II_7172;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_II_7236) )
+    return GAL_SPECLINES_C_II_7236;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_IV_7237) )
+    return GAL_SPECLINES_Ar_IV_7237;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_I_7254) )
+    return GAL_SPECLINES_O_I_7254;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_IV_7262) )
+    return GAL_SPECLINES_Ar_IV_7262;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_7281) )
+    return GAL_SPECLINES_He_I_7281;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_II_7319) )
+    return GAL_SPECLINES_O_II_7319;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_II_7330) )
+    return GAL_SPECLINES_O_II_7330;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ni_II_7377) )
+    return GAL_SPECLINES_Ni_II_7377;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ni_II_7411) )
+    return GAL_SPECLINES_Ni_II_7411;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_7452) )
+    return GAL_SPECLINES_Fe_II_7452;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_I_7468) )
+    return GAL_SPECLINES_N_I_7468;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_XII) )
+    return GAL_SPECLINES_S_XII;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_III_7751) )
+    return GAL_SPECLINES_Ar_III_7751;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_7816) )
+    return GAL_SPECLINES_He_I_7816;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ar_I_7868) )
+    return GAL_SPECLINES_Ar_I_7868;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ni_III) )
+    return GAL_SPECLINES_Ni_III;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_XI_7891) )
+    return GAL_SPECLINES_Fe_XI_7891;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_II_8236) )
+    return GAL_SPECLINES_He_II_8236;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_20) )
+    return GAL_SPECLINES_Pa_20;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_19) )
+    return GAL_SPECLINES_Pa_19;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_18) )
+    return GAL_SPECLINES_Pa_18;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_O_I_8446) )
+    return GAL_SPECLINES_O_I_8446;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_17) )
+    return GAL_SPECLINES_Pa_17;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ca_II_8498) )
+    return GAL_SPECLINES_Ca_II_8498;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_16) )
+    return GAL_SPECLINES_Pa_16;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ca_II_8542) )
+    return GAL_SPECLINES_Ca_II_8542;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_15) )
+    return GAL_SPECLINES_Pa_15;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Cl_II) )
+    return GAL_SPECLINES_Cl_II;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_14) )
+    return GAL_SPECLINES_Pa_14;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_8616) )
+    return GAL_SPECLINES_Fe_II_8616;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Ca_II_8662) )
+    return GAL_SPECLINES_Ca_II_8662;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_13) )
+    return GAL_SPECLINES_Pa_13;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_I_8680) )
+    return GAL_SPECLINES_N_I_8680;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_I_8703) )
+    return GAL_SPECLINES_N_I_8703;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_N_I_8711) )
+    return GAL_SPECLINES_N_I_8711;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_12) )
+    return GAL_SPECLINES_Pa_12;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_11) )
+    return GAL_SPECLINES_Pa_11;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_II_8891) )
+    return GAL_SPECLINES_Fe_II_8891;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_10) )
+    return GAL_SPECLINES_Pa_10;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_III_9068) )
+    return GAL_SPECLINES_S_III_9068;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_9) )
+    return GAL_SPECLINES_Pa_9;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_III_9531) )
+    return GAL_SPECLINES_S_III_9531;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_epsilon) )
+    return GAL_SPECLINES_Pa_epsilon;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_I_9824) )
+    return GAL_SPECLINES_C_I_9824;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_C_I_9850) )
+    return GAL_SPECLINES_C_I_9850;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_VIII) )
+    return GAL_SPECLINES_S_VIII;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_10027) )
+    return GAL_SPECLINES_He_I_10027;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_10031) )
+    return GAL_SPECLINES_He_I_10031;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_delta) )
+    return GAL_SPECLINES_Pa_delta;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_II_10286) )
+    return GAL_SPECLINES_S_II_10286;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_II_10320) )
+    return GAL_SPECLINES_S_II_10320;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_S_II_10336) )
+    return GAL_SPECLINES_S_II_10336;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Fe_XIII) )
+    return GAL_SPECLINES_Fe_XIII;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_He_I_10830) )
+    return GAL_SPECLINES_He_I_10830;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_Pa_gamma) )
+    return GAL_SPECLINES_Pa_gamma;
+
+  /* Limits */
+  else if( !strcmp(name, GAL_SPECLINES_NAME_LIMIT_LYMAN) )
+    return GAL_SPECLINES_LIMIT_LYMAN;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_LIMIT_BALMER) )
+    return GAL_SPECLINES_LIMIT_BALMER;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_LIMIT_PASCHEN) )
+    return GAL_SPECLINES_LIMIT_PASCHEN;
+
+  /* Invalid. */
   else return GAL_SPECLINES_INVALID;
   return GAL_SPECLINES_INVALID;
 }
@@ -197,49 +788,247 @@ gal_speclines_line_angstrom(int linecode)
 {
   switch(linecode)
     {
-    case GAL_SPECLINES_SIIRED:        return GAL_SPECLINES_ANGSTROM_SIIRED;
-    case GAL_SPECLINES_SII:           return GAL_SPECLINES_ANGSTROM_SII;
-    case GAL_SPECLINES_SIIBLUE:       return GAL_SPECLINES_ANGSTROM_SIIBLUE;
-    case GAL_SPECLINES_NIIRED:        return GAL_SPECLINES_ANGSTROM_NIIRED;
-    case GAL_SPECLINES_NII:           return GAL_SPECLINES_ANGSTROM_NII;
-    case GAL_SPECLINES_HALPHA:        return GAL_SPECLINES_ANGSTROM_HALPHA;
-    case GAL_SPECLINES_NIIBLUE:       return GAL_SPECLINES_ANGSTROM_NIIBLUE;
-    case GAL_SPECLINES_OIIIRED_VIS:   return 
GAL_SPECLINES_ANGSTROM_OIIIRED_VIS;
-    case GAL_SPECLINES_OIII_VIS:      return GAL_SPECLINES_ANGSTROM_OIII_VIS;
-    case GAL_SPECLINES_OIIIBLUE_VIS:  return 
GAL_SPECLINES_ANGSTROM_OIIIBLUE_VIS;
-    case GAL_SPECLINES_HBETA:         return GAL_SPECLINES_ANGSTROM_HBETA;
-    case GAL_SPECLINES_HEII_VIS:      return GAL_SPECLINES_ANGSTROM_HEII_VIS;
-    case GAL_SPECLINES_HGAMMA:        return GAL_SPECLINES_ANGSTROM_HGAMMA;
-    case GAL_SPECLINES_HDELTA:        return GAL_SPECLINES_ANGSTROM_HDELTA;
-    case GAL_SPECLINES_HEPSILON:      return GAL_SPECLINES_ANGSTROM_HEPSILON;
-    case GAL_SPECLINES_NEIII:         return GAL_SPECLINES_ANGSTROM_NEIII;
-    case GAL_SPECLINES_OIIRED:        return GAL_SPECLINES_ANGSTROM_OIIRED;
-    case GAL_SPECLINES_OII:           return GAL_SPECLINES_ANGSTROM_OII;
-    case GAL_SPECLINES_OIIBLUE:       return GAL_SPECLINES_ANGSTROM_OIIBLUE;
-    case GAL_SPECLINES_BLIMIT:        return GAL_SPECLINES_ANGSTROM_BLIMIT;
-    case GAL_SPECLINES_MGIIRED:       return GAL_SPECLINES_ANGSTROM_MGIIRED;
-    case GAL_SPECLINES_MGII:          return GAL_SPECLINES_ANGSTROM_MGII;
-    case GAL_SPECLINES_MGIIBLUE:      return GAL_SPECLINES_ANGSTROM_MGIIBLUE;
-    case GAL_SPECLINES_CIIIRED:       return GAL_SPECLINES_ANGSTROM_CIIIRED;
-    case GAL_SPECLINES_CIII:          return GAL_SPECLINES_ANGSTROM_CIII;
-    case GAL_SPECLINES_CIIIBLUE:      return GAL_SPECLINES_ANGSTROM_CIIIBLUE;
-    case GAL_SPECLINES_SiIIIRED:      return GAL_SPECLINES_ANGSTROM_SiIIIRED;
-    case GAL_SPECLINES_SiIII:         return GAL_SPECLINES_ANGSTROM_SiIII;
-    case GAL_SPECLINES_SiIIIBLUE:     return GAL_SPECLINES_ANGSTROM_SiIIIBLUE;
-    case GAL_SPECLINES_OIIIRED_UV:    return GAL_SPECLINES_ANGSTROM_OIIIRED_UV;
-    case GAL_SPECLINES_OIII_UV:       return GAL_SPECLINES_ANGSTROM_OIII_UV;
-    case GAL_SPECLINES_OIIIBLUE_UV:   return 
GAL_SPECLINES_ANGSTROM_OIIIBLUE_UV;
-    case GAL_SPECLINES_HEII_UV:       return GAL_SPECLINES_ANGSTROM_HEII_UV;
-    case GAL_SPECLINES_CIVRED:        return GAL_SPECLINES_ANGSTROM_CIVRED;
-    case GAL_SPECLINES_CIV:           return GAL_SPECLINES_ANGSTROM_CIV;
-    case GAL_SPECLINES_CIVBLUE:       return GAL_SPECLINES_ANGSTROM_CIVBLUE;
-    case GAL_SPECLINES_NV:            return GAL_SPECLINES_ANGSTROM_NV;
-    case GAL_SPECLINES_LYALPHA:       return GAL_SPECLINES_ANGSTROM_LYALPHA;
-    case GAL_SPECLINES_LYBETA:        return GAL_SPECLINES_ANGSTROM_LYBETA;
-    case GAL_SPECLINES_LYGAMMA:       return GAL_SPECLINES_ANGSTROM_LYGAMMA;
-    case GAL_SPECLINES_LYDELTA:       return GAL_SPECLINES_ANGSTROM_LYDELTA;
-    case GAL_SPECLINES_LYEPSILON:     return GAL_SPECLINES_ANGSTROM_LYEPSILON;
-    case GAL_SPECLINES_LYLIMIT:       return GAL_SPECLINES_ANGSTROM_LYLIMIT;
+    case GAL_SPECLINES_Ne_VIII_770:    return 
GAL_SPECLINES_ANGSTROM_Ne_VIII_770;
+    case GAL_SPECLINES_Ne_VIII_780:    return 
GAL_SPECLINES_ANGSTROM_Ne_VIII_780;
+    case GAL_SPECLINES_Ly_epsilon:     return 
GAL_SPECLINES_ANGSTROM_Ly_epsilon;
+    case GAL_SPECLINES_Ly_delta:       return GAL_SPECLINES_ANGSTROM_Ly_delta;
+    case GAL_SPECLINES_Ly_gamma:       return GAL_SPECLINES_ANGSTROM_Ly_gamma;
+    case GAL_SPECLINES_C_III_977:      return GAL_SPECLINES_ANGSTROM_C_III_977;
+    case GAL_SPECLINES_N_III_989:      return GAL_SPECLINES_ANGSTROM_N_III_989;
+    case GAL_SPECLINES_N_III_991_51:   return 
GAL_SPECLINES_ANGSTROM_N_III_991_51;
+    case GAL_SPECLINES_N_III_991_57:   return 
GAL_SPECLINES_ANGSTROM_N_III_991_57;
+    case GAL_SPECLINES_Ly_beta:        return GAL_SPECLINES_ANGSTROM_Ly_beta;
+    case GAL_SPECLINES_O_VI_1031:      return GAL_SPECLINES_ANGSTROM_O_VI_1031;
+    case GAL_SPECLINES_O_VI_1037:      return GAL_SPECLINES_ANGSTROM_O_VI_1037;
+    case GAL_SPECLINES_Ar_I_1066:      return GAL_SPECLINES_ANGSTROM_Ar_I_1066;
+    case GAL_SPECLINES_Ly_alpha:       return GAL_SPECLINES_ANGSTROM_Ly_alpha;
+    case GAL_SPECLINES_N_V_1238:       return GAL_SPECLINES_ANGSTROM_N_V_1238;
+    case GAL_SPECLINES_N_V_1242:       return GAL_SPECLINES_ANGSTROM_N_V_1242;
+    case GAL_SPECLINES_Si_II_1260:     return 
GAL_SPECLINES_ANGSTROM_Si_II_1260;
+    case GAL_SPECLINES_Si_II_1264:     return 
GAL_SPECLINES_ANGSTROM_Si_II_1264;
+    case GAL_SPECLINES_O_I_1302:       return GAL_SPECLINES_ANGSTROM_O_I_1302;
+    case GAL_SPECLINES_C_II_1334:      return GAL_SPECLINES_ANGSTROM_C_II_1334;
+    case GAL_SPECLINES_C_II_1335:      return GAL_SPECLINES_ANGSTROM_C_II_1335;
+    case GAL_SPECLINES_Si_IV_1393:     return 
GAL_SPECLINES_ANGSTROM_Si_IV_1393;
+    case GAL_SPECLINES_O_IV_1397:      return GAL_SPECLINES_ANGSTROM_O_IV_1397;
+    case GAL_SPECLINES_O_IV_1399:      return GAL_SPECLINES_ANGSTROM_O_IV_1399;
+    case GAL_SPECLINES_Si_IV_1402:     return 
GAL_SPECLINES_ANGSTROM_Si_IV_1402;
+    case GAL_SPECLINES_N_IV_1486:      return GAL_SPECLINES_ANGSTROM_N_IV_1486;
+    case GAL_SPECLINES_C_IV_1548:      return GAL_SPECLINES_ANGSTROM_C_IV_1548;
+    case GAL_SPECLINES_C_IV_1550:      return GAL_SPECLINES_ANGSTROM_C_IV_1550;
+    case GAL_SPECLINES_He_II_1640:     return 
GAL_SPECLINES_ANGSTROM_He_II_1640;
+    case GAL_SPECLINES_O_III_1660:     return 
GAL_SPECLINES_ANGSTROM_O_III_1660;
+    case GAL_SPECLINES_O_III_1666:     return 
GAL_SPECLINES_ANGSTROM_O_III_1666;
+    case GAL_SPECLINES_N_III_1746:     return 
GAL_SPECLINES_ANGSTROM_N_III_1746;
+    case GAL_SPECLINES_N_III_1748:     return 
GAL_SPECLINES_ANGSTROM_N_III_1748;
+    case GAL_SPECLINES_Al_III_1854:    return 
GAL_SPECLINES_ANGSTROM_Al_III_1854;
+    case GAL_SPECLINES_Al_III_1862:    return 
GAL_SPECLINES_ANGSTROM_Al_III_1862;
+    case GAL_SPECLINES_Si_III:         return GAL_SPECLINES_ANGSTROM_Si_III;
+    case GAL_SPECLINES_C_III_1908:     return 
GAL_SPECLINES_ANGSTROM_C_III_1908;
+    case GAL_SPECLINES_N_II_2142:      return GAL_SPECLINES_ANGSTROM_N_II_2142;
+    case GAL_SPECLINES_O_III_2320:     return 
GAL_SPECLINES_ANGSTROM_O_III_2320;
+    case GAL_SPECLINES_C_II_2323:      return GAL_SPECLINES_ANGSTROM_C_II_2323;
+    case GAL_SPECLINES_C_II_2324:      return GAL_SPECLINES_ANGSTROM_C_II_2324;
+    case GAL_SPECLINES_Fe_XI_2648:     return 
GAL_SPECLINES_ANGSTROM_Fe_XI_2648;
+    case GAL_SPECLINES_He_II_2733:     return 
GAL_SPECLINES_ANGSTROM_He_II_2733;
+    case GAL_SPECLINES_Mg_V_2782:      return GAL_SPECLINES_ANGSTROM_Mg_V_2782;
+    case GAL_SPECLINES_Mg_II_2795:     return 
GAL_SPECLINES_ANGSTROM_Mg_II_2795;
+    case GAL_SPECLINES_Mg_II_2802:     return 
GAL_SPECLINES_ANGSTROM_Mg_II_2802;
+    case GAL_SPECLINES_Fe_IV_2829:     return 
GAL_SPECLINES_ANGSTROM_Fe_IV_2829;
+    case GAL_SPECLINES_Fe_IV_2835:     return 
GAL_SPECLINES_ANGSTROM_Fe_IV_2835;
+    case GAL_SPECLINES_Ar_IV_2853:     return 
GAL_SPECLINES_ANGSTROM_Ar_IV_2853;
+    case GAL_SPECLINES_Ar_IV_2868:     return 
GAL_SPECLINES_ANGSTROM_Ar_IV_2868;
+    case GAL_SPECLINES_Mg_V_2928:      return GAL_SPECLINES_ANGSTROM_Mg_V_2928;
+    case GAL_SPECLINES_He_I_2945:      return GAL_SPECLINES_ANGSTROM_He_I_2945;
+    case GAL_SPECLINES_O_III_3132:     return 
GAL_SPECLINES_ANGSTROM_O_III_3132;
+    case GAL_SPECLINES_He_I_3187:      return GAL_SPECLINES_ANGSTROM_He_I_3187;
+    case GAL_SPECLINES_He_II_3203:     return 
GAL_SPECLINES_ANGSTROM_He_II_3203;
+    case GAL_SPECLINES_O_III_3312:     return 
GAL_SPECLINES_ANGSTROM_O_III_3312;
+    case GAL_SPECLINES_Ne_V_3345:      return GAL_SPECLINES_ANGSTROM_Ne_V_3345;
+    case GAL_SPECLINES_Ne_V_3425:      return GAL_SPECLINES_ANGSTROM_Ne_V_3425;
+    case GAL_SPECLINES_O_III_3444:     return 
GAL_SPECLINES_ANGSTROM_O_III_3444;
+    case GAL_SPECLINES_N_I_3466_4:     return 
GAL_SPECLINES_ANGSTROM_N_I_3466_4;
+    case GAL_SPECLINES_N_I_3466_5:     return 
GAL_SPECLINES_ANGSTROM_N_I_3466_5;
+    case GAL_SPECLINES_He_I_3487:      return GAL_SPECLINES_ANGSTROM_He_I_3487;
+    case GAL_SPECLINES_Fe_VII_3586:    return 
GAL_SPECLINES_ANGSTROM_Fe_VII_3586;
+    case GAL_SPECLINES_Fe_VI_3662:     return 
GAL_SPECLINES_ANGSTROM_Fe_VI_3662;
+    case GAL_SPECLINES_H_19:           return GAL_SPECLINES_ANGSTROM_H_19;
+    case GAL_SPECLINES_H_18:           return GAL_SPECLINES_ANGSTROM_H_18;
+    case GAL_SPECLINES_H_17:           return GAL_SPECLINES_ANGSTROM_H_17;
+    case GAL_SPECLINES_H_16:           return GAL_SPECLINES_ANGSTROM_H_16;
+    case GAL_SPECLINES_H_15:           return GAL_SPECLINES_ANGSTROM_H_15;
+    case GAL_SPECLINES_H_14:           return GAL_SPECLINES_ANGSTROM_H_14;
+    case GAL_SPECLINES_O_II_3726:      return GAL_SPECLINES_ANGSTROM_O_II_3726;
+    case GAL_SPECLINES_O_II_3728:      return GAL_SPECLINES_ANGSTROM_O_II_3728;
+    case GAL_SPECLINES_H_13:           return GAL_SPECLINES_ANGSTROM_H_13;
+    case GAL_SPECLINES_H_12:           return GAL_SPECLINES_ANGSTROM_H_12;
+    case GAL_SPECLINES_Fe_VII_3758:    return 
GAL_SPECLINES_ANGSTROM_Fe_VII_3758;
+    case GAL_SPECLINES_H_11:           return GAL_SPECLINES_ANGSTROM_H_11;
+    case GAL_SPECLINES_H_10:           return GAL_SPECLINES_ANGSTROM_H_10;
+    case GAL_SPECLINES_H_9:            return GAL_SPECLINES_ANGSTROM_H_9;
+    case GAL_SPECLINES_Fe_V_3839:      return GAL_SPECLINES_ANGSTROM_Fe_V_3839;
+    case GAL_SPECLINES_Ne_III_3868:    return 
GAL_SPECLINES_ANGSTROM_Ne_III_3868;
+    case GAL_SPECLINES_He_I_3888:      return GAL_SPECLINES_ANGSTROM_He_I_3888;
+    case GAL_SPECLINES_H_8:            return GAL_SPECLINES_ANGSTROM_H_8;
+    case GAL_SPECLINES_Fe_V_3891:      return GAL_SPECLINES_ANGSTROM_Fe_V_3891;
+    case GAL_SPECLINES_Fe_V_3911:      return GAL_SPECLINES_ANGSTROM_Fe_V_3911;
+    case GAL_SPECLINES_Ne_III_3967:    return 
GAL_SPECLINES_ANGSTROM_Ne_III_3967;
+    case GAL_SPECLINES_H_epsilon:      return GAL_SPECLINES_ANGSTROM_H_epsilon;
+    case GAL_SPECLINES_He_I_4026:      return GAL_SPECLINES_ANGSTROM_He_I_4026;
+    case GAL_SPECLINES_S_II_4068:      return GAL_SPECLINES_ANGSTROM_S_II_4068;
+    case GAL_SPECLINES_Fe_V_4071:      return GAL_SPECLINES_ANGSTROM_Fe_V_4071;
+    case GAL_SPECLINES_S_II_4076:      return GAL_SPECLINES_ANGSTROM_S_II_4076;
+    case GAL_SPECLINES_H_delta:        return GAL_SPECLINES_ANGSTROM_H_delta;
+    case GAL_SPECLINES_He_I_4143:      return GAL_SPECLINES_ANGSTROM_He_I_4143;
+    case GAL_SPECLINES_Fe_II_4178:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4178;
+    case GAL_SPECLINES_Fe_V_4180:      return GAL_SPECLINES_ANGSTROM_Fe_V_4180;
+    case GAL_SPECLINES_Fe_II_4233:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4233;
+    case GAL_SPECLINES_Fe_V_4227:      return GAL_SPECLINES_ANGSTROM_Fe_V_4227;
+    case GAL_SPECLINES_Fe_II_4287:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4287;
+    case GAL_SPECLINES_Fe_II_4304:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4304;
+    case GAL_SPECLINES_O_II_4317:      return GAL_SPECLINES_ANGSTROM_O_II_4317;
+    case GAL_SPECLINES_H_gamma:        return GAL_SPECLINES_ANGSTROM_H_gamma;
+    case GAL_SPECLINES_O_III_4363:     return 
GAL_SPECLINES_ANGSTROM_O_III_4363;
+    case GAL_SPECLINES_Ar_XIV:         return GAL_SPECLINES_ANGSTROM_Ar_XIV;
+    case GAL_SPECLINES_O_II_4414:      return GAL_SPECLINES_ANGSTROM_O_II_4414;
+    case GAL_SPECLINES_Fe_II_4416:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4416;
+    case GAL_SPECLINES_Fe_II_4452:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4452;
+    case GAL_SPECLINES_He_I_4471:      return GAL_SPECLINES_ANGSTROM_He_I_4471;
+    case GAL_SPECLINES_Fe_II_4489:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4489;
+    case GAL_SPECLINES_Fe_II_4491:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4491;
+    case GAL_SPECLINES_N_III_4510:     return 
GAL_SPECLINES_ANGSTROM_N_III_4510;
+    case GAL_SPECLINES_Fe_II_4522:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4522;
+    case GAL_SPECLINES_Fe_II_4555:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4555;
+    case GAL_SPECLINES_Fe_II_4582:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4582;
+    case GAL_SPECLINES_Fe_II_4583:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4583;
+    case GAL_SPECLINES_Fe_II_4629:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4629;
+    case GAL_SPECLINES_N_III_4634:     return 
GAL_SPECLINES_ANGSTROM_N_III_4634;
+    case GAL_SPECLINES_N_III_4640:     return 
GAL_SPECLINES_ANGSTROM_N_III_4640;
+    case GAL_SPECLINES_N_III_4641:     return 
GAL_SPECLINES_ANGSTROM_N_III_4641;
+    case GAL_SPECLINES_C_III_4647:     return 
GAL_SPECLINES_ANGSTROM_C_III_4647;
+    case GAL_SPECLINES_C_III_4650:     return 
GAL_SPECLINES_ANGSTROM_C_III_4650;
+    case GAL_SPECLINES_C_III_5651:     return 
GAL_SPECLINES_ANGSTROM_C_III_5651;
+    case GAL_SPECLINES_Fe_III_4658:    return 
GAL_SPECLINES_ANGSTROM_Fe_III_4658;
+    case GAL_SPECLINES_He_II_4685:     return 
GAL_SPECLINES_ANGSTROM_He_II_4685;
+    case GAL_SPECLINES_Ar_IV_4711:     return 
GAL_SPECLINES_ANGSTROM_Ar_IV_4711;
+    case GAL_SPECLINES_Ar_IV_4740:     return 
GAL_SPECLINES_ANGSTROM_Ar_IV_4740;
+    case GAL_SPECLINES_H_beta:         return GAL_SPECLINES_ANGSTROM_H_beta;
+    case GAL_SPECLINES_Fe_VII_4893:    return 
GAL_SPECLINES_ANGSTROM_Fe_VII_4893;
+    case GAL_SPECLINES_Fe_IV_4903:     return 
GAL_SPECLINES_ANGSTROM_Fe_IV_4903;
+    case GAL_SPECLINES_Fe_II_4923:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_4923;
+    case GAL_SPECLINES_O_III_4958:     return 
GAL_SPECLINES_ANGSTROM_O_III_4958;
+    case GAL_SPECLINES_O_III_5006:     return 
GAL_SPECLINES_ANGSTROM_O_III_5006;
+    case GAL_SPECLINES_Fe_II_5018:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_5018;
+    case GAL_SPECLINES_Fe_III_5084:    return 
GAL_SPECLINES_ANGSTROM_Fe_III_5084;
+    case GAL_SPECLINES_Fe_VI_5145:     return 
GAL_SPECLINES_ANGSTROM_Fe_VI_5145;
+    case GAL_SPECLINES_Fe_VII_5158:    return 
GAL_SPECLINES_ANGSTROM_Fe_VII_5158;
+    case GAL_SPECLINES_Fe_II_5169:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_5169;
+    case GAL_SPECLINES_Fe_VI_5176:     return 
GAL_SPECLINES_ANGSTROM_Fe_VI_5176;
+    case GAL_SPECLINES_Fe_II_5197:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_5197;
+    case GAL_SPECLINES_N_I_5200:       return GAL_SPECLINES_ANGSTROM_N_I_5200;
+    case GAL_SPECLINES_Fe_II_5234:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_5234;
+    case GAL_SPECLINES_Fe_IV_5236:     return 
GAL_SPECLINES_ANGSTROM_Fe_IV_5236;
+    case GAL_SPECLINES_Fe_III_5270:    return 
GAL_SPECLINES_ANGSTROM_Fe_III_5270;
+    case GAL_SPECLINES_Fe_II_5276:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_5276;
+    case GAL_SPECLINES_Fe_VII_5276:    return 
GAL_SPECLINES_ANGSTROM_Fe_VII_5276;
+    case GAL_SPECLINES_Fe_XIV:         return GAL_SPECLINES_ANGSTROM_Fe_XIV;
+    case GAL_SPECLINES_Ca_V:           return GAL_SPECLINES_ANGSTROM_Ca_V;
+    case GAL_SPECLINES_Fe_II_5316_6:   return 
GAL_SPECLINES_ANGSTROM_Fe_II_5316_6;
+    case GAL_SPECLINES_Fe_II_5316_7:   return 
GAL_SPECLINES_ANGSTROM_Fe_II_5316_7;
+    case GAL_SPECLINES_Fe_VI_5335:     return 
GAL_SPECLINES_ANGSTROM_Fe_VI_5335;
+    case GAL_SPECLINES_Fe_VI_5424:     return 
GAL_SPECLINES_ANGSTROM_Fe_VI_5424;
+    case GAL_SPECLINES_Cl_III_5517:    return 
GAL_SPECLINES_ANGSTROM_Cl_III_5517;
+    case GAL_SPECLINES_Cl_III_5537:    return 
GAL_SPECLINES_ANGSTROM_Cl_III_5537;
+    case GAL_SPECLINES_Fe_VI_5637:     return 
GAL_SPECLINES_ANGSTROM_Fe_VI_5637;
+    case GAL_SPECLINES_Fe_VI_5677:     return 
GAL_SPECLINES_ANGSTROM_Fe_VI_5677;
+    case GAL_SPECLINES_C_III_5697:     return 
GAL_SPECLINES_ANGSTROM_C_III_5697;
+    case GAL_SPECLINES_Fe_VII_5720:    return 
GAL_SPECLINES_ANGSTROM_Fe_VII_5720;
+    case GAL_SPECLINES_N_II_5754:      return GAL_SPECLINES_ANGSTROM_N_II_5754;
+    case GAL_SPECLINES_C_IV_5801:      return GAL_SPECLINES_ANGSTROM_C_IV_5801;
+    case GAL_SPECLINES_C_IV_5811:      return GAL_SPECLINES_ANGSTROM_C_IV_5811;
+    case GAL_SPECLINES_He_I_5875:      return GAL_SPECLINES_ANGSTROM_He_I_5875;
+    case GAL_SPECLINES_O_I_6046:       return GAL_SPECLINES_ANGSTROM_O_I_6046;
+    case GAL_SPECLINES_Fe_VII_6087:    return 
GAL_SPECLINES_ANGSTROM_Fe_VII_6087;
+    case GAL_SPECLINES_O_I_6300:       return GAL_SPECLINES_ANGSTROM_O_I_6300;
+    case GAL_SPECLINES_S_III_6312:     return 
GAL_SPECLINES_ANGSTROM_S_III_6312;
+    case GAL_SPECLINES_Si_II_6347:     return 
GAL_SPECLINES_ANGSTROM_Si_II_6347;
+    case GAL_SPECLINES_O_I_6363:       return GAL_SPECLINES_ANGSTROM_O_I_6363;
+    case GAL_SPECLINES_Fe_II_6369:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_6369;
+    case GAL_SPECLINES_Fe_X:           return GAL_SPECLINES_ANGSTROM_Fe_X;
+    case GAL_SPECLINES_Fe_II_6516:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_6516;
+    case GAL_SPECLINES_N_II_6548:      return GAL_SPECLINES_ANGSTROM_N_II_6548;
+    case GAL_SPECLINES_H_alpha:        return GAL_SPECLINES_ANGSTROM_H_alpha;
+    case GAL_SPECLINES_N_II_6583:      return GAL_SPECLINES_ANGSTROM_N_II_6583;
+    case GAL_SPECLINES_S_II_6716:      return GAL_SPECLINES_ANGSTROM_S_II_6716;
+    case GAL_SPECLINES_S_II_6730:      return GAL_SPECLINES_ANGSTROM_S_II_6730;
+    case GAL_SPECLINES_O_I_7002:       return GAL_SPECLINES_ANGSTROM_O_I_7002;
+    case GAL_SPECLINES_Ar_V:           return GAL_SPECLINES_ANGSTROM_Ar_V;
+    case GAL_SPECLINES_He_I_7065:      return GAL_SPECLINES_ANGSTROM_He_I_7065;
+    case GAL_SPECLINES_Ar_III_7135:    return 
GAL_SPECLINES_ANGSTROM_Ar_III_7135;
+    case GAL_SPECLINES_Fe_II_7155:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_7155;
+    case GAL_SPECLINES_Ar_IV_7170:     return 
GAL_SPECLINES_ANGSTROM_Ar_IV_7170;
+    case GAL_SPECLINES_Fe_II_7172:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_7172;
+    case GAL_SPECLINES_C_II_7236:      return GAL_SPECLINES_ANGSTROM_C_II_7236;
+    case GAL_SPECLINES_Ar_IV_7237:     return 
GAL_SPECLINES_ANGSTROM_Ar_IV_7237;
+    case GAL_SPECLINES_O_I_7254:       return GAL_SPECLINES_ANGSTROM_O_I_7254;
+    case GAL_SPECLINES_Ar_IV_7262:     return 
GAL_SPECLINES_ANGSTROM_Ar_IV_7262;
+    case GAL_SPECLINES_He_I_7281:      return GAL_SPECLINES_ANGSTROM_He_I_7281;
+    case GAL_SPECLINES_O_II_7319:      return GAL_SPECLINES_ANGSTROM_O_II_7319;
+    case GAL_SPECLINES_O_II_7330:      return GAL_SPECLINES_ANGSTROM_O_II_7330;
+    case GAL_SPECLINES_Ni_II_7377:     return 
GAL_SPECLINES_ANGSTROM_Ni_II_7377;
+    case GAL_SPECLINES_Ni_II_7411:     return 
GAL_SPECLINES_ANGSTROM_Ni_II_7411;
+    case GAL_SPECLINES_Fe_II_7452:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_7452;
+    case GAL_SPECLINES_N_I_7468:       return GAL_SPECLINES_ANGSTROM_N_I_7468;
+    case GAL_SPECLINES_S_XII:          return GAL_SPECLINES_ANGSTROM_S_XII;
+    case GAL_SPECLINES_Ar_III_7751:    return 
GAL_SPECLINES_ANGSTROM_Ar_III_7751;
+    case GAL_SPECLINES_He_I_7816:      return GAL_SPECLINES_ANGSTROM_He_I_7816;
+    case GAL_SPECLINES_Ar_I_7868:      return GAL_SPECLINES_ANGSTROM_Ar_I_7868;
+    case GAL_SPECLINES_Ni_III:         return GAL_SPECLINES_ANGSTROM_Ni_III;
+    case GAL_SPECLINES_Fe_XI_7891:     return 
GAL_SPECLINES_ANGSTROM_Fe_XI_7891;
+    case GAL_SPECLINES_He_II_8236:     return 
GAL_SPECLINES_ANGSTROM_He_II_8236;
+    case GAL_SPECLINES_Pa_20:          return GAL_SPECLINES_ANGSTROM_Pa_20;
+    case GAL_SPECLINES_Pa_19:          return GAL_SPECLINES_ANGSTROM_Pa_19;
+    case GAL_SPECLINES_Pa_18:          return GAL_SPECLINES_ANGSTROM_Pa_18;
+    case GAL_SPECLINES_O_I_8446:       return GAL_SPECLINES_ANGSTROM_O_I_8446;
+    case GAL_SPECLINES_Pa_17:          return GAL_SPECLINES_ANGSTROM_Pa_17;
+    case GAL_SPECLINES_Ca_II_8498:     return 
GAL_SPECLINES_ANGSTROM_Ca_II_8498;
+    case GAL_SPECLINES_Pa_16:          return GAL_SPECLINES_ANGSTROM_Pa_16;
+    case GAL_SPECLINES_Ca_II_8542:     return 
GAL_SPECLINES_ANGSTROM_Ca_II_8542;
+    case GAL_SPECLINES_Pa_15:          return GAL_SPECLINES_ANGSTROM_Pa_15;
+    case GAL_SPECLINES_Cl_II:          return GAL_SPECLINES_ANGSTROM_Cl_II;
+    case GAL_SPECLINES_Pa_14:          return GAL_SPECLINES_ANGSTROM_Pa_14;
+    case GAL_SPECLINES_Fe_II_8616:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_8616;
+    case GAL_SPECLINES_Ca_II_8662:     return 
GAL_SPECLINES_ANGSTROM_Ca_II_8662;
+    case GAL_SPECLINES_Pa_13:          return GAL_SPECLINES_ANGSTROM_Pa_13;
+    case GAL_SPECLINES_N_I_8680:       return GAL_SPECLINES_ANGSTROM_N_I_8680;
+    case GAL_SPECLINES_N_I_8703:       return GAL_SPECLINES_ANGSTROM_N_I_8703;
+    case GAL_SPECLINES_N_I_8711:       return GAL_SPECLINES_ANGSTROM_N_I_8711;
+    case GAL_SPECLINES_Pa_12:          return GAL_SPECLINES_ANGSTROM_Pa_12;
+    case GAL_SPECLINES_Pa_11:          return GAL_SPECLINES_ANGSTROM_Pa_11;
+    case GAL_SPECLINES_Fe_II_8891:     return 
GAL_SPECLINES_ANGSTROM_Fe_II_8891;
+    case GAL_SPECLINES_Pa_10:          return GAL_SPECLINES_ANGSTROM_Pa_10;
+    case GAL_SPECLINES_S_III_9068:     return 
GAL_SPECLINES_ANGSTROM_S_III_9068;
+    case GAL_SPECLINES_Pa_9:           return GAL_SPECLINES_ANGSTROM_Pa_9;
+    case GAL_SPECLINES_S_III_9531:     return 
GAL_SPECLINES_ANGSTROM_S_III_9531;
+    case GAL_SPECLINES_Pa_epsilon:     return 
GAL_SPECLINES_ANGSTROM_Pa_epsilon;
+    case GAL_SPECLINES_C_I_9824:       return GAL_SPECLINES_ANGSTROM_C_I_9824;
+    case GAL_SPECLINES_C_I_9850:       return GAL_SPECLINES_ANGSTROM_C_I_9850;
+    case GAL_SPECLINES_S_VIII:         return GAL_SPECLINES_ANGSTROM_S_VIII;
+    case GAL_SPECLINES_He_I_10027:     return 
GAL_SPECLINES_ANGSTROM_He_I_10027;
+    case GAL_SPECLINES_He_I_10031:     return 
GAL_SPECLINES_ANGSTROM_He_I_10031;
+    case GAL_SPECLINES_Pa_delta:       return GAL_SPECLINES_ANGSTROM_Pa_delta;
+    case GAL_SPECLINES_S_II_10286:     return 
GAL_SPECLINES_ANGSTROM_S_II_10286;
+    case GAL_SPECLINES_S_II_10320:     return 
GAL_SPECLINES_ANGSTROM_S_II_10320;
+    case GAL_SPECLINES_S_II_10336:     return 
GAL_SPECLINES_ANGSTROM_S_II_10336;
+    case GAL_SPECLINES_Fe_XIII:        return GAL_SPECLINES_ANGSTROM_Fe_XIII;
+    case GAL_SPECLINES_He_I_10830:     return 
GAL_SPECLINES_ANGSTROM_He_I_10830;
+    case GAL_SPECLINES_Pa_gamma:       return GAL_SPECLINES_ANGSTROM_Pa_gamma;
+
+    /* Limits */
+    case GAL_SPECLINES_LIMIT_LYMAN:    return 
GAL_SPECLINES_ANGSTROM_LIMIT_LYMAN;
+    case GAL_SPECLINES_LIMIT_BALMER:   return 
GAL_SPECLINES_ANGSTROM_LIMIT_BALMER;
+    case GAL_SPECLINES_LIMIT_PASCHEN:  return 
GAL_SPECLINES_ANGSTROM_LIMIT_PASCHEN;
+
     default:
       error(EXIT_FAILURE, 0, "%s: '%d' not recognized line identifier",
             __func__, linecode);
diff --git a/lib/txt.c b/lib/txt.c
index 3cd693c9..314f013f 100644
--- a/lib/txt.c
+++ b/lib/txt.c
@@ -1854,9 +1854,10 @@ txt_write_metadata(FILE *fp, gal_data_t *datall, char 
**fmts,
       if( (tmp=fmts[ i*FMTS_COLS+1 ]) )      /* If it isn't NULL. */
         {
           twt=strlen(tmp);
-          if(tab0_img1==0 && data->ndim==2)        /* +1 for 0 to 10. */
-            twt+=(int)(log10(data->dsize[1]))+1+2; /* +2 for the '()'.*/
-          tw = twt > tw ? twt : tw;
+          /* A 2D col with second dim of 1 is just a normal 1D col. */
+          if(tab0_img1==0 && data->ndim==2 && data->dsize[1]>1)
+            twt+=(int)(log10(data->dsize[1]))+1+2; /* +1 for 0 to 10. */
+          tw = twt > tw ? twt : tw;                /* +2 for the '()'.*/
         }
 
       /* Go onto the next data element. */
@@ -1887,8 +1888,9 @@ txt_write_metadata(FILE *fp, gal_data_t *datall, char 
**fmts,
       for(j=1;j<nlen;++j)
         if(!isdigit(nstr[j])) nstr[j] = isdigit(nstr[j-1]) ? ':' : ' ';
 
-      /* For the type, we need to account for vector clumns. */
-      if(tab0_img1==0 && data->ndim==2)
+      /* For the type, we need to account for vector clumns. Note that a 2D
+         col with second dim of 1 is just a normal 1D col. */
+      if(tab0_img1==0 && data->ndim==2 && data->dsize[1]>1)
         { if( asprintf(&tstr, "%s(%zu)", fmts[i*FMTS_COLS+1],
                        data->dsize[1])<0 )
             error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__); }
diff --git a/tests/during-dev.sh b/tests/during-dev.sh
index 7678d7ae..90516c25 100755
--- a/tests/during-dev.sh
+++ b/tests/during-dev.sh
@@ -86,12 +86,15 @@ outdir=
 # TEST ASTSCRIPTs: if the problem is in the compiled programs used within
 # the script, you have to add a line under the line below
 #    'if [ -f "$utility" ]; then rm "$utility"; fi'
-# that will delete that particualr program.
+# that will delete that particular program.
 utilname=
 arguments=
 options=
 
 
+
+
+
 # RUN THE PROCEDURES
 # ==================
 



reply via email to

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