View Raw SPL
/*****************************************************************************
* *
* OVERLAYXSYNC.SPL Copyright (C) 2021 DSP Development Corporation *
* All Rights Reserved *
* *
* Author: Randy Race *
* *
* Synopsis: Simple X axis synchronization of multiple overlays *
* *
* Revisions: 22 Jan 2021 RRR Creation *
* *
*****************************************************************************/
#if @HELP_OVERLAYXSYNC
OVERLAYXSYNC
Purpose: X axis synchronization of one or more overlays.
Syntax: OVERLAYXSYNC(win, maxrange)
win - Optional. The target window. Defaults to the current
window.
maxrange - Optional. An integer, set the X range of each
overlay to fit all series. Defaults to 1.
Returns: Nothing, the overlays of a window are synchronized based on the
X axis.
Example:
W1: 1..10;settime(w0, "12:00");sethunits("s");setvunits("V")
W2: 3..0.1..20;settime(w0, "12:00");sethunits("s");setvunits("A")
W3: w1;setsym(14);overlay(w2);focus(2);scales(13);focus(1);
W4: w1;setsym(14);overlay(w2);focus(2);scales(13);overlayxsync();
The series in W1 starts at 1.0 and contains 10 samples.
The series in W2 starts at 3.0 and contains 171 samples.
The sample rate of W1 is 1 Hz and the sample rate of W2 is 10 Hz.
W3 contains a simple overlay of W1 and W2. Because the series
do not begin at the same time, the data values do not line up
on the X axis.
W4 contains an overlay of W1 and W2. The traces are X aligned
such that data samples with the same X value plot at the
same X coordinate.
Example:
W1: 1..10;settime(w0, "12:00");sethunits("Time");setvunits("V")
W2: 3..0.1..20;settime(w0, "12:00");sethunits("Time");setvunits("A")
W3: stripchart(w1, w2);setsym(14, 1);griddot;gridhv
W4: w1;setsym(14);overlay(w2);focus(2);scales(13);overlayxsync();
Similar to above, except wall clock time is used as the X axis.
The series in W1 starts at 12:00:01 and contains 10 samples.
The series in W2 starts at 12:00:03 and contains 171 samples.
The sample rate of W1 is 1 Hz and the sample rate of W2 is 10 Hz.
W3 contains a simple strupchart of W1 and W2. The stripchart
automatically aligns the data values in each trace on the common
time axis.
W4 contains an overlay of W1 and W2. Similar to the stripchart,
the traces are time aligned such that data samples with the same
time value plot at the same X coordinate.
Example:
W1: 1..10;settime(w0, "12:00");sethunits("Time");setvunits("V")
W2: 3..0.1..20;settime(w0, "12:00");sethunits("Time");setvunits("A")
W3: stripchart(w2, w1);setsym(14, 2);griddot;gridhv
W4: w2;overlay(w1);focus(2);scales(13);setsym(14);overlayxsync();
Same as above except the input series are swapped. The data
values of W4 still line up in time, but since the first trace
has more samples per second, there may not be a corresponding
value of the second trace for every sample of the first trace.
Example:
W1: 1..10;settime(w0, "12:00");sethunits("Time");setvunits("V")
W2: 3..0.1..20;settime(w0, "12:00");sethunits("Time");setvunits("A")
W3: (y1, y2) = timesync(w1, w2);y2;overlay(y1);focus(2);scales(13);setsym(14);focus(1);
W4: (y1, y2) = timesync(w1, w2);y2;overlay(y1);focus(2);scales(13);setsym(14);overlayxsync();
Same as above except the series are first time synchronized
by TIMESYNC to have the same sample rate. The data
values of W4 line up in time, and each value of the first trace
has a corresponding value in the second trace.
Remarks:
OVERLAYXSYNC synchronizes overlays by adjusting the window
extent so X values align as with an OVERPLOT. The data values are
not changed.
If MAXRANGE is 0, the X range of each overlay is set to the
X range of the root series.
If MAXRANGE is 1 (default), the X range of each overlay is
set to the maximum X extent of all the series.
See TIMESYNC to perform time synchronization of two series
by resampling and extraction.
See Also:
Overlay
Sync
Timesync
#endif
/* X axis synchronize overlays */
overlayxsync(win, maxrange)
{
local winnum, nfoc, xr, xl, j, xoff, doff, ddx, new_xl, new_xr;
/* inputs */
(winnum, maxrange) = overlayxsync_parse_args(win, maxrange);
win = castwindow(winnum);
/* number of traces */
if ((nfoc = numfocus(win)) > 1)
{
/* root */
focus(win, 1);
/* sync x */
sync(win, 1);
/* full x range */
autoscale(win, -1, -1);
if (maxrange)
{
/* full X span */
(xl, xr) = overlayxsync_xminmax(win, nfoc);
}
else
{
/* X coords of root */
(xl, xr) = overlayxsync_minmax_x(refseries(win, 1), refseries(win, 1));
}
/* set new x range */
setx(win, xl, xr);
setxauto(win, xl, xr);
autoscale(win);
xoff = overlayxsync_xoffset(win);
/* set coords of each trace */
loop (j = 2..nfoc)
{
/* potential date/time offset and scaling */
(doff, ddx) = xyconform(refseries(win, j), refseries(win, 1));
/* map new x range */
new_xl = xl * ddx + doff - xoff;
new_xr = xr * ddx + doff - xoff;
focus(win, j);
/* set new x range */
setx(win, new_xl, new_xr);
setxauto(win, new_xl, new_xr);
autoscale(win);
focus(win, 1);
}
}
}
/* parse inputs */
overlayxsync_parse_args(win, maxrange)
{
if (argc < 2)
{
/* default to full X range */
maxrange = 1;
if (argc < 1)
{
win = refwindow(w0);
}
else if (isscalar(win))
{
maxrange = win;
win = refwindow(w0);
}
}
return(getwnum(win), maxrange);
}
/* min/max of all overlays */
overlayxsync_xminmax(win, nfoc)
{
local i, xmin, xmax, smin, smax, f;
f = getfocus(win);
focus(win, 0);
/* initial range */
(xmin, xmax) = overlayxsync_minmax_x(refseries(win, 1), refseries(win, 1));
if (nfoc > 1)
{
loop (i = 2..nfoc)
{
(smin, smax) = overlayxsync_minmax_x(refseries(win, 1), refseries(win, i));
xmin = min(xmin, smin);
xmax = max(xmax, smax);
}
}
focus(win, f);
return(xmin, xmax);
}
/* fast lookup of minmax X with possible date/time correction */
overlayxsync_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);
}
/* x offset */
overlayxsync_xoffset(s)
{
local xoff = 0;
return(xoff); //
if (isdt(s))
{
xoff = isxy(s) ? 0.0 : xoffset(s);
}
return(xoff);
}