Skip to content

Commit 656d22c

Browse files
authored
HParams: Update scalar card to show columns based on selector (#6405)
## Motivation for features / changes As part of the effort to add hparams into time series we would like to be able to determine the columns to be shown at the selector layer. To that end I have added a new selector which, given a card id, returns the appropriate columns to be shown. ## Screenshots of UI changes (or N/A) Single Selection (its the same) ![image](https://github.com/tensorflow/tensorboard/assets/78179109/52331905-ab11-4f3d-b188-25c1cc696c43) Range Selection (it's also the same) ![image](https://github.com/tensorflow/tensorboard/assets/78179109/1ea9b237-d8d1-41d1-89d5-71ac15ba3438)
1 parent fe3cbf7 commit 656d22c

File tree

5 files changed

+209
-29
lines changed

5 files changed

+209
-29
lines changed

tensorboard/webapp/metrics/store/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ tf_ts_library(
2828
"//tensorboard/webapp/types",
2929
"//tensorboard/webapp/util:dom",
3030
"//tensorboard/webapp/util:lang",
31+
"//tensorboard/webapp/util:memoize",
3132
"//tensorboard/webapp/util:ngrx",
3233
"//tensorboard/webapp/util:types",
3334
"//tensorboard/webapp/widgets/card_fob:types",

tensorboard/webapp/metrics/store/metrics_selectors.ts

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
} from './metrics_types';
4949
import {ColumnHeader, DataTableMode} from '../../widgets/data_table/types';
5050
import {Extent} from '../../widgets/line_chart_v2/lib/public_types';
51+
import {memoize} from '../../util/memoize';
5152

5253
const selectMetricsState =
5354
createFeatureSelector<MetricsState>(METRICS_FEATURE_KEY);
@@ -405,20 +406,6 @@ export const getMetricsStepMinMax = createSelector(
405406
}
406407
);
407408

408-
export const getSingleSelectionHeaders = createSelector(
409-
selectMetricsState,
410-
(state: MetricsState): ColumnHeader[] => {
411-
return state.singleSelectionHeaders;
412-
}
413-
);
414-
415-
export const getRangeSelectionHeaders = createSelector(
416-
selectMetricsState,
417-
(state: MetricsState): ColumnHeader[] => {
418-
return state.rangeSelectionHeaders;
419-
}
420-
);
421-
422409
/**
423410
* Returns value of the linked time set by user. When linked time selection is never
424411
* set, it returns the default value which is derived from the timeseries data
@@ -628,3 +615,30 @@ export const getMetricsCardTimeSelection = createSelector(
628615
);
629616
}
630617
);
618+
619+
export const getSingleSelectionHeaders = createSelector(
620+
selectMetricsState,
621+
(state: MetricsState): ColumnHeader[] => {
622+
return state.singleSelectionHeaders;
623+
}
624+
);
625+
626+
export const getRangeSelectionHeaders = createSelector(
627+
selectMetricsState,
628+
(state: MetricsState): ColumnHeader[] => {
629+
return state.rangeSelectionHeaders;
630+
}
631+
);
632+
633+
export const getColumnHeadersForCard = memoize((cardId: string) => {
634+
return createSelector(
635+
(state) => state,
636+
getSingleSelectionHeaders,
637+
getRangeSelectionHeaders,
638+
(state, singleSelectionHeaders, rangeSelectionHeaders) => {
639+
return getMetricsCardRangeSelectionEnabled(state, cardId)
640+
? rangeSelectionHeaders
641+
: singleSelectionHeaders;
642+
}
643+
);
644+
});

tensorboard/webapp/metrics/store/metrics_selectors_test.ts

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ import {
2626
createTimeSeriesData,
2727
} from '../testing';
2828
import {HistogramMode, TooltipSort, XAxisType} from '../types';
29-
import {DataTableMode} from '../../widgets/data_table/types';
29+
import {
30+
ColumnHeader,
31+
ColumnHeaderType,
32+
DataTableMode,
33+
} from '../../widgets/data_table/types';
3034
import * as selectors from './metrics_selectors';
3135
import {CardFeatureOverride, MetricsState} from './metrics_types';
3236

@@ -1533,4 +1537,170 @@ describe('metrics selectors', () => {
15331537
);
15341538
});
15351539
});
1540+
1541+
describe('getSingleSelectionHeaders', () => {
1542+
it('returns all single selection headers', () => {
1543+
const state = appStateFromMetricsState(
1544+
buildMetricsState({
1545+
singleSelectionHeaders: [
1546+
{
1547+
type: ColumnHeaderType.COLOR,
1548+
name: 'color',
1549+
displayName: 'Color',
1550+
enabled: true,
1551+
},
1552+
{
1553+
type: ColumnHeaderType.RUN,
1554+
name: 'run',
1555+
displayName: 'My Run name',
1556+
enabled: false,
1557+
},
1558+
],
1559+
})
1560+
);
1561+
expect(selectors.getSingleSelectionHeaders(state)).toEqual([
1562+
{
1563+
type: ColumnHeaderType.COLOR,
1564+
name: 'color',
1565+
displayName: 'Color',
1566+
enabled: true,
1567+
},
1568+
{
1569+
type: ColumnHeaderType.RUN,
1570+
name: 'run',
1571+
displayName: 'My Run name',
1572+
enabled: false,
1573+
},
1574+
]);
1575+
});
1576+
});
1577+
1578+
describe('getRangeSelectionHeaders', () => {
1579+
it('returns all range selection headers', () => {
1580+
const state = appStateFromMetricsState(
1581+
buildMetricsState({
1582+
rangeSelectionHeaders: [
1583+
{
1584+
type: ColumnHeaderType.COLOR,
1585+
name: 'color',
1586+
displayName: 'Color',
1587+
enabled: true,
1588+
},
1589+
{
1590+
type: ColumnHeaderType.RUN,
1591+
name: 'run',
1592+
displayName: 'My Run name',
1593+
enabled: false,
1594+
},
1595+
],
1596+
})
1597+
);
1598+
expect(selectors.getRangeSelectionHeaders(state)).toEqual([
1599+
{
1600+
type: ColumnHeaderType.COLOR,
1601+
name: 'color',
1602+
displayName: 'Color',
1603+
enabled: true,
1604+
},
1605+
{
1606+
type: ColumnHeaderType.RUN,
1607+
name: 'run',
1608+
displayName: 'My Run name',
1609+
enabled: false,
1610+
},
1611+
]);
1612+
});
1613+
});
1614+
1615+
describe('getColumnHeadersForCard', () => {
1616+
let singleSelectionHeaders: ColumnHeader[];
1617+
let rangeSelectionHeaders: ColumnHeader[];
1618+
1619+
beforeEach(() => {
1620+
singleSelectionHeaders = [
1621+
{
1622+
type: ColumnHeaderType.COLOR,
1623+
name: 'color',
1624+
displayName: 'Color',
1625+
enabled: true,
1626+
},
1627+
{
1628+
type: ColumnHeaderType.RUN,
1629+
name: 'run',
1630+
displayName: 'My Run name',
1631+
enabled: false,
1632+
},
1633+
];
1634+
rangeSelectionHeaders = [
1635+
{
1636+
type: ColumnHeaderType.MEAN,
1637+
name: 'mean',
1638+
displayName: 'Mean',
1639+
enabled: true,
1640+
},
1641+
];
1642+
});
1643+
1644+
it('returns single selection headers when card range selection is disabled', () => {
1645+
expect(
1646+
selectors.getColumnHeadersForCard('card1')(
1647+
appStateFromMetricsState(
1648+
buildMetricsState({
1649+
singleSelectionHeaders,
1650+
rangeSelectionHeaders,
1651+
})
1652+
)
1653+
)
1654+
).toEqual(singleSelectionHeaders);
1655+
expect(
1656+
selectors.getColumnHeadersForCard('card1')(
1657+
appStateFromMetricsState(
1658+
buildMetricsState({
1659+
singleSelectionHeaders,
1660+
rangeSelectionHeaders,
1661+
cardStateMap: {
1662+
card1: {
1663+
rangeSelectionOverride:
1664+
CardFeatureOverride.OVERRIDE_AS_DISABLED,
1665+
},
1666+
},
1667+
})
1668+
)
1669+
)
1670+
).toEqual(singleSelectionHeaders);
1671+
});
1672+
1673+
it('returns range selection headers when card range selection is enabled', () => {
1674+
expect(
1675+
selectors.getColumnHeadersForCard('card1')(
1676+
appStateFromMetricsState(
1677+
buildMetricsState({
1678+
singleSelectionHeaders,
1679+
rangeSelectionHeaders,
1680+
cardStateMap: {
1681+
card1: {
1682+
rangeSelectionOverride:
1683+
CardFeatureOverride.OVERRIDE_AS_ENABLED,
1684+
},
1685+
},
1686+
})
1687+
)
1688+
)
1689+
).toEqual(rangeSelectionHeaders);
1690+
});
1691+
1692+
it('returns range selection headers when global range selection is enabled', () => {
1693+
expect(
1694+
selectors.getColumnHeadersForCard('card1')(
1695+
appStateFromMetricsState(
1696+
buildMetricsState({
1697+
singleSelectionHeaders,
1698+
rangeSelectionHeaders,
1699+
rangeSelectionEnabled: true,
1700+
})
1701+
)
1702+
)
1703+
).toEqual(rangeSelectionHeaders);
1704+
});
1705+
});
15361706
});

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

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
getRun,
5858
getRunColorMap,
5959
getCurrentRouteRunSelection,
60+
getColumnHeadersForCard,
6061
} from '../../../selectors';
6162
import {DataLoadState} from '../../../types/data';
6263
import {
@@ -89,8 +90,6 @@ import {
8990
getMetricsScalarSmoothing,
9091
getMetricsTooltipSort,
9192
getMetricsXAxisType,
92-
getRangeSelectionHeaders,
93-
getSingleSelectionHeaders,
9493
RunToSeries,
9594
} from '../../store';
9695
import {CardId, CardMetadata, HeaderEditInfo, XAxisType} from '../../types';
@@ -461,18 +460,8 @@ export class ScalarCardContainer implements CardRenderer, OnInit, OnDestroy {
461460
this.cardId
462461
);
463462

464-
this.columnHeaders$ = combineLatest([
465-
this.stepOrLinkedTimeSelection$,
466-
this.store.select(getSingleSelectionHeaders),
467-
this.store.select(getRangeSelectionHeaders),
468-
]).pipe(
469-
map(([timeSelection, singleSelectionHeaders, rangeSelectionHeaders]) => {
470-
if (!timeSelection || timeSelection.end === null) {
471-
return singleSelectionHeaders;
472-
} else {
473-
return rangeSelectionHeaders;
474-
}
475-
})
463+
this.columnHeaders$ = this.store.select(
464+
getColumnHeadersForCard(this.cardId)
476465
);
477466

478467
this.chartMetadataMap$ = partitionedSeries$.pipe(

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2668,6 +2668,8 @@ describe('scalar card', () => {
26682668
describe('getTimeSelectionTableData', () => {
26692669
beforeEach(() => {
26702670
store.overrideSelector(getMetricsLinkedTimeEnabled, true);
2671+
// These tests now rely on the selector getColumnHeadersForCard which in turn
2672+
// relies on these selectors.
26712673
store.overrideSelector(getSingleSelectionHeaders, [
26722674
{
26732675
type: ColumnHeaderType.RUN,
@@ -2880,6 +2882,7 @@ describe('scalar card', () => {
28802882
runToSeries
28812883
);
28822884
store.overrideSelector(getMetricsRangeSelectionEnabled, true);
2885+
store.overrideSelector(getMetricsCardRangeSelectionEnabled, true);
28832886
store.overrideSelector(
28842887
selectors.getCurrentRouteRunSelection,
28852888
new Map([
@@ -2961,6 +2964,7 @@ describe('scalar card', () => {
29612964
runToSeries
29622965
);
29632966
store.overrideSelector(getMetricsRangeSelectionEnabled, true);
2967+
store.overrideSelector(getMetricsCardRangeSelectionEnabled, true);
29642968
store.overrideSelector(
29652969
selectors.getCurrentRouteRunSelection,
29662970
new Map([['run1', true]])
@@ -3026,6 +3030,7 @@ describe('scalar card', () => {
30263030
runToSeries
30273031
);
30283032
store.overrideSelector(getMetricsRangeSelectionEnabled, true);
3033+
store.overrideSelector(getMetricsCardRangeSelectionEnabled, true);
30293034
store.overrideSelector(
30303035
selectors.getCurrentRouteRunSelection,
30313036
new Map([['run1', true]])
@@ -3141,6 +3146,7 @@ describe('scalar card', () => {
31413146
runToSeries
31423147
);
31433148
store.overrideSelector(getMetricsRangeSelectionEnabled, true);
3149+
store.overrideSelector(getMetricsCardRangeSelectionEnabled, true);
31443150
store.overrideSelector(
31453151
selectors.getCurrentRouteRunSelection,
31463152
new Map([

0 commit comments

Comments
 (0)