Skip to content

Instantly share code, notes, and snippets.

@yogi87
Last active October 6, 2015 20:53
Show Gist options
  • Save yogi87/4224f00f568a7d05c020 to your computer and use it in GitHub Desktop.
Save yogi87/4224f00f568a7d05c020 to your computer and use it in GitHub Desktop.
// ts -- juttle timeseries utilities
//
import 'https://gist.githubusercontent.com/welch/3f7b696beab6ba1b55bb/raw/stdj.juttle' as stdj;
//
// downsample: thin a series of values by retaining its extreme values over successive intervals
// parameters:
// in -- name of value field
// every -- interval of each downsample
//
export sub downsample(in, every) {
reduce -every every _downsample_max = max(in), _downsample_min = min(in)
| put *in = (Math.abs(_downsample_max) >= Math.abs(_downsample_min)) ? _downsample_max : _downsample_min
| remove _downsample_min, _downsample_max
}
//
// downsample_by: thin multiple series of values identified by the named field
// parameters:
// in -- name of value field
// every -- interval of each downsample
// by -- name of field identifying each series.
//
export sub downsample_by(in, every, by) {
reduce -every every _downsample_max = max(in), _downsample_min = min(in) by by
| put *in = (Math.abs(_downsample_max) >= Math.abs(_downsample_min)) ? _downsample_max : _downsample_min
| remove _downsample_min, _downsample_max
}
//
// lag: return the value of a field from N points ago.
//
// Note: this must be run as a windowed reducer, eg, reduce -every :h: -over :h:
//
// (running this as a windowed reducer means its reset() function will be called
// at the beginning of each new interval rather than the reducer being torn down and
// rebuilt. This allows the reducer to propagate values across intervals.)
//
// Note 2: if you want to lag by an amount of time rather than a number of
// points, use a windowed first()
//
export reducer lag(field, N, initial) {
var lagged = [];
var i = 0, n = 0;
function update() {
lagged[i] = *field;
n = Math.min(n + 1, N + 1);
i = (i + 1) % (N + 1);
}
function result() {
if (n < N + 1) {
return initial;
} else {
return lagged[i];
}
}
function reset() {
// never reset
}
}
//
// delta: return the difference betwen the current value of a field
// and that from the previous point.
//
// Note: this must be run as a windowed reducer, eg, reduce -every :h: -over :h:
//
// (running this as a windowed reducer means its reset() function will be called
// at the beginning of each new interval rather than the reducer being torn down and
// rebuilt. This allows the reducer to propagate values across intervals.)
//
// Note 2: if you want a delta over an amount of time rather than a number of
// points, use a windowed (last() - first())
//
export reducer delta(in) {
var last = null;
var this = null;
function update() {
last = this;
this = *in;
}
function result() {
return (last != null) ? this - last : this - this;
}
function reset() {
// don't reset
}
}
//
// chart_by: an inline chart. if by is null, chart will guess field
// which it should use (and may do a poor job of it)
export sub chart_by(by, title) {
(
@timechart -title title -id title -display.dataDensity 0 -keyField by;
merge;
)
}
export sub chart_by_every(by, title, every) {
(
@timechart -title title -id title -display.dataDensity 0 -keyField by -display.duration every;
merge;
)
}
//
// split_chart: inline chart that includes a split. Send it points having
// multiple value fields on them to see each field plotted
// as its own series.
//
export sub split_chart(title) {
(
split | @timechart -title title -id title -display.dataDensity 0;
merge;
)
}
export sub split_chart_every(title, every) {
(
split | @timechart -title title -id title -display.dataDensity 0 -display.duration every;
merge;
)
}
export sub split_chart_end(title) {
split | @timechart -title title -id title -display.dataDensity 0;
}
export sub split_chart_range(title, from, to) {
(
split | filter time > from time < to |
@timechart -title title -id title -display.dataDensity 0;
merge;
)
}
//
// dual_chart_by: an inline chart with two veritical axes for overlaying
// a differently scaled series
// parameters:
// by -- name of field holding series names (including secondary)
// secondary -- name of secondary series (all others go to primary axis)
//
export sub dual_chart_by(title, by, secondary) {
(
@timechart -id title -o {
keyField: by,
title: title,
display: { dataDensity: 0 },
yScales: { secondary: { } },
series: [
{ name: secondary, yScale: 'secondary' }
]
};
merge;
)
}
//
// split_dual_chart: an inline split chart with two veritical axes for overlaying
// a differently scaled series
// parameters:
// secondary -- name of secondary series (all others go to primary axis)
//
export sub split_dual_chart(title, secondary) {
(
split | @timechart -id title -o {
keyField: 'name',
title: title,
display: { dataDensity: 0 },
yScales: { secondary: { } },
series: [
{ name: secondary, yScale: 'secondary' }
]
};
merge;
)
}
// split_dual_chart_by: an inline split chart with two veritical axes for overlaying
// a differently scaled series
// parameters:
// by -- name of field holding series names (including secondary)
// secondary -- name of secondary series (all others go to primary axis)
//
export sub split_dual_chart_by(title, by, secondary) {
(
split by | @timechart -id title -o {
keyField: [by,'name'],
title: title,
display: { dataDensity: 0 },
yScales: { secondary: { } },
series: [
{ name: secondary, yScale: 'secondary' }
]
};
merge;
)
}
export sub run() {
emit -limit 100 -every :.1s:
| put c = count(), x = c * ((c % 2 == 0)? 1 : -1)
| downsample -in "x" -every :.2s:
| put c = count(), z = c/2
| split_dual_chart -title 'testing' -secondary 'c'
| stdj.end
}
run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment