Skip to content

Commit 6b05c0c

Browse files
JamesHollyerdna2github
authored andcommitted
Refactor: Handle Smoothed column logic in DataTable (tensorflow#6094)
* Motivation for features / changes The smoothed column in the scalar card data table does not render when smoothing is disabled. The logic for removing this column previously occurred in the ScalarCardContainer where it removed the column entirely from the list of headers. This causes some strange behavior which needs to be handled when dealing with changing the order of the columns. This change removes the special treatment of the Smoothed column everywhere except for when it is rendered. * Screenshots of UI changes No changes.
1 parent 4dba5f4 commit 6b05c0c

File tree

8 files changed

+70
-75
lines changed

8 files changed

+70
-75
lines changed

tensorboard/webapp/metrics/store/metrics_reducers.ts

+1-16
Original file line numberDiff line numberDiff line change
@@ -1100,24 +1100,9 @@ const reducer = createReducer(
11001100
};
11011101
}
11021102

1103-
// TODO(@jameshollyer): remove this logic with smoothing refactor *******
1104-
let orderAdjustedForSmoothed = newOrder;
1105-
const newSmoothedColumnIndex = newOrder.indexOf(ColumnHeaders.SMOOTHED);
1106-
const oldSmoothedColumnIndex = state.singleSelectionHeaders.indexOf(
1107-
ColumnHeaders.SMOOTHED
1108-
);
1109-
1110-
if (newSmoothedColumnIndex < 0 && oldSmoothedColumnIndex > 0) {
1111-
orderAdjustedForSmoothed = newOrder
1112-
.slice(0, oldSmoothedColumnIndex)
1113-
.concat([ColumnHeaders.SMOOTHED])
1114-
.concat(newOrder.slice(oldSmoothedColumnIndex, newOrder.length));
1115-
}
1116-
// *********************************************************************
1117-
11181103
return {
11191104
...state,
1120-
singleSelectionHeaders: orderAdjustedForSmoothed,
1105+
singleSelectionHeaders: newOrder,
11211106
};
11221107
}),
11231108
on(actions.metricsToggleVisiblePlugin, (state, {plugin}) => {

tensorboard/webapp/metrics/views/card_renderer/scalar_card_component.ng.html

+1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
[dataHeaders]="dataHeaders"
179179
[sortingInfo]="sortingInfo"
180180
[columnCustomizationEnabled]="columnCustomizationEnabled"
181+
[smoothingEnabled]="smoothingEnabled"
181182
(sortDataBy)="sortDataBy($event)"
182183
(orderColumns)="reorderColumnHeaders.emit($event)"
183184
>

tensorboard/webapp/metrics/views/card_renderer/scalar_card_container.ts

+6-23
Original file line numberDiff line numberDiff line change
@@ -492,34 +492,17 @@ export class ScalarCardContainer implements CardRenderer, OnInit, OnDestroy {
492492
);
493493

494494
this.columnHeaders$ = combineLatest([
495-
this.smoothingEnabled$,
496495
this.stepOrLinkedTimeSelection$,
497496
this.store.select(getSingleSelectionHeaders),
498497
this.store.select(getRangeSelectionHeaders),
499498
]).pipe(
500-
map(
501-
([
502-
smoothingEnabled,
503-
timeSelection,
504-
singleSelectionHeaders,
505-
rangeSelectionHeaders,
506-
]) => {
507-
if (timeSelection === null || timeSelection.end === null) {
508-
if (!smoothingEnabled) {
509-
// Return single selection headers without smoothed header.
510-
const indexOfSmoothed = singleSelectionHeaders.indexOf(
511-
ColumnHeaders.SMOOTHED
512-
);
513-
return singleSelectionHeaders
514-
.slice(0, indexOfSmoothed)
515-
.concat(singleSelectionHeaders.slice(indexOfSmoothed + 1));
516-
}
517-
return singleSelectionHeaders;
518-
} else {
519-
return rangeSelectionHeaders;
520-
}
499+
map(([timeSelection, singleSelectionHeaders, rangeSelectionHeaders]) => {
500+
if (timeSelection === null || timeSelection.end === null) {
501+
return singleSelectionHeaders;
502+
} else {
503+
return rangeSelectionHeaders;
521504
}
522-
)
505+
})
523506
);
524507

525508
this.chartMetadataMap$ = partitionedSeries$.pipe(

tensorboard/webapp/metrics/views/card_renderer/scalar_card_data_table.ts

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
[data]="getTimeSelectionTableData()"
4040
[sortingInfo]="sortingInfo"
4141
[columnCustomizationEnabled]="columnCustomizationEnabled"
42+
[smoothingEnabled]="smoothingEnabled"
4243
(sortDataBy)="sortDataBy.emit($event)"
4344
(orderColumns)="orderColumns.emit($event)"
4445
></tb-data-table>
@@ -52,6 +53,7 @@ export class ScalarCardDataTable {
5253
@Input() dataHeaders!: ColumnHeaders[];
5354
@Input() sortingInfo!: SortingInfo;
5455
@Input() columnCustomizationEnabled!: boolean;
56+
@Input() smoothingEnabled!: boolean;
5557

5658
@Output() sortDataBy = new EventEmitter<SortingInfo>();
5759
@Output() orderColumns = new EventEmitter<ColumnHeaders[]>();

tensorboard/webapp/metrics/views/card_renderer/scalar_card_test.ts

+3-34
Original file line numberDiff line numberDiff line change
@@ -2628,6 +2628,7 @@ describe('scalar card', () => {
26282628
RUN: 'run1',
26292629
STEP: 2,
26302630
VALUE: 10,
2631+
SMOOTHED: 10,
26312632
},
26322633
{
26332634
id: 'run2',
@@ -2636,6 +2637,7 @@ describe('scalar card', () => {
26362637
RUN: 'run2',
26372638
STEP: 2,
26382639
VALUE: 10,
2640+
SMOOTHED: 10,
26392641
},
26402642
]);
26412643
}));
@@ -3011,7 +3013,7 @@ describe('scalar card', () => {
30113013
expect(data[1].RUN).toEqual('200 test alias 2/Run2 name');
30123014
}));
30133015

3014-
it('adds smoothed column header when smoothed is enabled', fakeAsync(() => {
3016+
it('edits smoothed value when smoothed is enabled', fakeAsync(() => {
30153017
store.overrideSelector(selectors.getMetricsScalarSmoothing, 0.8);
30163018

30173019
const runToSeries = {
@@ -3053,39 +3055,6 @@ describe('scalar card', () => {
30533055
).toBe(6.000000000000001);
30543056
}));
30553057

3056-
it('does not add smoothed column header when smoothed is disabled', fakeAsync(() => {
3057-
store.overrideSelector(selectors.getMetricsScalarSmoothing, 0);
3058-
3059-
const runToSeries = {
3060-
run1: [{wallTime: 1, value: 1, step: 10}],
3061-
};
3062-
provideMockCardRunToSeriesData(
3063-
selectSpy,
3064-
PluginType.SCALARS,
3065-
'card1',
3066-
null /* metadataOverride */,
3067-
runToSeries
3068-
);
3069-
store.overrideSelector(
3070-
selectors.getCurrentRouteRunSelection,
3071-
new Map([['run1', true]])
3072-
);
3073-
store.overrideSelector(getMetricsLinkedTimeSelection, {
3074-
start: {step: 20},
3075-
end: null,
3076-
});
3077-
3078-
const fixture = createComponent('card1');
3079-
fixture.detectChanges();
3080-
const scalarCardDataTable = fixture.debugElement.query(
3081-
By.directive(ScalarCardDataTable)
3082-
);
3083-
3084-
expect(scalarCardDataTable.componentInstance.dataHeaders).not.toContain(
3085-
ColumnHeaders.SMOOTHED
3086-
);
3087-
}));
3088-
30893058
it('orders data ascending', fakeAsync(() => {
30903059
const runToSeries = {
30913060
run1: [{wallTime: 1, value: 2, step: 1}],

tensorboard/webapp/widgets/data_table/data_table_component.ng.html

+8-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
<!-- This header is intentionally left blank for the color column -->
2121
</th>
2222
<ng-container *ngFor="let header of headers;">
23-
<th (click)="headerClicked(header)">
23+
<th
24+
*ngIf="smoothingEnabled || header !== ColumnHeaders.SMOOTHED"
25+
(click)="headerClicked(header)"
26+
>
2427
<div
2528
[draggable]="columnCustomizationEnabled"
2629
(dragstart)="dragStart(header)"
@@ -67,7 +70,10 @@
6770
<span [style.backgroundColor]="runData.COLOR"></span>
6871
</td>
6972
<ng-container *ngFor="let header of headers;">
70-
<td [ngSwitch]="header">
73+
<td
74+
*ngIf="smoothingEnabled || header !== ColumnHeaders.SMOOTHED"
75+
[ngSwitch]="header"
76+
>
7177
<div *ngSwitchCase="ColumnHeaders.VALUE_CHANGE" class="cell">
7278
<ng-container
7379
*ngTemplateOutlet="arrow; context: {$implicit:runData.VALUE_CHANGE}"

tensorboard/webapp/widgets/data_table/data_table_component.ts

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export class DataTableComponent implements OnDestroy {
5555
@Input() data!: SelectedStepRunData[];
5656
@Input() sortingInfo!: SortingInfo;
5757
@Input() columnCustomizationEnabled!: boolean;
58+
@Input() smoothingEnabled!: boolean;
5859

5960
@Output() sortDataBy = new EventEmitter<SortingInfo>();
6061
@Output() orderColumns = new EventEmitter<ColumnHeaders[]>();

tensorboard/webapp/widgets/data_table/data_table_test.ts

+48
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {DataTableComponent} from './data_table_component';
3333
[headers]="headers"
3434
[data]="data"
3535
[sortingInfo]="sortingInfo"
36+
[smoothingEnabled]="smoothingEnabled"
3637
(sortDataBy)="sortDataBy($event)"
3738
(orderColumns)="orderColumns($event)"
3839
></tb-data-table>
@@ -45,6 +46,7 @@ class TestableComponent {
4546
@Input() headers!: ColumnHeaders[];
4647
@Input() data!: SelectedStepRunData[];
4748
@Input() sortingInfo!: SortingInfo;
49+
@Input() smoothingEnabled!: boolean;
4850

4951
@Input() sortDataBy!: (sortingInfo: SortingInfo) => void;
5052
@Input() orderColumns!: (newOrder: ColumnHeaders[]) => void;
@@ -64,6 +66,7 @@ describe('data table', () => {
6466
headers?: ColumnHeaders[];
6567
data?: SelectedStepRunData[];
6668
sortingInfo?: SortingInfo;
69+
smoothingEnabled?: boolean;
6770
}): ComponentFixture<TestableComponent> {
6871
const fixture = TestBed.createComponent(TestableComponent);
6972

@@ -74,6 +77,9 @@ describe('data table', () => {
7477
order: SortingOrder.ASCENDING,
7578
};
7679

80+
fixture.componentInstance.smoothingEnabled =
81+
input.smoothingEnabled === undefined ? true : input.smoothingEnabled;
82+
7783
sortDataBySpy = jasmine.createSpy();
7884
fixture.componentInstance.sortDataBy = sortDataBySpy;
7985

@@ -105,6 +111,7 @@ describe('data table', () => {
105111
ColumnHeaders.MIN_VALUE,
106112
ColumnHeaders.MAX_VALUE,
107113
ColumnHeaders.PERCENTAGE_CHANGE,
114+
ColumnHeaders.SMOOTHED,
108115
],
109116
});
110117
fixture.detectChanges();
@@ -134,6 +141,7 @@ describe('data table', () => {
134141
.queryAll(By.css('mat-icon'))[0]
135142
.nativeElement.getAttribute('svgIcon')
136143
).toBe('change_history_24px');
144+
expect(headerElements[13].nativeElement.innerText).toBe('Smoothed');
137145
});
138146

139147
it('displays data in order', () => {
@@ -151,6 +159,7 @@ describe('data table', () => {
151159
ColumnHeaders.MIN_VALUE,
152160
ColumnHeaders.MAX_VALUE,
153161
ColumnHeaders.PERCENTAGE_CHANGE,
162+
ColumnHeaders.SMOOTHED,
154163
],
155164
data: [
156165
{
@@ -167,6 +176,7 @@ describe('data table', () => {
167176
MIN_VALUE: 1,
168177
MAX_VALUE: 500,
169178
PERCENTAGE_CHANGE: 0.3,
179+
SMOOTHED: 2,
170180
},
171181
],
172182
});
@@ -199,6 +209,7 @@ describe('data table', () => {
199209
.queryAll(By.css('mat-icon'))[0]
200210
.nativeElement.getAttribute('svgIcon')
201211
).toBe('arrow_upward_24px');
212+
expect(dataElements[13].nativeElement.innerText).toBe('2');
202213
});
203214

204215
it('displays nothing when no data is available', () => {
@@ -400,4 +411,41 @@ describe('data table', () => {
400411
ColumnHeaders.RUN,
401412
]);
402413
});
414+
415+
it('does not display Smoothed column when smoothingEnabled is false', () => {
416+
const fixture = createComponent({
417+
headers: [
418+
ColumnHeaders.VALUE,
419+
ColumnHeaders.RUN,
420+
ColumnHeaders.SMOOTHED,
421+
ColumnHeaders.STEP,
422+
],
423+
data: [
424+
{
425+
id: 'someid',
426+
RUN: 'run name',
427+
VALUE: 3,
428+
STEP: 1,
429+
SMOOTHED: 2,
430+
},
431+
],
432+
smoothingEnabled: false,
433+
});
434+
fixture.detectChanges();
435+
const headerElements = fixture.debugElement.queryAll(By.css('th'));
436+
const dataElements = fixture.debugElement.queryAll(By.css('td'));
437+
438+
// The first header should always be blank as it is the run color column.
439+
expect(headerElements[0].nativeElement.innerText).toBe('');
440+
expect(headerElements[1].nativeElement.innerText).toBe('Value');
441+
expect(headerElements[2].nativeElement.innerText).toBe('Run');
442+
expect(headerElements[3].nativeElement.innerText).toBe('Step');
443+
expect(headerElements.length).toBe(4);
444+
445+
expect(dataElements[0].nativeElement.innerText).toBe('');
446+
expect(dataElements[1].nativeElement.innerText).toBe('3');
447+
expect(dataElements[2].nativeElement.innerText).toBe('run name');
448+
expect(dataElements[3].nativeElement.innerText).toBe('1');
449+
expect(dataElements.length).toBe(4);
450+
});
403451
});

0 commit comments

Comments
 (0)