Skip to content

Commit 3f561db

Browse files
authored
Merge pull request #219 from labmlai/compare-fix
move smoothing to a single location for both line and spark charts
2 parents 049c4be + 37fb1f5 commit 3f561db

File tree

8 files changed

+87
-81
lines changed

8 files changed

+87
-81
lines changed

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {Indicator} from "../../../models/run"
33
import {
44
AnalysisPreferenceModel, ComparisonPreferenceModel,
55
} from "../../../models/preferences"
6-
import {getChartType} from "../../../components/charts/utils"
6+
import {getChartType, smoothAndTrimAllCharts, trimSteps} from "../../../components/charts/utils"
77
import {LineChart} from "../../../components/charts/lines/chart"
88
import {SparkLines} from "../../../components/charts/spark_lines/chart"
99

@@ -73,6 +73,8 @@ export class CardWrapper {
7373
this.stepRange = preferenceData.step_range
7474
this.focusSmoothed = preferenceData.focus_smoothed
7575
this.smoothValue = preferenceData.smooth_value
76+
77+
smoothAndTrimAllCharts(this.series, this.baseSeries, this.smoothValue, this.stepRange)
7678
}
7779

7880
public render() {

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

+12-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import {Weya as $, WeyaElement} from "../../../../../lib/weya/weya"
33
import {DeleteButton, SaveButton, ToggleButton} from "../../../components/buttons"
44
import {LineChart} from "../../../components/charts/lines/chart"
55
import {SparkLines} from "../../../components/charts/spark_lines/chart"
6-
import {getChartType} from "../../../components/charts/utils"
6+
import {
7+
getChartType,
8+
smoothAndTrimAllCharts
9+
} from "../../../components/charts/utils"
710
import {NumericRangeField} from "../../../components/input/numeric_range_field"
811
import {Loader} from "../../../components/loader"
912
import {Slider} from "../../../components/input/slider"
@@ -129,7 +132,7 @@ namespace ChangeHandlers {
129132

130133
if ((this.isBase && this.wrapper.dataStore.baseSeries[this.idx].is_summary) || (!this.isBase && this.wrapper.dataStore.series[this.idx].is_summary)) {
131134
// have to load from the backend
132-
this.wrapper.requestMissingMetrics()
135+
this.wrapper.requestMissingMetrics().then()
133136
}
134137
}
135138
}
@@ -305,12 +308,17 @@ export class ViewWrapper {
305308
})
306309
})
307310
} else if (!isLoading) {
311+
this.smoothSeries()
308312
this.renderCharts()
309313
}
310314

311315
this.isLoading = isLoading
312316
}
313317

318+
private smoothSeries() {
319+
smoothAndTrimAllCharts(this.dataStore.series, this.dataStore.baseSeries, this.dataStore.smoothValue, this.dataStore.stepRange)
320+
}
321+
314322
private renderTopButtons() {
315323
this.saveButton.disabled = !this.dataStore.isUnsaved
316324
this.topButtonContainer.innerHTML = ''
@@ -323,6 +331,8 @@ export class ViewWrapper {
323331
}
324332

325333
private renderCharts() {
334+
this.smoothSeries()
335+
326336
this.renderSparkLines()
327337
this.renderLineChart()
328338
}

app/ui/src/analyses/sessions/gpu/utils.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {Indicator} from "../../../models/run"
33
export function getSeriesData(series: Indicator[], analysis: string, isMean: boolean = false): Indicator[]{
44
let res: Indicator[] = []
55
for (let r of series) {
6-
let s = {...r}
6+
let s = r.getCopy()
77
if (s.name.includes(analysis)) {
88
if (s.name.includes('mean')) {
99
if (isMean) {

app/ui/src/components/charts/lines/chart.ts

+5-22
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ export class LineChart {
7474
this.chartWidth = windowWidth - 2 * this.margin - this.axisSize
7575
this.chartHeight = Math.round(Math.min(this.chartWidth, windowHeight) / 2)
7676

77-
let [smoothWindow, smoothRange ] = getSmoothWindow(this.currentSeries, this.baseSeries, opt.smoothValue)
78-
7977
let idx: number = 0
8078
for (let s of this.currentSeries.concat(this.baseSeries)) {
8179
if (!this.uniqueItems.has(s.name)) {
@@ -86,22 +84,7 @@ export class LineChart {
8684
this.baseSeries = this.baseSeries.filter((_, i) => this.basePlotIndex[i] == 1)
8785
this.currentSeries = this.currentSeries.filter((_, i) => this.currentPlotIndex[i] == 1)
8886

89-
smoothWindow[0] = smoothWindow[0].filter((_, i) => this.currentPlotIndex[i] == 1)
90-
smoothWindow[1] = smoothWindow[1].filter((_, i) => this.basePlotIndex[i] == 1)
91-
92-
this.currentSeries = this.currentSeries.map((s, i) => {
93-
s.series = smoothSeries(s.series, smoothWindow[0][i])
94-
return s
95-
})
96-
this.baseSeries = this.baseSeries.map((s, i) => {
97-
s.series = smoothSeries(s.series, smoothWindow[1][i])
98-
return s
99-
})
100-
101-
this.baseSeries = trimSteps(this.baseSeries, opt.stepRange[0], opt.stepRange[1], smoothRange)
102-
this.currentSeries = trimSteps(this.currentSeries, opt.stepRange[0], opt.stepRange[1], smoothRange)
103-
104-
const stepExtent = getExtent(this.baseSeries.concat(this.currentSeries).map(s => s.series), d => d.step, false, true)
87+
const stepExtent = getExtent(this.baseSeries.concat(this.currentSeries).map(s => s.trimmedSeries), d => d.step, false, true)
10588
this.xScale = getScale(stepExtent, this.chartWidth, false)
10689

10790
this.chartColors = new ChartColors({
@@ -213,11 +196,11 @@ export class LineChart {
213196
}, $ => {
214197
if (this.currentSeries.length < 3 && this.baseSeries.length == 0) {
215198
this.currentSeries.map((s, i) => {
216-
if (this.currentSeries[i].series.length == 0) {
199+
if (this.currentSeries[i].trimmedSeries.length == 0) {
217200
return
218201
}
219202
new LineFill({
220-
series: this.currentSeries[i].series,
203+
series: this.currentSeries[i].trimmedSeries,
221204
xScale: this.xScale,
222205
yScale: this.yScale,
223206
color: this.chartColors.getColor(this.uniqueItems.get(s.name)),
@@ -228,7 +211,7 @@ export class LineChart {
228211
}
229212
this.currentSeries.map((s, i) => {
230213
let linePlot = new LinePlot({
231-
series: s.series,
214+
series: s.trimmedSeries,
232215
xScale: this.xScale,
233216
yScale: this.yScale,
234217
color: this.chartColors.getColor(this.uniqueItems.get(s.name)),
@@ -241,7 +224,7 @@ export class LineChart {
241224

242225
this.baseSeries.map((s, i) => {
243226
let linePlot = new LinePlot({
244-
series: s.series,
227+
series: s.trimmedSeries,
245228
xScale: this.xScale,
246229
yScale: this.yScale,
247230
color: this.chartColors.getSecondColor(this.uniqueItems.get(s.name)),

app/ui/src/components/charts/spark_lines/chart.ts

-11
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,6 @@ export class SparkLines {
5656
const margin = Math.floor(opt.width / 64)
5757
this.rowWidth = Math.min(450, opt.width - Math.max(3 * margin, 60))
5858

59-
let [smoothWindow, _] = getSmoothWindow(this.currentSeries, this.baseSeries, opt.smoothValue)
60-
61-
this.currentSeries = this.currentSeries.map((s, i) => {
62-
s.series = smoothSeries(s.series, smoothWindow[0][i])
63-
return s
64-
})
65-
this.baseSeries = this.baseSeries.map((s, i) => {
66-
s.series = smoothSeries(s.series, smoothWindow[1][i])
67-
return s
68-
})
69-
7059
this.stepExtent = getExtent(this.currentSeries.concat(this.baseSeries).map(s => s.series), d => d.step)
7160

7261
this.chartColors = new ChartColors({nColors: this.uniqueItems.size, secondNColors: this.uniqueItems.size, isDivergent: opt.isDivergent})

app/ui/src/components/charts/timeseries/chart.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export class TimeSeriesChart {
7575
})
7676

7777
if (opt.stepRange != null) {
78-
this.series = trimSteps(this.series, opt.stepRange[0], opt.stepRange[1])
78+
// this.series = trimSteps(this.series, opt.stepRange[0], opt.stepRange[1]) // todo
7979
this.isEmpty = true
8080
for (let series of this.series) {
8181
if (series.series.length > 0) {

app/ui/src/components/charts/utils.ts

+44-43
Original file line numberDiff line numberDiff line change
@@ -181,73 +181,74 @@ export function getChartType(index: number): 'log' | 'linear' {
181181
return index === 0 ? 'linear' : 'log'
182182
}
183183

184-
export function trimSteps(series: Indicator[], min: number, max: number, smoothRange: number = 0) : Indicator[] {
185-
smoothRange /= 2 // remove half from each end
186-
return <Indicator[]>series.map(s => {
187-
let res = {...s}
184+
/**
185+
* Smooths and trims all charts in the current and base series.
186+
*
187+
* @param {Indicator[]} series - The current series of data.
188+
* @param {Indicator[]} baseSeries - The base series of data for comparison.
189+
* @param {number} smoothValue - The value to be used for smoothing the data.
190+
* @param {number[]} stepRange - The range of steps to be considered for trimming.
191+
*/
192+
export function smoothAndTrimAllCharts(series: Indicator[], baseSeries: Indicator[], smoothValue: number, stepRange: number[]) {
193+
let [smoothWindow, smoothRange ] = getSmoothWindow(series ?? [],
194+
baseSeries ?? [], smoothValue)
195+
196+
if (series != null) {
197+
series = series.map((s, i) => {
198+
s.series = smoothSeries(s.series, smoothWindow[0][i])
199+
return s
200+
})
201+
trimSteps(series, stepRange[0], stepRange[1], smoothRange)
202+
}
188203

204+
if (baseSeries != null) {
205+
baseSeries = baseSeries.map((s, i) => {
206+
s.series = smoothSeries(s.series, smoothWindow[1][i])
207+
return s
208+
})
209+
trimSteps(baseSeries, stepRange[0], stepRange[1], smoothRange)
210+
}
211+
}
212+
213+
export function trimSteps(series: Indicator[], min: number, max: number, smoothRange: number = 0) {
214+
smoothRange /= 2 // remove half from each end
215+
series.forEach(s => {
216+
let localSmoothRange = smoothRange
189217
if (s.series.length <= 2) {
190-
smoothRange = 0
218+
localSmoothRange = 0
191219
} else {
192-
let trimStepCount = smoothRange / (s.series[1].step - s.series[0].step)
220+
let trimStepCount = localSmoothRange / (s.series[1].step - s.series[0].step)
193221
if (trimStepCount < 1) {
194-
smoothRange = 0
222+
localSmoothRange = 0
195223
}
196224
}
197225

198-
res.series = []
199-
200226
let localMin = min
201227
let localMax = max
202228

203229
if (localMin == -1) {
204230
localMin = s.series[0].step
205231
}
206-
localMin = Math.max(localMin, s.series[0].step + smoothRange)
232+
localMin = Math.max(localMin, s.series[0].step + localSmoothRange)
207233

208234
if (localMax == -1) {
209235
localMax = s.series[s.series.length - 1].step
210236
}
211-
localMax = Math.min(localMax, s.series[s.series.length - 1].step - smoothRange)
237+
localMax = Math.min(localMax, s.series[s.series.length - 1].step - localSmoothRange)
238+
239+
let minIndex = s.series.length - 1
240+
let maxIndex = 0
212241

213242
for (let i = 0; i < s.series.length; i++) {
214243
let p = s.series[i]
215244
if (p.step >= localMin && p.step <= localMax) {
216-
res.series.push(p)
217-
}
218-
}
219-
220-
return res
221-
})
222-
}
223-
224-
export function trimStepsOfPoints(series: PointValue[][], min: number, max: number, smoothRange: number = 0) : PointValue[][] {
225-
smoothRange /= 2 // remove half from each end
226-
return series.map(s => {
227-
let res = []
228-
let start = 1e9, end = -1
229-
let localMin = min
230-
let localMax = max
231-
232-
if (localMin == -1) {
233-
localMin = s[0].step
234-
}
235-
localMin = Math.max(localMin, s[0].step + smoothRange)
236-
237-
if (localMax == -1) {
238-
localMax = s[s.length - 1].step
239-
}
240-
localMax = Math.min(localMax, s[s.length - 1].step - smoothRange)
241-
for (let i = 0; i < s.length; i++) {
242-
let p = s[i]
243-
if ((p.step >= localMin || localMin == -1) && (p.step <= localMax || localMax == -1)) {
244-
start = Math.min(start, i)
245-
end = Math.max(end, i)
246-
res.push(p)
245+
minIndex = Math.min(i, minIndex)
246+
maxIndex = Math.max(i, maxIndex)
247247
}
248248
}
249249

250-
return res
250+
s.lowTrimIndex = minIndex
251+
s.highTrimIndex = maxIndex
251252
})
252253
}
253254

app/ui/src/models/run.ts

+21
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,32 @@ export class Indicator {
5353
name : string
5454
series: PointValue[]
5555
is_summary: boolean
56+
lowTrimIndex: number
57+
highTrimIndex: number
5658

5759
constructor(indicator: IndicatorModel) {
5860
this.name = indicator.name
5961
this.series = toPointValue(indicator)
6062
this.is_summary = indicator.is_summary
63+
this.lowTrimIndex = 0
64+
this.highTrimIndex = this.series.length - 1
65+
}
66+
67+
get trimmedSeries(): PointValue[] {
68+
return this.series.slice(this.lowTrimIndex, this.highTrimIndex + 1)
69+
}
70+
71+
getCopy(): Indicator {
72+
let copy = new Indicator({
73+
name: this.name,
74+
step: "",
75+
value: "",
76+
mean: 0,
77+
is_summary: this.is_summary,
78+
last_step: ""
79+
})
80+
copy.series = [...this.series]
81+
return copy
6182
}
6283
}
6384

0 commit comments

Comments
 (0)