Skip to content

Commit 4d64e50

Browse files
authored
Let user know which tags are missing per run (tensorflow#967)
Some early users of margin plots noticed a bug. If data associated with a tag for any run was missing, an error message appeared noting that data was missing for that tag. The error message gave no indication of which runs were missing information. Sometimes, the behavior is intended. For instance, some run might not log a certain scalar value. This change now offers users a more nuanced message when margin plot logic is missing information for certain tags within a run. The message notes specific runs and then lists the specific tags without data for those runs. The message is placed under a collapsible so that the user can chose to not see the message if the behavior is intended. Messages are only shown if a run is missing data for some but not all tags.
1 parent e48165c commit 4d64e50

File tree

1 file changed

+85
-30
lines changed

1 file changed

+85
-30
lines changed

tensorboard/plugins/custom_scalar/tf_custom_scalar_dashboard/tf-custom-scalar-margin-chart-card.html

Lines changed: 85 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -99,31 +99,47 @@ <h1>[[_titleDisplayString]]</h1>
9999
</template>
100100
</div>
101101

102-
<template is="dom-if" if="[[_tagsWithNoData]]">
103-
<div id="error-content">
104-
<iron-icon class="error-icon" icon="icons:error"></iron-icon>
105-
No data found for these tags:
106-
<ul>
107-
<template is="dom-repeat" items="[[_tagsWithNoData]]">
108-
<li>[[item]]</li>
109-
</template>
110-
</ul>
111-
<br>
112-
Tags for the value, lower, and upper bounds of margin charts in the Layout
113-
proto must match tags in the SCALARS dashboard.
102+
<!-- here -->
103+
<template is="dom-if" if="[[_missingTags.length]]">
104+
<div class="collapsible-list-title">
105+
<paper-icon-button
106+
icon="[[_getToggleCollapsibleIcon(_missingTagsCollapsibleOpened)]]"
107+
on-click="_toggleMissingTagsCollapsibleOpen"
108+
class="toggle-collapsible-button">
109+
</paper-icon-button>
110+
<span class="collapsible-title-text">
111+
<iron-icon icon="icons:error"></iron-icon> Missing Tags
112+
</span>
114113
</div>
114+
<iron-collapse opened="[[_missingTagsCollapsibleOpened]]">
115+
<div class="error-content">
116+
<iron-icon class="error-icon" icon="icons:error"></iron-icon>
117+
<template is="dom-repeat"
118+
items="[[_missingTags]]"
119+
as="missingEntry">
120+
<div class="missing-tags-for-run-container">
121+
Run "[[missingEntry.run]]" lacks data for tags
122+
<ul>
123+
<template is="dom-repeat" items="[[missingEntry.tags]]" as="tag">
124+
<li>[[tag]]</li>
125+
</template>
126+
</ul>
127+
</div>
128+
</template>
129+
</div>
130+
</iron-collapse>
115131
</template>
116132

117133
<template is="dom-if" if="[[_tagFilterInvalid]]">
118-
<div id="error-content">
134+
<div class="error-content">
119135
<iron-icon class="error-icon" icon="icons:error"></iron-icon>
120136
This regular expresion is invalid:<br>
121137
<span class="invalid-regex">[[_tagFilter]]</span>
122138
</div>
123139
</template>
124140

125141
<template is="dom-if" if="[[_stepsMismatch]]">
126-
<div id="error-content">
142+
<div class="error-content">
127143
<iron-icon class="error-icon" icon="icons:error"></iron-icon>
128144
The steps for value, lower, and upper tags do not match:
129145
<ul>
@@ -144,16 +160,16 @@ <h1>[[_titleDisplayString]]</h1>
144160
</template>
145161

146162
<div id="matches-container">
147-
<div id="matches-list-title">
163+
<div class="collapsible-list-title">
148164
<template is="dom-if" if="[[_dataSeriesStrings.length]]">
149165
<paper-icon-button
150-
icon="[[_getToggleMatchesIcon(_matchesListOpened)]]"
166+
icon="[[_getToggleCollapsibleIcon(_matchesListOpened)]]"
151167
on-click="_toggleMatchesOpen"
152168
class="toggle-matches-button">
153169
</paper-icon-button>
154170
</template>
155171

156-
<span class="matches-text">
172+
<span class="collapsible-title-text">
157173
Matches ([[_dataSeriesStrings.length]])
158174
</span>
159175
</div>
@@ -179,7 +195,7 @@ <h1>[[_titleDisplayString]]</h1>
179195
</div>
180196
<style include="tf-custom-scalar-card-style"></style>
181197
<style>
182-
#error-content {
198+
.error-content {
183199
background: #f00;
184200
border-radius: 5px;
185201
color: #fff;
@@ -197,7 +213,7 @@ <h1>[[_titleDisplayString]]</h1>
197213
font-weight: bold;
198214
}
199215

200-
#error-content ul {
216+
.error-content ul {
201217
margin: 1px 0 0 0;
202218
padding: 0 0 0 19px;
203219
}
@@ -206,10 +222,14 @@ <h1>[[_titleDisplayString]]</h1>
206222
font-weight: bold;
207223
}
208224

209-
#matches-list-title {
225+
.collapsible-list-title {
210226
margin: 10px 0 5px 0;
211227
}
212228

229+
.collapsible-title-text {
230+
vertical-align: middle;
231+
}
232+
213233
#matches-list {
214234
font-size: 0.8em;
215235
max-height: 200px;
@@ -226,8 +246,8 @@ <h1>[[_titleDisplayString]]</h1>
226246
width: 10px;
227247
}
228248

229-
.matches-text {
230-
vertical-align: middle;
249+
.missing-tags-for-run-container {
250+
margin: 8px 0 0 0;
231251
}
232252
</style>
233253
</template>
@@ -381,7 +401,22 @@ <h1>[[_titleDisplayString]]</h1>
381401
];
382402
}
383403
},
384-
_tagsWithNoData: String,
404+
/**
405+
* A list of objects encapsulating missing tags. Each object within this
406+
* list has the following properties:
407+
* run: A string denoting the relevant run.
408+
* tags: A non-empty list of tags (strings) missing for that run.
409+
* A run only has an entry in this list if some (but not all) of its 3
410+
* tags (value, lower, upper) are missing.
411+
*/
412+
_missingTags: {
413+
type: Array,
414+
value: [],
415+
},
416+
_missingTagsCollapsibleOpened: {
417+
type: Boolean,
418+
value: false,
419+
},
385420
/**
386421
* This field is only set if data retrieved from the server exhibits a
387422
* step mismatch: if the lists of values, lower bounds, and upper bounds
@@ -517,13 +552,28 @@ <h1>[[_titleDisplayString]]</h1>
517552
run, tagsObject.value, seriesName, dataPoints);
518553
}
519554
});
555+
this.set('_nameToDataSeries', newMapping);
520556

521-
if (tagsNotFound.length) {
522-
// At least 1 tag could not be found. Show an error message.
523-
this.set('_tagsWithNoData', tagsNotFound);
557+
const entryIndex = _.findIndex(this._missingTags, (entry) => {
558+
return entry.run === run;
559+
});
560+
if (tagsNotFound.length && tagsNotFound.length != 3) {
561+
// Some but not all tags were found. Show a warning message.
562+
const entry = {
563+
run: run,
564+
tags: tagsNotFound,
565+
};
566+
if (entryIndex >= 0) {
567+
// Remove the previous entry. Insert the new one.
568+
this.splice('_missingTags', entryIndex, 1, entry);
569+
} else {
570+
// Insert a new entry.
571+
this.push('_missingTags', entry);
572+
}
573+
} else if (entryIndex >= 0) {
574+
// Remove the previous entry if it exists.
575+
this.splice('_missingTags', entryIndex, 1);
524576
}
525-
526-
this.set('_nameToDataSeries', newMapping);
527577
});
528578
},
529579
_findStepMismatch(tagsObject, valueSteps, lowerSteps, upperSteps) {
@@ -606,8 +656,8 @@ <h1>[[_titleDisplayString]]</h1>
606656
_escapeRegexCharacters(stringValue) {
607657
return stringValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
608658
},
609-
_getToggleMatchesIcon(matchesListOpened) {
610-
return matchesListOpened ? 'expand-less' : 'expand-more';
659+
_getToggleCollapsibleIcon(listOpened) {
660+
return listOpened ? 'expand-less' : 'expand-more';
611661
},
612662
_toggleMatchesOpen() {
613663
this.set('_matchesListOpened', !this._matchesListOpened);
@@ -620,6 +670,11 @@ <h1>[[_titleDisplayString]]</h1>
620670
_separateWithCommas(numbers) {
621671
return numbers.join(', ');
622672
},
673+
_toggleMissingTagsCollapsibleOpen() {
674+
this.set(
675+
'_missingTagsCollapsibleOpened',
676+
!this._missingTagsCollapsibleOpened);
677+
},
623678
});
624679
</script>
625680
</dom-module>

0 commit comments

Comments
 (0)