View Raw SPL
/*****************************************************************************
*                                                                            *
*   XYTAB.SPL  Copyright (C) 2015-2024 DSP Development Corporation           *
*                               All Rights Reserved                          *
*                                                                            *
*   Author:      Randy Race                                                  *
*                                                                            *
*   Synopsis:    Creates a table of XY series from a table                   *
*                                                                            *
*   Revisions:   20 Apr 2015  RRR  Creation                                  *
*                                                                            *
*****************************************************************************/

#if @HELP_XYTAB

    XYTAB

    Purpose: Creates a table of multiple XY series from a table.

    Syntax:  XYTAB(data, x, collist, interval)

                  data - A table or series of y values.

                     x - Optional. A series or integer. A series of X
                         values or the column number in DATA containing
                         the X values. Defaults to the first column in
                         DATA.

               collist - Optional. A series or column number from DATA
                         to use as the Y values. Defaults to all the
                         columns except the X column.

              interval - Optional. A real specifying the interpolation
                         interval. Defaults to -2, no interpolation, return
                         XY series.

    Returns: A table of one or more XY series.

    Example:
             W1: ravel(1..10, randn(10, 1), integ(randn(10, 1)));
             W2: xytab(w1)
             W3: getitem(W2, 2)

             W1 contains 3 columns of data where the first column is the
             X data and columns 2 and 3 are the Y values.
             
             W2 converts the 3 column table into 2 XY plots (a total of 4
             columns) where the X data for each XY series is column 1
             of W1.

             W3 returns the second XY plot from the XY table in W2.

    Example:
             W1: ravel(1..10, randn(10, 1), integ(randn(10, 1)));
             W2: stripchart(xytab(w1))

             W1 contains 3 columns of data where the first column is the
             X data and columns 2 and 3 are the Y values.
             
             W2 converts the 3 column table into 2 XY plots (a total of 4
             columns) and plots each XY as a stripchart.

    Example:
             W1: ravel(1..10, randn(10, 1), integ(randn(10, 1)));
             W2: stripchart(xytab(w1, 2))

             Same as above except the X values are column 2 of W1 and the
             Y values are column 1 and column 3 of W1.

    Remarks:
             XYTAB creates a table of XY plots from a table where
             typically one column is the X data and the remaining
             columns are the Y data. By default, the first column of
             the input table is considered the X values and the
             remaining columns are the Y values.
             
             Use GETITEM to extract a specific XY plot from the result.

             See XYDTTAB to create a table of XY plots from date, time and
             Y data.

    See Also:
             GETITEM
             XY
             XYDT
             XYDTTAB
#endif


static ip = -1;


/* convert all columns of a table to XY given the X column */
xytab(tab, timecol, collist, intv)
{
        local nc, cols, ncols, timeser, s, k;

        if (argc < 3)
        {
                if (argc < 2)
                {
                        if (argc < 1) error("xytab - input table required");

                        timecol = 1;
                }

                collist = {};
                intv    = -2;
        }
        else
        {
                (collist, intv) = xytab_parse_args(collist, intv);
        }

        if (isempty(collist))
        {
                collist = 1..numcols(tab);
        }

        if (isarray(timecol))
        {
                /* use input time data */
                timeser = refseries(timecol);
        }
        else
        {
                /* get time column from input table */
                timeser = col(tab, timecol);
                cols    = collist;
                collist = delete(cols, cols == timecol);

                if (length(collist) == 0)
                {
                        collist = cols;
                }
        }

        /* remove out of range columns */
        collist = delete(collist, collist > numcols(tab));

        if (isempty(tab) || isempty(timeser) || isempty(collist))
        {
                return({});
        }

        /* check default comment for time */
        defcom = getwksattribute("defaultcomment");

        if (strcmp(getcomment(timeser), defcom) == 0)
        {
                setcomment(timeser, "X");
        }
        
        /* replicate timeser for number of columns and convert to XY */
        s = xyitem(timeser, tab[.., collist], 1, 1);

        if (intv > 0 || intv == -1)
        {
                /* override "process_items" mode to interpolate entire table */
                ip = setconfig("process_items", 1);

                /* interpolate each XY to interval series */
                s = xyinterp(s, intv);

                setconfig("process_items", ip);
                ip = -1;
        }

        /* set comments for Y */
        loop (k = 1..numitems(s))
        {
                com = getcomment(s, k, 1);

                if (strcmp(defcom, com) == 0)
                {
                        com = sprintf("Chan %d", collist[k]);
                        setcomment(s, com, k, 1);
                }
        }

        if (intv > 0 || intv == -1)
        {
                /* interval series */
                if (numitems(s) > 1)
                {
                        setmatrix(s, 1);
                }

                /* each column is a separate interval series */
                itemprocess(s, 0);
        }
        else
        {
                /* XY - let functions operate on each XY column */
                itemprocess(s, 1);
        }

        /* display as table */
        setplotstyle(s, 4);
        setplottype(s, 0);

        return(s);
}


/* error handler, reset "process_items" */
xytab_error(errnum, errmes)
{
        if (ip != -1)
        {
                setconfig("process_items", ip);
                ip = -1;
        }

        error(errmes);
}


xytab_parse_args(collist, intv)
{
        local cl, iv;

        cl = {};
        iv = {};

        if (argc == 2)
        {
                if (isscalar(collist) && isarray(intv))
                {
                        cl = refseries(intv);
                        iv = collist;
                }
                else
                {
                        cl = refseries(collist);
                        iv = intv;
                }
        }

        if (argc == 1)
        {
                if (isscalar(collist))
                {
                        iv = collist;
                }
                else
                {
                        cl = collist;
                }
        }

        if (isempty(iv))
        {
                iv = -2;
        }

        return(cl, iv);
}