Skip to content

Commit 3c12d68

Browse files
committed
implement exponential average smoothing
1 parent a8016e8 commit 3c12d68

File tree

5 files changed

+79
-9
lines changed

5 files changed

+79
-9
lines changed

app/ui/src/analyses/experiments/chart_wrapper/card.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
import {getChartType} from "../../../components/charts/utils"
77
import {LineChart} from "../../../components/charts/lines/chart"
88
import {SparkLines} from "../../../components/charts/spark_lines/chart"
9-
import {MovingAverage} from "../../../components/charts/smoothing/moving_average"
9+
import {TwoSidedExponentialAverage} from "../../../components/charts/smoothing/two_sided_exponential_average"
1010

1111
interface CardWrapperOptions {
1212
width: number
@@ -77,13 +77,13 @@ export class CardWrapper {
7777
this.smoothValue = preferenceData.smooth_value
7878
this.trimSmoothEnds = preferenceData.trim_smooth_ends
7979

80-
let [smoothedSeries, smoothedBaseSeries] = (new MovingAverage({
80+
let [smoothedSeries, smoothedBaseSeries] = (new TwoSidedExponentialAverage({
8181
indicators: this.series.concat(this.baseSeries ?? []) ?? [],
8282
smoothValue: this.smoothValue,
8383
min: this.stepRange[0],
8484
max: this.stepRange[1],
8585
currentIndicatorLength: this.series.length
86-
}, this.trimSmoothEnds)).smoothAndTrim()
86+
})).smoothAndTrim()
8787

8888
this.series = smoothedSeries
8989
this.baseSeries = smoothedBaseSeries

app/ui/src/analyses/experiments/chart_wrapper/view.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {Loader} from "../../../components/loader"
1111
import {Slider} from "../../../components/input/slider"
1212
import {UserMessages} from "../../../components/user_messages"
1313
import {NetworkError} from "../../../network"
14-
import {MovingAverage} from "../../../components/charts/smoothing/moving_average"
14+
import {TwoSidedExponentialAverage} from "../../../components/charts/smoothing/two_sided_exponential_average"
1515

1616
interface ViewWrapperOpt {
1717
dataStore: MetricDataStore
@@ -221,10 +221,10 @@ export class ViewWrapper {
221221
parent: this.constructor.name
222222
})
223223
this.smoothSlider = new Slider({
224-
min: 1,
224+
min: 0,
225225
max: 100,
226226
value: this.dataStore.smoothValue,
227-
step: 0.1,
227+
step: 0.001,
228228
onChange: (value: number) => {
229229
let changeHandler = new ChangeHandlers.SmoothValueHandler(this, value)
230230
changeHandler.change()
@@ -333,13 +333,13 @@ export class ViewWrapper {
333333
}
334334

335335
private smoothSeries() {
336-
let [series, baseSeries] = (new MovingAverage({
336+
let [series, baseSeries] = (new TwoSidedExponentialAverage({
337337
indicators: this.dataStore.series.concat(this.dataStore.baseSeries ?? []) ?? [],
338338
smoothValue: this.dataStore.smoothValue,
339339
min: this.dataStore.stepRange[0],
340340
max: this.dataStore.stepRange[1],
341341
currentIndicatorLength: this.dataStore.series.length
342-
}, this.dataStore.trimSmoothEnds)).smoothAndTrim()
342+
})).smoothAndTrim()
343343

344344
this.dataStore.series = series
345345
this.dataStore.baseSeries = baseSeries
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {SeriesSmoothing} from "./smoothing_base";
2+
import {PointValue} from "../../../models/run";
3+
4+
export class ExponentialMovingAverage extends SeriesSmoothing {
5+
protected smooth(): void {
6+
let smoothingFactor = 1 - this.smoothValue / 100
7+
8+
for (let i = 0; i < this.indicators.length; i++) {
9+
let ind = this.indicators[i]
10+
11+
if (ind.series.length == 0) {
12+
continue
13+
}
14+
15+
let result: PointValue[] = []
16+
17+
let lastSmoothed = ind.series[0].value
18+
for (let j = 0; j < ind.series.length; j++) {
19+
let smoothed = lastSmoothed * (1 - smoothingFactor) + ind.series[j].value * smoothingFactor
20+
result.push({step: ind.series[j].step, value: ind.series[j].value, smoothed: smoothed,
21+
lastStep: ind.series[j].lastStep})
22+
lastSmoothed = smoothed
23+
}
24+
25+
ind.series = result
26+
}
27+
}
28+
}

app/ui/src/components/charts/smoothing/smoothing_base.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export abstract class SeriesSmoothing {
1515
protected max: number
1616
protected currentIndicatorLength: number
1717

18-
protected constructor(opt: SeriesSmoothingOptions) {
18+
constructor(opt: SeriesSmoothingOptions) {
1919
this.indicators = opt.indicators
2020
this.smoothValue = opt.smoothValue
2121
this.min = opt.min
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {SeriesSmoothing} from "./smoothing_base"
2+
import {PointValue} from "../../../models/run"
3+
4+
export class TwoSidedExponentialAverage extends SeriesSmoothing {
5+
protected smooth(): void {
6+
let smoothingFactor = 1 - this.smoothValue / 100
7+
8+
for (let i = 0; i < this.indicators.length; i++) {
9+
let ind = this.indicators[i]
10+
11+
if (ind.series.length < 2) {
12+
continue
13+
}
14+
15+
let result: PointValue[] = []
16+
let forward_pass: number[] = []
17+
let lastSmoothed = ind.series[0].value
18+
for (let j = 0; j < ind.series.length; j++) {
19+
let smoothed = lastSmoothed * (1 - smoothingFactor) + ind.series[j].value * smoothingFactor
20+
forward_pass.push(smoothed)
21+
lastSmoothed = smoothed
22+
}
23+
24+
let backward_pass: number[] = []
25+
lastSmoothed = ind.series[ind.series.length - 1].value
26+
for (let j = ind.series.length - 1; j >= 0; j--) {
27+
let smoothed = lastSmoothed * (1 - smoothingFactor) + ind.series[j].value * smoothingFactor
28+
backward_pass.push(smoothed)
29+
lastSmoothed = smoothed
30+
}
31+
backward_pass = backward_pass.reverse()
32+
33+
for (let j = 0; j < ind.series.length; j++) {
34+
let smoothed = (forward_pass[j] + backward_pass[j]) / 2
35+
result.push({step: ind.series[j].step, value: ind.series[j].value, smoothed: smoothed,
36+
lastStep: ind.series[j].lastStep})
37+
}
38+
39+
ind.series = result
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)