Skip to content

Commit acf1cb9

Browse files
authored
Hparams: Show 'differs' tag in selector if hparam has differing value (#6779)
Shows a 'differs' tag in the data table column selector if an hparam has multiple values. We start by adding generic support to the data table column selector for "tags". Tags can be arbitrary strings. Then, for each Hparam column, we calculate whether to include a 'differs' tag. Light mode: ![image](https://github.com/tensorflow/tensorboard/assets/17152369/7c8110cd-ac9f-48e5-97f1-ff4c1b5bf8d4) Dark mode: ![image](https://github.com/tensorflow/tensorboard/assets/17152369/59b3af5d-6990-483b-8a05-4c27c0c37182) Internal Light mode: ![image](https://github.com/tensorflow/tensorboard/assets/17152369/1ada0711-724a-4e2a-80ab-452bc1f8cd02) Internal Dark mode: ![image](https://github.com/tensorflow/tensorboard/assets/17152369/48c0321d-4db7-4244-b7b0-6fb249539d69)
1 parent da812d2 commit acf1cb9

File tree

9 files changed

+55
-6
lines changed

9 files changed

+55
-6
lines changed

tensorboard/webapp/hparams/_redux/hparams_data_source_test.ts

+8
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ describe('HparamsDataSource Test', () => {
8282
minValue: -100,
8383
maxValue: 100,
8484
},
85+
differs: true,
8586
},
8687
{
8788
description: 'describes hparams two',
@@ -92,6 +93,7 @@ describe('HparamsDataSource Test', () => {
9293
type: DomainType.DISCRETE,
9394
values: ['foo', 'bar', 'baz'],
9495
},
96+
differs: true,
9597
},
9698
]);
9799
});
@@ -112,6 +114,7 @@ describe('HparamsDataSource Test', () => {
112114
type: DomainType.DISCRETE,
113115
values: [],
114116
},
117+
differs: false,
115118
},
116119
{
117120
description: 'describes hparams two',
@@ -122,6 +125,7 @@ describe('HparamsDataSource Test', () => {
122125
type: DomainType.DISCRETE,
123126
values: ['foo', 'bar', 'baz'],
124127
},
128+
differs: true,
125129
},
126130
]);
127131
});
@@ -321,13 +325,15 @@ export function createHparamsExperimentResponse(): BackendHparamsExperimentRespo
321325
name: 'hparams1',
322326
type: BackendHparamsValueType.DATA_TYPE_STRING,
323327
domainInterval: {minValue: -100, maxValue: 100},
328+
differs: true,
324329
},
325330
{
326331
description: 'describes hparams two',
327332
displayName: 'hparams two',
328333
name: 'hparams2',
329334
type: BackendHparamsValueType.DATA_TYPE_BOOL,
330335
domainDiscrete: ['foo', 'bar', 'baz'],
336+
differs: true,
331337
},
332338
],
333339
metricInfos: [],
@@ -346,13 +352,15 @@ export function createHparamsExperimentNoDomainResponse(): BackendHparamsExperim
346352
displayName: 'hparams one',
347353
name: 'hparams1',
348354
type: BackendHparamsValueType.DATA_TYPE_STRING,
355+
differs: false,
349356
} as BackendHparamSpec,
350357
{
351358
description: 'describes hparams two',
352359
displayName: 'hparams two',
353360
name: 'hparams2',
354361
type: BackendHparamsValueType.DATA_TYPE_BOOL,
355362
domainDiscrete: ['foo', 'bar', 'baz'],
363+
differs: true,
356364
},
357365
],
358366
metricInfos: [],

tensorboard/webapp/hparams/_redux/testing.ts

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export function buildHparamSpec(
5757
domain: {type: DomainType.INTERVAL, minValue: 0, maxValue: 1},
5858
name: 'sample_param',
5959
type: HparamsValueType.DATA_TYPE_FLOAT64,
60+
differs: false,
6061
...override,
6162
};
6263
}

tensorboard/webapp/metrics/views/main_view/common_selectors.ts

+1
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ export const getPotentialHparamColumns = createSelector(
284284
// be displayed tensorboard/plugins/hparams/api.proto
285285
displayName: hparamSpec.displayName || hparamSpec.name,
286286
enabled: false,
287+
tags: hparamSpec.differs ? ['differs'] : [],
287288
removable: true,
288289
sortable: true,
289290
movable: true,

tensorboard/webapp/metrics/views/main_view/common_selectors_test.ts

+15-6
Original file line numberDiff line numberDiff line change
@@ -1008,12 +1008,13 @@ describe('common selectors', () => {
10081008
});
10091009

10101010
describe('getPotentialHparamColumns', () => {
1011-
const expectedBooleanFlags = {
1011+
const expectedCommonProperties = {
10121012
enabled: false,
10131013
removable: true,
10141014
sortable: true,
10151015
movable: true,
10161016
filterable: true,
1017+
tags: [],
10171018
};
10181019

10191020
it('returns empty list when there are no experiments', () => {
@@ -1028,25 +1029,25 @@ describe('common selectors', () => {
10281029
type: ColumnHeaderType.HPARAM,
10291030
name: 'conv_layers',
10301031
displayName: 'Conv Layers',
1031-
...expectedBooleanFlags,
1032+
...expectedCommonProperties,
10321033
},
10331034
{
10341035
type: ColumnHeaderType.HPARAM,
10351036
name: 'conv_kernel_size',
10361037
displayName: 'Conv Kernel Size',
1037-
...expectedBooleanFlags,
1038+
...expectedCommonProperties,
10381039
},
10391040
{
10401041
type: ColumnHeaderType.HPARAM,
10411042
name: 'dense_layers',
10421043
displayName: 'Dense Layers',
1043-
...expectedBooleanFlags,
1044+
...expectedCommonProperties,
10441045
},
10451046
{
10461047
type: ColumnHeaderType.HPARAM,
10471048
name: 'dropout',
10481049
displayName: 'Dropout',
1049-
...expectedBooleanFlags,
1050+
...expectedCommonProperties,
10501051
},
10511052
]);
10521053
});
@@ -1061,10 +1062,18 @@ describe('common selectors', () => {
10611062
type: ColumnHeaderType.HPARAM,
10621063
name: 'conv_layers',
10631064
displayName: 'conv_layers',
1064-
...expectedBooleanFlags,
1065+
...expectedCommonProperties,
10651066
},
10661067
]);
10671068
});
1069+
1070+
it('sets differs tag', () => {
1071+
state.hparams!.dashboardHparamSpecs = [buildHparamSpec({differs: true})];
1072+
1073+
expect(selectors.getPotentialHparamColumns(state)[0].tags).toEqual([
1074+
'differs',
1075+
]);
1076+
});
10681077
});
10691078

10701079
describe('getSelectableColumns', () => {

tensorboard/webapp/runs/data_source/runs_backend_types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ interface BaseHparamSpec {
5454
displayName: string;
5555
name: string;
5656
type: BackendHparamsValueType;
57+
differs: boolean;
5758
}
5859

5960
export interface IntervalDomainHparamSpec extends BaseHparamSpec {

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

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
[matTooltipDisabled]="column.name.localeCompare(column.displayName, undefined, {sensitivity: 'accent'}) === 0"
4949
>
5050
{{column.displayName}}
51+
<span *ngFor="let tag of column.tags" class="tag"> {{ tag }} </span>
5152
</button>
5253
</div>
5354
</div>

tensorboard/webapp/widgets/data_table/column_selector_component.scss

+9
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,13 @@ limitations under the License.
8787
}
8888
}
8989
}
90+
91+
.tag {
92+
background-color: mat.get-color-from-palette($tb-primary, 500);
93+
border-radius: 8px;
94+
font-size: 12px;
95+
font-style: italic;
96+
font-weight: normal;
97+
padding: 4px;
98+
}
9099
}

tensorboard/webapp/widgets/data_table/column_selector_test.ts

+18
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,24 @@ describe('column selector', () => {
212212
expect(selectedColumn!.name).toEqual('runs');
213213
}));
214214

215+
it('renders tags', () => {
216+
fixture.componentInstance.selectableColumns = [
217+
{
218+
type: ColumnHeaderType.HPARAM,
219+
name: 'lr',
220+
displayName: 'Learning Rate',
221+
enabled: true,
222+
tags: ['tag1', 'tag2'],
223+
},
224+
];
225+
fixture.detectChanges();
226+
227+
const tagEls = fixture.debugElement.queryAll(By.css('.tag'));
228+
expect(tagEls.length).toEqual(2);
229+
expect(tagEls[0].nativeElement.textContent.trim()).toEqual('tag1');
230+
expect(tagEls[1].nativeElement.textContent.trim()).toEqual('tag2');
231+
});
232+
215233
it('renders number of loaded columns', fakeAsync(() => {
216234
fixture.componentInstance.numColumnsLoaded = 100;
217235
fixture.detectChanges();

tensorboard/webapp/widgets/data_table/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export declare interface ColumnHeader {
8080
name: string;
8181
displayName: string;
8282
enabled: boolean;
83+
tags?: string[];
8384

8485
// Default to false when not specified.
8586
removable?: boolean;

0 commit comments

Comments
 (0)