Skip to content

Commit 784454d

Browse files
authored
Codec-Compare version 0.3.1 (#20)
Add setting for displaying 10th and 90th percentiles as error bars. Only works for absolute mode for now.
1 parent 5b1a32f commit 784454d

11 files changed

Lines changed: 201 additions & 14 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## v0.3.1
4+
5+
- Add setting for displaying 10th and 90th percentiles as error bars.
6+
37
## v0.3.0
48

59
- Add absolute metrics mode. Default mode remains relative ratios.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codec_compare",
3-
"version": "0.3.0",
3+
"version": "0.3.1",
44
"description": "Codec performance comparison tool",
55
"publisher": "Google LLC",
66
"author": "Yannis Guyon",

readme_preview.png

27 Bytes
Loading

src/codec_compare.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export class CodecCompare extends LitElement {
208208
</p>
209209
210210
<p id="credits">
211-
Codec Compare beta version 0.3.0<br>
211+
Codec Compare version 0.3.1<br>
212212
<a href="https://github.com/webmproject/codec-compare">
213213
Sources on GitHub
214214
</a>

src/geometric_mean.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* See https://en.wikipedia.org/wiki/Geometric_mean.
1818
*/
1919
export class GeometricMean {
20-
/** Add a value to be part of the geometric mean. */
20+
/** Adds a value to be part of the geometric mean. */
2121
add(value: number) {
2222
this.product *= value;
2323
++this.numValues;

src/metric.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {getFinalValue} from './constant';
1616
import {areFieldsComparable, Batch, Field, FieldId} from './entry';
1717
import {GeometricMean} from './geometric_mean';
1818
import {Match} from './matcher';
19+
import {Quantile} from './quantile';
1920

2021
/** References two fields from two selected batches to compare data points. */
2122
export class FieldMetric {
@@ -32,19 +33,36 @@ export class FieldMetric {
3233
export class FieldMetricStats {
3334
// Absolute values
3435
absoluteArithmeticMean = 0;
36+
absoluteArithmeticLowQuantile = 0;
37+
absoluteArithmeticHighQuantile = 0;
3538

3639
// Relative ratios
3740
geometricMean = 1;
3841
minRatio = 1;
3942
maxRatio = 1;
4043
relativeArithmeticMean = 1;
44+
relativeArithmeticLowQuantile = 1;
45+
relativeArithmeticHighQuantile = 1;
4146

4247
getAbsoluteMean() {
4348
return this.absoluteArithmeticMean;
4449
}
50+
getAbsoluteLowQuantile() {
51+
return this.absoluteArithmeticLowQuantile;
52+
}
53+
getAbsoluteHighQuantile() {
54+
return this.absoluteArithmeticHighQuantile;
55+
}
56+
4557
getRelativeMean(geometric: boolean) {
4658
return geometric ? this.geometricMean : this.relativeArithmeticMean;
4759
}
60+
getRelativeLowQuantile() {
61+
return this.relativeArithmeticLowQuantile;
62+
}
63+
getRelativeHighQuantile() {
64+
return this.relativeArithmeticHighQuantile;
65+
}
4866
}
4967

5068
/** Aggregated stats for a unique source media. */
@@ -187,6 +205,8 @@ export function computeStats(
187205

188206
const fieldStats = new FieldMetricStats();
189207
let numDataPoints = 0;
208+
const leftQuantile = new Quantile();
209+
const rightQuantile = new Quantile();
190210
const geometricMean = new GeometricMean();
191211
let leftSum = 0;
192212
let rightSum = 0;
@@ -200,6 +220,8 @@ export function computeStats(
200220
// it is safer to surface that in the final user interface than
201221
// silently skipping that data point here.
202222

223+
leftQuantile.add(leftValue);
224+
rightQuantile.add(rightValue);
203225
if (numDataPoints === 0) {
204226
fieldStats.minRatio = ratio;
205227
fieldStats.maxRatio = ratio;
@@ -214,8 +236,15 @@ export function computeStats(
214236
}
215237
if (numDataPoints > 0) {
216238
fieldStats.absoluteArithmeticMean = leftSum / numDataPoints;
239+
// TODO(yguyon): Do not hardcode quantiles but use State fields.
240+
fieldStats.absoluteArithmeticLowQuantile = leftQuantile.get(0.1);
241+
fieldStats.absoluteArithmeticHighQuantile = leftQuantile.get(0.9);
217242
fieldStats.geometricMean = geometricMean.get();
218243
fieldStats.relativeArithmeticMean = getRatio(leftSum, rightSum);
244+
fieldStats.relativeArithmeticLowQuantile =
245+
getRatio(leftQuantile.get(0.1), rightQuantile.get(0.1));
246+
fieldStats.relativeArithmeticHighQuantile =
247+
getRatio(leftQuantile.get(0.9), rightQuantile.get(0.9));
219248
}
220249
stats.push(fieldStats);
221250
}

src/plot_ui.ts

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ export class PlotUi {
226226
for (const group of this.state.groups) {
227227
const xMeans: number[] = [];
228228
const yMeans: number[] = [];
229+
const xLowErrors: number[] = [];
230+
const xHighErrors: number[] = [];
231+
const yLowErrors: number[] = [];
232+
const yHighErrors: number[] = [];
229233
const meanTexts: string[] = [];
230234
const colors: string[] = [];
231235
const batchIndices: number[] = [];
@@ -250,14 +254,37 @@ export class PlotUi {
250254
this.state.metrics.findIndex((metric) => metric === xMetric);
251255
const yMetricIndex =
252256
this.state.metrics.findIndex((metric) => metric === yMetric);
253-
if (showRelativeRatios) {
254-
xMeans.push(batchSelection.stats[xMetricIndex].getRelativeMean(
255-
useGeometricMean));
256-
yMeans.push(batchSelection.stats[yMetricIndex].getRelativeMean(
257-
useGeometricMean));
258-
} else {
259-
xMeans.push(batchSelection.stats[xMetricIndex].getAbsoluteMean());
260-
yMeans.push(batchSelection.stats[yMetricIndex].getAbsoluteMean());
257+
const xMean = showRelativeRatios ?
258+
batchSelection.stats[xMetricIndex].getRelativeMean(
259+
useGeometricMean) :
260+
batchSelection.stats[xMetricIndex].getAbsoluteMean();
261+
const yMean = showRelativeRatios ?
262+
batchSelection.stats[yMetricIndex].getRelativeMean(
263+
useGeometricMean) :
264+
batchSelection.stats[yMetricIndex].getAbsoluteMean();
265+
xMeans.push(xMean);
266+
yMeans.push(yMean);
267+
if (!useGeometricMean) {
268+
if (this.state.horizontalQuantile === 0.1) {
269+
const xLowError = showRelativeRatios ?
270+
batchSelection.stats[xMetricIndex].getRelativeLowQuantile() :
271+
batchSelection.stats[xMetricIndex].getAbsoluteLowQuantile();
272+
const xHighError = showRelativeRatios ?
273+
batchSelection.stats[xMetricIndex].getRelativeHighQuantile() :
274+
batchSelection.stats[xMetricIndex].getAbsoluteHighQuantile();
275+
xLowErrors.push(xMean - xLowError);
276+
xHighErrors.push(xHighError - xMean);
277+
}
278+
if (this.state.verticalQuantile === 0.1) {
279+
const yLowError = showRelativeRatios ?
280+
batchSelection.stats[yMetricIndex].getRelativeLowQuantile() :
281+
batchSelection.stats[yMetricIndex].getAbsoluteLowQuantile();
282+
const yHighError = showRelativeRatios ?
283+
batchSelection.stats[yMetricIndex].getRelativeHighQuantile() :
284+
batchSelection.stats[yMetricIndex].getAbsoluteHighQuantile();
285+
yLowErrors.push(yMean - yLowError);
286+
yHighErrors.push(yHighError - yMean);
287+
}
261288
}
262289
meanTexts.push(batch.name);
263290
colors.push(batch.color);
@@ -269,7 +296,7 @@ export class PlotUi {
269296
let hovertemplate = '%{text} vs ' + referenceBatch.name + '<br>';
270297
hovertemplate += xAxis + ': %{x:.2f}<br>';
271298
hovertemplate += yAxis + ': %{y:.2f}';
272-
const geomeans: PlotlyData = {
299+
let geomeans: PlotlyData = {
273300
x: xMeans,
274301
y: yMeans,
275302
text: meanTexts,
@@ -284,6 +311,25 @@ export class PlotUi {
284311
isAggregated: true,
285312
batchIndices,
286313
};
314+
// TODO(yguyon): Fix quantiles then enable them with showRelativeRatios.
315+
if (!showRelativeRatios && !useGeometricMean &&
316+
this.state.horizontalQuantile === 0.1) {
317+
geomeans.error_x = {
318+
type: 'data',
319+
symmetric: false,
320+
array: xLowErrors,
321+
arrayminus: xHighErrors,
322+
};
323+
}
324+
if (!showRelativeRatios && !useGeometricMean &&
325+
this.state.verticalQuantile === 0.1) {
326+
geomeans.error_y = {
327+
type: 'data',
328+
symmetric: false,
329+
array: yLowErrors,
330+
arrayminus: yHighErrors,
331+
};
332+
}
287333
this.plotlyData.push(geomeans);
288334
}
289335
}

src/quantile.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/** Accumulates values and computes the given quantile. */
16+
export class Quantile {
17+
/**
18+
* Adds a value to be part of the points on which the quantile is computed.
19+
*/
20+
add(value: number) {
21+
this.values.push(value);
22+
this.valuesAreSorted = false;
23+
}
24+
25+
/** Computes and returns the quantile of all the added values so far. */
26+
get(quantile: number) {
27+
if (this.values.length === 0) {
28+
return 0;
29+
}
30+
if (!this.valuesAreSorted) {
31+
this.values.sort((a: number, b: number) => a - b);
32+
this.valuesAreSorted = true;
33+
}
34+
// Naive quantile computation for now.
35+
return this.values[Math.floor((this.values.length - 1) * quantile)];
36+
}
37+
38+
private values = new Array<number>();
39+
private valuesAreSorted = true;
40+
}

src/settings_ui.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,48 @@ export class SettingsUi extends LitElement {
118118
Geometric mean
119119
</span>
120120
</div>
121+
<div class="settingGroup">
122+
<span title="Do not show horizontal error bars">
123+
Hide X error bars
124+
</span>
125+
<mwc-switch id="settingUseHorizontalErrorBars" ?selected=${
126+
!this.state.showRelativeRatios && !this.state.useGeometricMean &&
127+
this.state.horizontalQuantile === 0.1}
128+
?disabled=${
129+
this.state.showRelativeRatios ||
130+
this.state.useGeometricMean}
131+
@click=${() => {
132+
this.state.horizontalQuantile =
133+
this.state.horizontalQuantile === 0.1 ? 0.5 : 0.1;
134+
dispatch(EventType.MATCHER_OR_METRIC_CHANGED);
135+
dispatch(EventType.SETTINGS_CHANGED);
136+
}}>
137+
</mwc-switch>
138+
<span title="Display the 10th and 90th percentiles as horizontal error bars">
139+
Show X error bars
140+
</span>
141+
</div>
142+
<div class="settingGroup">
143+
<span title="Do not show vertical error bars">
144+
Hide Y error bars
145+
</span>
146+
<mwc-switch id="settingUseVerticalErrorBars" ?selected=${
147+
!this.state.showRelativeRatios && !this.state.useGeometricMean &&
148+
this.state.verticalQuantile === 0.1}
149+
?disabled=${
150+
this.state.showRelativeRatios ||
151+
this.state.useGeometricMean}
152+
@click=${() => {
153+
this.state.verticalQuantile =
154+
this.state.verticalQuantile === 0.1 ? 0.5 : 0.1;
155+
dispatch(EventType.MATCHER_OR_METRIC_CHANGED);
156+
dispatch(EventType.SETTINGS_CHANGED);
157+
}}>
158+
</mwc-switch>
159+
<span title="Display the 10th and 90th percentiles as vertical error bars">
160+
Show Y error bars
161+
</span>
162+
</div>
121163
<div class="settingGroup">
122164
<span title="Only display the first rows of the filtered or matched data point tables">
123165
Show some rows

src/state.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ export class State {
5454
metrics: FieldMetric[] = [];
5555
plotMetricVertical: FieldMetric|undefined = undefined; // among metrics
5656
plotMetricHorizontal: FieldMetric|undefined = undefined; // among metrics
57-
verticalLogScale = true; // Use a linear scale if false.
58-
horizontalLogScale = false; // Use a linear scale if false.
57+
verticalLogScale = true; // Use a linear scale on the Y axis if false.
58+
horizontalLogScale = false; // Use a linear scale on the X axis if false.
59+
verticalQuantile = 0.5; // Display Y error bars if in [0:0.5[.
60+
horizontalQuantile = 0.5; // Display X error bars if in [0:0.5[.
5961

6062
/**
6163
* If true, each absolute data point or relative match is shown on the plot

0 commit comments

Comments
 (0)