View Raw SPL
/*****************************************************************************
* *
* SETSTRIPCHART.SPL Copyright (C) 2007-2021 DSP Development Corporation *
* All Rights Reserved *
* *
* Author: Randy Race *
* *
* Synopsis: Overlays multiple series in a stripchart fashion *
* *
* Revisions: 27 Feb 2007 RRR Creation *
* 1 Mar 2007 RRR color support *
* 16 Apr 2012 RRR date/time range adjustment *
* 10 Jun 2014 RRR inherit grid color *
* 23 Apr 2015 RRR date/time XY vs interval support *
* 8 Feb 2017 RRR item check *
* *
*****************************************************************************/
#include
#if @HELP_SETSTRIPCHART
SETSTRIPCHART
Purpose: Overlays multiple series with separate stacked scales.
Syntax: SETSTRIPCHART(s1, ..., sN, altscales, gap, xgrid, ygrid, color1, ... colorN)
sN - Optional. One or more series to stack. Defaults
to the series in the current window.
altscales - Optional. An integer, the scales location.
0: left side of window (default)
1: alternate left and right sides
gap - Optional. A real bewteen 0 and 100. The
percentage gap between each overlay. Defaults
to 0.0, no gap.
xgrid - Optional. An integer, the X grid style for
each overlay.
-1: inherit current window style (default)
0: no grids
1: solid
2: dashed
3: dotted
ygrid - Optional. An integer, the Y grid style for
each overlay. Defaults to XGRID.
-1: inherit current window style
0: no grids
1: solid
2: dashed
3: dotted
colorN - Optional. A list of integers, the color for each
series. Defaults to -1, each series automatically
set to a different color. If only one color is
specified, all the series are set to that color.
Returns: Nothing, the series are displayed as a stacked stripchart.
Example:
W1: setstripchart(gnorm(100,1), integ(gnorm(100,1)), 10..80)
W1 contains a stripchart of 3 series spaced equally apart.
Example:
W1: setstripchart(gnorm(100,1), integ(gnorm(100,1)), 10..80, 1, 10, 3, 3, lblue)
Same as above accept the scales alternate, a 10 percent gap is
inserted between each overlay, dotted grids are displayed and
each series is plotted in light blue.
Example:
W1: setstripchart(gnorm(100,1), integ(gnorm(100,1)), 10..80, 1, 10, 3)
W2: integ(w1);setstripchart(1, 10, 3, 3, lblue, lgreen, lred)
W1 contains a 3 trace stripchart. W2 integrates each trace and
displays a stripchart with alternating scales, a 10 percent gap
and dotted grids. The color of the third trace is set to light
red.
When W1 changes, W2 will automatically integrate each series in
W1 and display the result in W2 as a stripchart.
Remarks:
SETSTRIPCHART can operate on a list of input series as shown
in the first example. STRIPCHART can also be used to set
a plot style as part a Window formula (shown in W2 of the
last example) or on a standalone basis.
SETSTRIPCHART uses SPANY and SETY to arrange the series as
overlays with separate, stacked scales.
If no colors are specified, each series is automatically
plotted in a different color.
If only one color is specified, all series are plotted in
that color.
SETSTRIPCHART also works with XY series. For example:
a = xy(1..100, gnorm(100, 1));
b = integ(a);
c = deriv(a);
W1: setstripchart(a, b, c);
The X plotting range is set to the minimum and maximum of all
the traces.
See Also:
Setyauto
Spany
Staggery
#endif
static stripchart_handling;
static stripchart_focus;
/* create a stripchart display */
setstripchart(argv)
{
local i, k, gap, alt, s, s1, nc, xgrid, ygrid, nfoc, foc, cmode;
local n, color, colors, colset, incolors, xmin, xmax, oclr, pmode = 1;
local gridcol, isitem, ref, force = 1, ascale = 0;
local yrange, yspan, ytics, init = 1;
if (stripchart_handling)
{
return;
}
stripchart_handling = 1;
if (outargc == 0)
{
/* disable display */
pmode = plotmode(0);
force = 0;
stripchart_focus = getfocus();
focus(0);
if (getplotstyle() == 4)
{
/* currently table, force lines */
setplotstyle(0);
}
}
numser = 0;
alt = getstripchartalt(); /* alternating scales */
gap = getstripchartgap(); /* gap between overlays as percentage */
xgrid = -1; /* xgrid style - unspecified */
ygrid = -1; /* ygrid style - unspecified */
cmode = getstripchartcolormode(); /* color unspecified */
dir = getstripchartdir(); /* direction, bottom-up or top-down */
colset = 0;
gridcol = -1;
incolors = {};
/* parse args */
if (argc > 0)
{
loop (i = 1..argc)
{
if (isarray(getargv(i)))
{
/* input series */
numser++;
}
else if (isstring(getargv(i)))
{
/* autoscale mode */
ascale = 1;
init = (getargv(i) == "init");
if (cmode >= 1000)
{
cmode -= 1000;
setstripchartcolormode(cmode);
}
else if (not(init))
{
cmode = 0;
}
break;
}
else
{
/* alternative scales, gap percentage and grids */
alt = castint(getargv(i));
if (argc > i)
{
gap = castreal(getargv(i + 1));
}
if (argc > i + 1)
{
xgrid = castint(getargv(i + 2));
}
if (argc > i + 2)
{
ygrid = castint(getargv(i + 3));
}
if (argc > i + 3)
{
dir = castint(getargv(i + 4));
}
if (argc > i + 4)
{
/* remaining values are colors */
n = argc - i - 4;
incolors = -1 * ones(n, 1);
loop (k = 1..n)
{
incolors[k] = castint(getargv(k + i + 4));
}
colset = 1;
}
break;
}
}
}
/* number of current overlays */
nfoc = getfocus(-1);
if (numser > 0)
{
if (outargc > 0)
{
colors = -1 * ones(numser, 1);
if (length(incolors) > 0)
{
if (length(incolors) == 1 && incolors[1] < -1)
{
/* -2 implies separate colors */
colors = {};
setstripchartcolormode(1);
}
else
{
/* use passed in colors */
n = min(numser, length(incolors));
colors[1..n] = incolors[1..n];
}
}
/* return a stripchart series */
s = {};
/* build array */
loop (i = 1..numser)
{
s = ravel(s, getargv(i));
if (colors[i] >= 0)
{
setcolor(s, colors[i], 1, i);
}
}
/* set to stripchart type */
setplottype(s, 7);
stripchart_handling = 0;
return(s);
}
/* existing y span, range and tic intervals */
(yspan, yrange, ytics) = setstripchart_yspanrange(w0);
/* stick empty series in window to preserve window formula */
{};
/* have list of series - create overlays */
loop (i = 1..numser)
{
/* multi-column list, chart or multiple items */
if (itemtype(getargv(i)) == 2 || itemtype(getargv(i)) == 9)
{
nc = numcols(getargv(i));
isitem = 0;
}
else
{
nc = numitems(getargv(i));
isitem = 1;
}
if (nc > 1)
{
loop (k = 1..nc)
{
s = (isitem) ? getitem(getargv(i), k) : col(getargv(i), k);
if (i == 1 && k == 1)
{
/* primary series */
s;
}
/* overlays */
else
{
if (colset || cmode == 1)
{
overlay(s);
}
else
{
/* use input series color */
overlay(s, getcolor(s));
}
}
}
}
else
{
/* XY or XYZ item */
if (i == 1)
{
getargv(i);
}
else
{
if (colset || cmode == 1)
{
/*
* use auto colors, if explicit list given,
* actual color is set later
*/
overlay(getargv(i));
}
else
{
/* use input series color */
overlay(getargv(i), getcolor(getargv(i)));
}
}
}
}
/* default grids to primary series grid style */
if (xgrid < 0)
{
xgrid = getgridstyle(1);
}
if (ygrid < 0)
{
ygrid = getgridstyle(2);
}
gridcol = getgridcolor();
}
else
{
/* existing y span, range and tic intervals */
(yspan, yrange, ytics) = setstripchart_yspanrange(w0);
/* no series args - check window for resident series */
if (getfocus(-1) == 1)
{
nc = numitems;
/* check if any item not simple interval series */
if (nc > 1 && stripchart_itemtype(W0, nc) != 0)
{
setstripchart_setitems(w0, nc, 1);
loop (k = 1..nc)
{
if (k == 1)
{
eval(sprintf("_tempitem_%d", k));
}
else
{
eval(sprintf("overlay(_tempitem_%d)", k));
}
}
setstripchart_setitems(w0, nc, 0);
}
else
{
/* have series but no overlays */
if (getplottype(w0) != 7)
{
setplottype(w0, 7);
}
nc = numitems(w0);
s = refseries(w0);
loop (k = 1..nc)
{
s1 = refseries(s, k, 1);
if (k == 1)
{
/* set primary series */
if (cmode == 2)
{
setcolor(s1, getcolor(s));
cmode = 0;
}
getitem(s, k);
}
else
{
/* overlay spans */
oclr = (cmode == 0) ? getcolor(s1) : -1;
/* set overlay to reference item */
overlay(getitem(s, k), oclr, -1, -1, -1, 0);
}
}
}
/* default grids to primary series grid style */
if (xgrid < 0)
{
xgrid = getgridstyle(1);
}
if (ygrid < 0)
{
ygrid = getgridstyle(2);
}
gridcol = getgridcolor();
}
else
{
if (cmode == 1)
{
/* get overlay colors */
incolors = getwincolorlist(numitems);
}
}
}
/* number of overlays */
nfoc = getfocus(-1);
/* overlay colors */
colors = (length(incolors) == 0) ? -1 * ones(nfoc, 1) : incolors;
if (colset || cmode == 2)
{
if (length(incolors) == 0)
{
incolors = {-1};
}
if (length(incolors) == 1)
{
/* special case, set all colors */
color = incolors[1];
if (color < -1)
{
/* -2 implies separate colors */
colors[1..nfoc] = -1;
setstripchartcolormode(1);
}
else
{
if (color == -1)
{
/* default to primary series color */
color = getwcolor(1);
}
colors[1..nfoc] = color;
setstripchartcolormode(2);
}
}
else
{
/* use passed in colors */
n = min(nfoc, length(incolors));
colors[1..n] = incolors[1..n];
if (colset)
{
setstripchartcolormode(0);
}
}
}
(xmin, xmax, xmode) = setstripchart_xminmax(nfoc, ascale);
if (nfoc > 1 || itemtype(w0) == 2 || numitems(w0) > 1)
{
/* set plot type to stripchart */
setplottype(w0, 7);
/* arrange all overlays with span and y range */
loop (i = 1..nfoc)
{
setstripchart_arrange(i, nfoc, alt, gap, xgrid, ygrid, xmin, xmax, colors[i], dir, gridcol, xmode, ascale, yspan, yrange, ytics);
}
/* sync XY */
sync(3);
/* process as one item, allows dependent windows to process overlays */
itemprocess(1);
/* set attributes */
setstripchartalt(alt);
setstripchartgap(gap);
setstripchartdir(dir);
if (max(collen(w0, 2)) == 1)
{
/* set to point if all columns only have at most one point */
setplotstyle(1);
/* add symbols */
stripchart_autosym();
}
/* show it */
focus(init ? 0 : stripchart_focus);
}
else
{
/* set to lines */
setplotstyle(w0, 0);
setplottype(w0, 0);
}
plotmode(pmode, force);
stripchart_handling = 0;
}
/* set span and y range for stripchart display */
setstripchart_arrange(n, nfoc, alt, gap, xgrid, ygrid, xmin, xmax, color, dir, gridcol, xtype, ascale, yspan, yrange, ytics)
{
local f, yt, rt, rb, off, s, k, minval, maxval, xt, ticx, yt, ticy, sign;
local ymin, ymax, ymode, ylog;
static basescales;
if (argc < 2) nfoc = getfocus(-1);
if (argc < 3) alt = 0;
if (argc < 4) gap = 0;
if (argc < 5) xgrid = -1;
if (argc < 6) ygrid = xgrid;
if (argc < 7) color = -1;
/* prevent item processing for scaling */
itemprocess(refseries(n), 0);
/* get current focus and sync */
f = getfocus();
s = getsync();
/* focus on root trace with no syncing */
focus(0);
sync(0);
xt = (getxticset()) ? xtic : -1;
/* get y autoscaling mode of root */
yauto = getyautoscale();
/* focus on this trace */
focus(n);
if (ascale) //
{
stripchart_setlog(n);
}
yt = (getyticset() && !getylog()) ? ytic() : -1;
/* get range and autoy mode */
(ymin, ymax, ymode) = setyauto();
/* check if user set autoy range */
ymode = not(ymin != ymax && ymode == 0);
if (not(yauto))
{
if (ascale)
{
/* reset tics if autoscaling */
yt = -1;
}
if (length(yspan) >= n)
{
/* use existing range and spans */
yt = ytics[n];
ybot = yrange[n, 1];
ytop = yrange[n, 2];
ymin = yspan[n, 1];
ymax = yspan[n, 2];
/* no span, use autoscale mode */
if (ymin == ymax)
{
yauto = 1;
}
}
else
{
yauto = 1;
}
}
/* reset ytics and autoscale to find plot range */
setytic(-1);
setyauto(-1, -1);
setxtic(-1);
setxauto(-1, -1);
/* set scales - check for alternating y scale location */
if (n == 1)
{
/* first trace - Y left, X bottom with labels */
basescales = stripchart_base_scales();
scales(basescales);
}
else
{
scales(stripchart_overlay_scales(n, alt, basescales));
if (!ascale)
{
// stripchart_setlog(n);
}
}
/* natural scaling, use previous autoscale mode if any */
autoscale(-1, -1);
if (ymode > 0 && (yauto || ascale))
{
/* automatic scaling */
ymin = getyb(1);
ymax = getyt(1);
}
/* stagger and span for this focus */
staggery(0);
/* new tic interval */
if (yt < 0) yt = ytic();
if (getylog())
{
/* handle log scales */
spany(ymin, ymax);
/* use automatic range */
rt = log10(abs(ymax));
rb = log10(abs(ymin));
sign = (ymax < 0) ? -1 : 1;
}
else
{
/* linear scales */
minval = ymin;
maxval = ymax;
/* set span */
spany(minval, maxval);
minval = ymin;
maxval = ymax;
rt = ceil( maxval / yt) * yt;
rb = floor(minval / yt) * yt;
sign = 1;
}
if (ascale || yauto)
{
/* total plot range including gap percentage */
rg = (rt - rb) * (1 + gap / 100);
/* plot factors for this plot */
k = (nfoc - 1) / 2;
/* direction 1:top-down, 0:bottom-up */
off = (dir) ? n - nfoc : 1 - n;
/* set y range to position this focus */
if (getylog)
{
sety(sign * (10 ^ (rb + off * rg)), sign * (10 ^ (rt + (2 * k + off) * rg)), 1);
}
else
{
sety(rb + off * rg, rt + (2 * k + off) * rg, 1);
}
}
else
{
/* use existing range */
sety(ybot, ytop, 1);
}
/* tics and grids */
setytic(yt);
if (gridcol >= 0)
{
gridcolor(gridcol);
}
if (xgrid >= 0)
{
setgridstyle(1, xgrid);
}
if (ygrid >= 0)
{
setgridstyle(2, ygrid);
}
if (color >= 0)
{
setcolor(color);
}
/* set Y autoscale parameters */
setyauto(ymin, ymax, ymode);
/* set X axis */
/* xtype = isdt(refseries(1)) && isxy(refseries(1)); */
/* xtype >= 0 indicates autoscale range set by user */
xtype = (xtype >= 0) ? xtype : -1;
ticx = (xt > 0) ? xt : xtic;
if (stripchart_scale_x_ontic())
{
xmax = ceil(xmax / ticx) * ticx;
xmin = floor(xmin / ticx) * ticx;
}
setx(xmin, xmax, xtype);
setxauto(xmin, xmax, xtype);
/* set tics after x range */
if (xt > 0)
{
setxtic(xt);
}
focus(f);
sync(s);
return();
}
stripchart_base_scales()
{
local f, winscales, xloc, yloc, lab, scales;
/* current scales */
f = getfocus();
focus(0);
winscales = getscales();
focus(f);
(xloc, yloc, lab) = stripchart_scales_loc(winscales);
if (xloc) /* x scales on, top or bottom */
{
if (xloc == 11)
{
/* x bottom */
if (yloc == 9) /* y left */
{
/* XBYL_XY_LABELS or XBYL */
scales = (lab) ? 2 : 1;
}
else if (yloc == 10) /* right */
{
/* XBYR_XY_LABELS or XBYR */
scales = (lab) ? 3 : 4;
}
else /* y off */
{
/* XB_X_LABELS or XB */
scales = (lab) ? 15 : 11;
}
}
else
{
/* x top */
if (yloc == 9) /* y left */
{
/* XTYL_XY_LABELS or XTYL */
scales = (lab) ? 7 : 6;
}
else if (yloc == 10) /* right */
{
/* XTYR_XY_LABELS or XTYR */
scales = (lab) ? 8 : 5;
}
else /* y off */
{
/* XT_X_LABELS or XT */
scales = (lab) ? 16 : 12;
}
}
}
else /* x scales off */
{
if (yloc == 9) /* y left */
{
/* YL_Y_LABELS or YL */
scales = (lab) ? 13 : 9;
}
else if (yloc == 10) /* right */
{
/* YR_Y_LABELS or YR */
scales = (lab) ? 14 : 10;
}
else /* y off */
{
scales = 0;
}
}
return(scales);
}
stripchart_overlay_scales(n, alt, basescales)
{
local xloc, yloc, lab, even, odd, scales;
(xloc, yloc, lab) = stripchart_scales_loc(basescales);
even = n % 2 == 0;
odd = not(even);
scales = 0;
if (xloc == 0 && yloc == 0)
{
scales = 0;
}
else if (alt)
{
/* alternate scales */
if ((even && yloc == 9) || (odd && yloc == 10))
{
/* YR_Y_LABELS or YR */
scales = (lab) ? 14 : 10;
}
else if ((odd && yloc == 9) || (even && yloc == 10))
{
/* YL_Y_LABELS or YL */
scales = (lab) ? 13 : 9;
}
}
else
{
/* same side */
if (yloc == 9)
{
/* left - YL_Y_LABELS or YL */
scales = (lab) ? 13 : 9;
}
else if (yloc == 10)
{
/* right - YR_Y_LABELS or YR */
scales = (lab) ? 14 : 10;
}
}
return(scales);
}
/* create or destroy temp vars set to window items */
setstripchart_setitems(win, nc, mode)
{
local i, n;
extern _tempitem_1;
if (mode == 1)
{
n = getwnum(win);
loop (i = 1..nc)
{
eval(sprintf("setvar('_tempitem_%d', refseries(castwin(%d), %d))", i, n, i));
}
if (nc > 0)
{
itemprocess(_tempitem_1, 0);
}
}
else
{
loop (i = 1..nc)
{
eval(sprintf("delvar(_tempitem_%d)", i));
}
}
}
/* min/max of stripchart */
setstripchart_xminmax(nfoc, ascale)
{
local i, xmin, xmax, smin, smax, f, user_autox;
f = getfocus();
focus(0);
/* get range and autox mode */
(xmin, xmax, xmode) = setxauto();
/* check if user set autox range */
user_autox = (xmin != xmax && xmode >= 0);
if (not(user_autox))
{
/* indicates autox set by stripchart, not user */
xmode = -1;
(xmin, xmax) = setstripchart_minmax_x(refseries(1), refseries(1));
if (nfoc > 1)
{
loop (i = 2..nfoc)
{
(smin, smax) = setstripchart_minmax_x(refseries(1), refseries(i));
xmin = min(xmin, smin);
xmax = max(xmax, smax);
}
}
}
focus(f);
return(xmin, xmax, xmode);
}
/* fast lookup of minmax X with possible date/time correction */
setstripchart_minmax_x(s0, s)
{
local xmin, xmax, dt_off, dt_dx;
/* xval min/max */
(xmin, xmax) = xminmax(s);
/* offset for date/time */
(dt_off, dt_dx) = xyconform(s0, s);
xmin *= dt_dx;
xmax *= dt_dx;
xmin += dt_off;
xmax += dt_off;
return(xmin, xmax);
}
/* scales location */
stripchart_scales_loc(stype)
{
local xloc, yloc, lab;
xloc = stripchart_scales_x_loc(stype);
yloc = stripchart_scales_y_loc(stype);
lab = stripchart_scales_lab(stype);
return(xloc, yloc, lab);
}
/* x scales location */
stripchart_scales_x_loc(stype)
{
local loc;
switch (stype)
{
case 1: /* XBYL */
case 2: /* XBYL_XY_LABEL */
case 3: /* XBYR_XY_LABELS */
case 4: /* XBYR */
case 11: /* XB */
case 15: /* XBL */
loc = 11; /* XB */
break;
case 5: /* XTYR */
case 6: /* XTLY */
case 7: /* XTYL_XY_LABELS */
case 8: /* XTYR_XY_LABELS */
case 12: /* XT */
case 16: /* XTL */
loc = 12; /* XT */
break;
default:
loc = 0;
break;
}
return(loc);
}
/* y scales location */
stripchart_scales_y_loc(stype)
{
local loc;
switch (stype)
{
case 1: /* XBYL */
case 2: /* XBYL_XY_LABEL */
case 6: /* XTLY */
case 7: /* XTYL_XY_LABELS */
case 9: /* YL */
case 13: /* YL_Y_LABELS */
loc = 9; /* YL */
break;
case 3: /* XBYR_XY_LABELS */
case 4: /* XBYR */
case 5: /* XTYR */
case 8: /* XTYR_XY_LABELS */
case 10: /* YR */
case 14: /* YR_Y_LABELS */
loc = 10; /* YR */
break;
default:
loc = 0;
break;
}
return(loc);
}
/* axis label location */
stripchart_scales_lab(stype)
{
local lab;
switch (stype)
{
case 2: /* XBYL_XY_LABEL */
case 3: /* XBYR_XY_LABELS */
case 7: /* XTYL_XY_LABELS */
case 8: /* XTYR_XY_LABELS */
case 14: /* YR_Y_LABELS */
lab = 3; /* XY */
break;
case 15: /* XB_X_LABELS */
case 16: /* XT_X_LABELS */
lab = 1; /* X */
break;
case 13: /* YL_Y_LABELS */
case 14: /* YT_Y_LABLES */
lab = 2; /* Y */
break;
default:
lab = 0;
break;
}
return(lab);
}
/* error handler */
setstripchart_error()
{
stripchart_handling = 0;
pon;
}
/* does X axis scale on tic marks? */
stripchart_scale_x_ontic()
{
local p, status = 0;
p = getconf("scale_on_tics");
if (strlen(p) > 0)
{
status = (castint(p) & 0x02) > 0;
}
return(status);
}
/* check if any item not a series */
stripchart_itemtype(w, numitem)
{
local j;
loop (j = 1..numitem)
{
if (itemtype(refseries(w, j)) != 0)
{
return(1);
}
}
return(0);
}
/* set log attributes based of root */
stripchart_setlog(n)
{
local xlog, xlab, xexp, ylog, ylab, yexp;
focus(0);
xlog = getxlog(w0, 0);
xlab = getxlog(w0, 1);
xexp = getxlog(w0, 2);
ylog = getylog(w0, 0);
ylab = getylog(w0, 1);
yexp = getylog(w0, 2);
focus(n);
setxlog(xlog, xlab, xexp);
setylog(ylog, ylab, yexp);
}
/* get y span, range and tic intervals as arrays for each trace */
setstripchart_yspanrange(w)
{
local yspan, yrange, ytics, i, nfoc;
nfoc = getfocus(w, -1);
yspan = zeros(nfoc, 2);
yrange = zeros(nfoc, 2);
ytics = zeros(nfoc, 1);
/* only used if Y autoscaling is off */
if (not(getyautoscale(w0)))
{
loop (i = 1..nfoc)
{
focus(w, i);
(yspan[i, 1], yspan[i, 2]) = getspany(w);
(yrange[i, 1], yrange[i, 2]) = gety(w, 1);
ytics[i] = ytic(w);
}
}
focus(w, 0);
return(yspan, yrange, ytics);
}
/* automatically set symbols on each trace */
stripchart_autosym(sym)
{
local j, f;
if (argc < 1) sym = 1;
f = getfocus();
loop (j = 1..numfocus())
{
focus(j);
setsym(sym);
sym++;
}
focus(f);
}