Skip to content

Commit a5f87e4

Browse files
author
Anuar Talipov
committed
Add a color by regex feature that matches the experiment name.
1 parent d73e213 commit a5f87e4

17 files changed

+433
-91
lines changed

tensorboard/webapp/angular/BUILD

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,15 @@ tf_ts_library(
132132
],
133133
)
134134

135+
# This is a dummy rule used as a @angular/material/chips dependency.
136+
tf_ts_library(
137+
name = "expect_angular_material_core",
138+
srcs = [],
139+
deps = [
140+
"@npm//@angular/material",
141+
],
142+
)
143+
135144
# This is a dummy rule used as a @angular/material/dialog dependency.
136145
tf_ts_library(
137146
name = "expect_angular_material_dialog",

tensorboard/webapp/runs/actions/runs_actions.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,11 @@ export const runColorChanged = createAction(
7777
props<{runId: string; newColor: string}>()
7878
);
7979

80-
export const runGroupByChanged = createAction(
81-
'[Runs] Run Group By Changed',
82-
props<{experimentIds: string[]; groupBy: GroupBy}>()
83-
);
80+
export const runGroupByChanged =
81+
createAction('[Runs] Run Group By Changed', props<{
82+
experimentIds: string[]; groupBy: GroupBy;
83+
expNameByExpId?: Record<string, string>
84+
}>());
8485

8586
/**
8687
* Inserts the provided column header at the specified index.

tensorboard/webapp/runs/store/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ tf_ts_library(
6464
],
6565
deps = [
6666
"//tensorboard/webapp/app_routing:namespaced_state_reducer_helper",
67+
"//tensorboard/webapp/experiments:types",
6768
"//tensorboard/webapp/runs:types",
6869
"//tensorboard/webapp/runs/data_source",
6970
"//tensorboard/webapp/types",

tensorboard/webapp/runs/store/runs_reducers.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ const dataReducer: ActionReducer<RunsDataState, Action> = createReducer(
118118
let {colorGroupRegexString, userSetGroupByKey} = state;
119119
if (groupBy) {
120120
const regexString =
121-
groupBy.key === GroupByKey.REGEX
121+
groupBy.key === GroupByKey.REGEX || groupBy.key === GroupByKey.REGEX_BY_EXP
122122
? groupBy.regexString
123123
: state.colorGroupRegexString;
124124
colorGroupRegexString = regexString;
@@ -244,7 +244,7 @@ const dataReducer: ActionReducer<RunsDataState, Action> = createReducer(
244244
}),
245245
on(
246246
runsActions.runGroupByChanged,
247-
(state: RunsDataState, {experimentIds, groupBy}): RunsDataState => {
247+
(state: RunsDataState, {experimentIds, groupBy, expNameByExpId}): RunsDataState => {
248248
// Reset the groupKeyToColorId
249249
const groupKeyToColorId = new Map<string, number>();
250250
const defaultRunColorIdForGroupBy = new Map(
@@ -255,7 +255,8 @@ const dataReducer: ActionReducer<RunsDataState, Action> = createReducer(
255255
.flatMap((experimentId) => state.runIds[experimentId])
256256
.map((runId) => state.runMetadata[runId]);
257257

258-
const groups = groupRuns(groupBy, allRuns, state.runIdToExpId);
258+
const groups =
259+
groupRuns(groupBy, allRuns, state.runIdToExpId, expNameByExpId);
259260

260261
Object.entries(groups.matches).forEach(([groupId, runs]) => {
261262
const colorId =
@@ -272,10 +273,10 @@ const dataReducer: ActionReducer<RunsDataState, Action> = createReducer(
272273
defaultRunColorIdForGroupBy.set(run.id, -1);
273274
}
274275

275-
const updatedRegexString =
276-
groupBy.key === GroupByKey.REGEX
277-
? groupBy.regexString
278-
: state.colorGroupRegexString;
276+
const updatedRegexString = (groupBy.key === GroupByKey.REGEX ||
277+
groupBy.key === GroupByKey.REGEX_BY_EXP) ?
278+
groupBy.regexString :
279+
state.colorGroupRegexString;
279280

280281
return {
281282
...state,

tensorboard/webapp/runs/store/runs_reducers_test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,10 @@ describe('runs_reducers', () => {
358358
])
359359
);
360360
});
361+
362+
it('assigns non-matched colors to regex non-matched runs', () => {
363+
// TODO(anuartb@): Make test for reducer.
364+
});
361365
});
362366

363367
it('auto-selects new runs if total num <= N', () => {
@@ -916,6 +920,8 @@ describe('runs_reducers', () => {
916920
expect(nextState.data.colorGroupRegexString).toBe('foo(\\d+)');
917921
});
918922

923+
it('reassigns color to REGEX from RUN', () => {});
924+
919925
it('preserves regexString when reassigning color to RUN from REGEX', () => {
920926
const state = buildRunsState({
921927
initialGroupBy: {key: GroupByKey.RUN},
@@ -976,6 +982,8 @@ describe('runs_reducers', () => {
976982
);
977983
expect(state4.data.colorGroupRegexString).toBe('updated regexString');
978984
});
985+
986+
it('preserves experiment regexString when reassigning color to RUN from REGEX', () => {});
979987
});
980988

981989
describe('#stateRehydratedFromUrl', () => {

tensorboard/webapp/runs/store/utils.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@ See the License for the specific language governing permissions and
1313
limitations under the License.
1414
==============================================================================*/
1515
import {GroupBy, GroupByKey, Run, RunGroup} from '../types';
16+
1617
import {ExperimentId, RunId} from './runs_types';
1718

1819
export function groupRuns(
19-
groupBy: GroupBy,
20-
runs: Run[],
21-
runIdToExpId: Readonly<Record<RunId, ExperimentId>>
22-
): RunGroup {
20+
groupBy: GroupBy, runs: Run[],
21+
runIdToExpId: Readonly<Record<RunId, ExperimentId>>,
22+
expNameByExpId?: Record<string, string>): RunGroup {
2323
const matches: {[id: string]: Run[]} = {};
2424
const nonMatches: Run[] = [];
2525
const runGroup: RunGroup = {matches, nonMatches};
26+
let regExp: RegExp;
2627

2728
switch (groupBy.key) {
2829
case GroupByKey.RUN:
@@ -44,7 +45,6 @@ export function groupRuns(
4445
//TODO(japie1235813): propagate invalidity of regex string to user more gracefully
4546
break;
4647
}
47-
let regExp: RegExp;
4848

4949
// TODO(japie1235813): add additonal `\` to convert string to regex, which
5050
// makes `new RegExp()` construct properly
@@ -73,7 +73,38 @@ export function groupRuns(
7373
}
7474
}
7575
break;
76+
77+
case GroupByKey.REGEX_BY_EXP:
78+
if (!groupBy.regexString || !expNameByExpId) {
79+
break;
80+
}
81+
82+
try {
83+
regExp = new RegExp(groupBy.regexString);
84+
} catch (e) {
85+
break;
86+
}
87+
88+
for (const run of runs) {
89+
// Tries to match against experiment alias of the run.
90+
const experimentName = expNameByExpId[runIdToExpId[run.id]];
91+
const matchesList = experimentName.match(regExp);
92+
if (matchesList) {
93+
const hasCapturingGroup = matchesList.length > 1;
94+
// In case regex string does not have a capturing group, we use pseudo
95+
// group id of `pseudo_group`.
96+
const id = hasCapturingGroup ? JSON.stringify(matchesList.slice(1)) :
97+
'pseudo_group';
98+
const runs = matches[id] || [];
99+
runs.push(run);
100+
matches[id] = runs;
101+
} else {
102+
nonMatches.push(run);
103+
}
104+
}
105+
break;
76106
default:
107+
break;
77108
}
78109
return runGroup;
79110
}
@@ -82,11 +113,12 @@ export function groupRuns(
82113
* Util function for composing `GroupBy` key and regex string.
83114
*/
84115
export function createGroupBy(
85-
groupByKey: GroupByKey,
116+
groupByKey: GroupByKey,
86117
regexString?: string
87118
): GroupBy {
88119
switch (groupByKey) {
89120
case GroupByKey.REGEX:
121+
case GroupByKey.REGEX_BY_EXP:
90122
return {key: groupByKey, regexString: regexString ?? ''};
91123
case GroupByKey.RUN:
92124
case GroupByKey.EXPERIMENT:

0 commit comments

Comments
 (0)