diff --git a/WORKSPACE b/WORKSPACE
index 6fb8f8794e5..b6dbc7463f2 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -91,7 +91,7 @@ new_git_repository(
name = "iron_behaviors",
build_file = "bower.BUILD",
remote = "https://github.com/polymerelements/iron-behaviors.git",
- tag = "v1.0.16",
+ tag = "v1.0.17",
)
new_git_repository(
@@ -143,13 +143,6 @@ new_git_repository(
tag = "v1.0.8",
)
-new_git_repository(
- name = "iron_icons",
- build_file = "bower.BUILD",
- remote = "https://github.com/polymerelements/iron-icons.git",
- tag = "v1.1.3",
-)
-
new_git_repository(
name = "iron_iconset_svg",
build_file = "bower.BUILD",
diff --git a/bower.BUILD b/bower.BUILD
index 9f4994944fc..cb3309a36e2 100644
--- a/bower.BUILD
+++ b/bower.BUILD
@@ -142,24 +142,6 @@ filegroup(
],
)
-filegroup(
- name = "iron_icons",
- srcs = [
- "av-icons.html",
- "communication-icons.html",
- "device-icons.html",
- "editor-icons.html",
- "hardware-icons.html",
- "image-icons.html",
- "index.html",
- "iron-icons.html",
- "maps-icons.html",
- "notification-icons.html",
- "places-icons.html",
- "social-icons.html",
- ],
-)
-
filegroup(
name = "iron_iconset_svg",
srcs = [
diff --git a/tensorflow/tensorboard/TAG b/tensorflow/tensorboard/TAG
index a45fd52cc58..7273c0fa8c5 100644
--- a/tensorflow/tensorboard/TAG
+++ b/tensorflow/tensorboard/TAG
@@ -1 +1 @@
-24
+25
diff --git a/tensorflow/tensorboard/bower.json b/tensorflow/tensorboard/bower.json
index 27ca5dc6193..20095d92750 100644
--- a/tensorflow/tensorboard/bower.json
+++ b/tensorflow/tensorboard/bower.json
@@ -10,7 +10,6 @@
"iron-flex-layout",
"iron-form-element-behavior",
"iron-icon",
- "iron-icons",
"iron-iconset-svg",
"iron-input",
"iron-menu-behavior",
@@ -41,7 +40,7 @@
"iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#1.1.2",
"iron-ajax": "PolymerElements/iron-ajax#1.2.0",
"iron-autogrow-textarea": "PolymerElements/iron-autogrow-textarea#1.0.12",
- "iron-behaviors": "PolymerElements/iron-behaviors#1.0.16",
+ "iron-behaviors": "PolymerElements/iron-behaviors#1.0.17",
"iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#1.0.4",
"iron-collapse": "PolymerElements/iron-collapse#1.0.8",
"iron-dropdown": "PolymerElements/iron-dropdown#1.4.0",
@@ -49,7 +48,6 @@
"iron-flex-layout": "PolymerElements/iron-flex-layout#1.3.0",
"iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#1.0.6",
"iron-icon": "PolymerElements/iron-icon#1.0.8",
- "iron-icons": "PolymerElements/iron-icons#1.1.3",
"iron-iconset-svg": "PolymerElements/iron-iconset-svg#1.0.9",
"iron-input": "PolymerElements/iron-input#1.0.10",
"iron-list": "PolymerElements/iron-list#1.1.7",
@@ -117,7 +115,7 @@
"iron-a11y-keys-behavior": "1.1.2",
"iron-ajax": "1.2.0",
"iron-autogrow-textarea": "1.0.12",
- "iron-behaviors": "1.0.16",
+ "iron-behaviors": "1.0.17",
"iron-checked-element-behavior": "1.0.4",
"iron-collapse": "1.0.8",
"iron-dropdown": "1.4.0",
diff --git a/tensorflow/tensorboard/bower/BUILD b/tensorflow/tensorboard/bower/BUILD
index 90d9910205b..4b43b558443 100644
--- a/tensorflow/tensorboard/bower/BUILD
+++ b/tensorflow/tensorboard/bower/BUILD
@@ -22,7 +22,6 @@ filegroup(
"@iron_flex_layout//:iron_flex_layout",
"@iron_form_element_behavior//:iron_form_element_behavior",
"@iron_icon//:iron_icon",
- "@iron_icons//:iron_icons",
"@iron_iconset_svg//:iron_iconset_svg",
"@iron_input//:iron_input",
"@iron_list//:iron_list",
diff --git a/tensorflow/tensorboard/dist/tf-tensorboard.html b/tensorflow/tensorboard/dist/tf-tensorboard.html
index effefbd572c..97f9fbbc7f1 100644
--- a/tensorflow/tensorboard/dist/tf-tensorboard.html
+++ b/tensorflow/tensorboard/dist/tf-tensorboard.html
@@ -99,7 +99,7 @@ var TF;
var Globals;
(function (Globals) {
// The names of TensorBoard tabs.
- Globals.TABS = ['events', 'images', 'audio', 'graphs', 'distributions'];
+ Globals.TABS = ['events', 'images', 'audio', 'graphs', 'distributions', 'histograms'];
// If true, TensorBoard stores its hash in the URI state.
// If false, tab switching in TensorBoard will not update location hash,
// because hash updates interfere with wct_tests.
@@ -1681,19 +1681,23 @@ var Categorizer;
position: relative;
}
- .card .card-title {
+ .card .card-title, .card .card-subtitle {
flex-grow: 0;
flex-shrink: 0;
- margin-bottom: 10px;
font-size: 14px;
text-overflow: ellipsis;
overflow: hidden;
}
+ .card .card-subtitle {
+ font-size: 12px;
+ }
+
.card .card-content {
flex-grow: 1;
flex-shrink: 1;
display: flex;
+ margin-top: 10px;
}
.card .card-bottom-row {
position: absolute;
@@ -2361,11 +2365,15 @@ var TF;
var url = this.router.histograms(tag, run);
p = this.requestManager.request(url);
return p.then(map(detupler(createHistogram))).then(function (histos) {
+ // Get the minimum and maximum values across all histograms so that the
+ // visualization is aligned for all timesteps.
+ var min = d3.min(histos, function (d) { return d.min; });
+ var max = d3.max(histos, function (d) { return d.max; });
return histos.map(function (histo, i) {
return {
wall_time: histo.wall_time,
step: histo.step,
- bins: convertBins(histo)
+ bins: convertBins(histo, min, max)
};
});
});
@@ -2427,13 +2435,73 @@ var TF;
}());
Backend_1.Backend = Backend;
/** Given a RunToTag, return sorted array of all runs */
- function getRuns(r) { return _.keys(r).sort(); }
+ function getRuns(r) {
+ return _.keys(r).sort(compareTagNames);
+ }
Backend_1.getRuns = getRuns;
/** Given a RunToTag, return array of all tags (sorted + dedup'd) */
function getTags(r) {
- return _.union.apply(null, _.values(r)).sort();
+ return _.union.apply(null, _.values(r)).sort(compareTagNames);
}
Backend_1.getTags = getTags;
+ /** Compares tag names asciinumerically broken into components. */
+ function compareTagNames(a, b) {
+ var ai = 0;
+ var bi = 0;
+ while (true) {
+ if (ai === a.length)
+ return bi === b.length ? 0 : -1;
+ if (bi === b.length)
+ return 1;
+ if (isDigit(a[ai]) && isDigit(b[bi])) {
+ var ais = ai;
+ var bis = bi;
+ ai = consumeNumber(a, ai + 1);
+ bi = consumeNumber(b, bi + 1);
+ var an = parseFloat(a.slice(ais, ai));
+ var bn = parseFloat(b.slice(bis, bi));
+ if (an < bn)
+ return -1;
+ if (an > bn)
+ return 1;
+ continue;
+ }
+ if (isBreak(a[ai])) {
+ if (!isBreak(b[bi]))
+ return -1;
+ }
+ else if (isBreak(b[bi])) {
+ return 1;
+ }
+ else if (a[ai] < b[bi]) {
+ return -1;
+ }
+ else if (a[ai] > b[bi]) {
+ return 1;
+ }
+ ai++;
+ bi++;
+ }
+ }
+ Backend_1.compareTagNames = compareTagNames;
+ function consumeNumber(s, i) {
+ var decimal = false;
+ for (; i < s.length; i++) {
+ if (isDigit(s[i]))
+ continue;
+ if (!decimal && s[i] === '.') {
+ decimal = true;
+ continue;
+ }
+ break;
+ }
+ return i;
+ }
+ function isDigit(c) { return '0' <= c && c <= '9'; }
+ function isBreak(c) {
+ // TODO(jart): Remove underscore when people stop using it like a slash.
+ return c === '/' || c === '_' || isDigit(c);
+ }
/**
* Given a RunToTag and an array of runs, return every tag that appears for
* at least one run.
@@ -2486,28 +2554,53 @@ var TF;
* Takes histogram data as stored by tensorboard backend and converts it to
* the standard d3 histogram data format to make it more compatible and easier
* to visualize. When visualizing histograms, having the left edge and width
- * makes things quite a bit easier.
+ * makes things quite a bit easier. The bins are also converted to have an
+ * uniform width, what makes the visualization easier to understand.
*
* @param histogram A histogram from tensorboard backend.
+ * @param min The leftmost edge. The binning will start on it.
+ * @param max The rightmost edge. The binning will end on it.
+ * @param numBins The number of bins of the converted data. The default of 30
+ * is a sensible default, using more starts to get artifacts because the event
+ * data is stored in buckets, and you start being able to see the aliased
+ * borders between each bucket.
* @return A histogram bin. Each bin has an x (left edge), a dx (width),
* and a y (count).
*
* If given rightedges are inclusive, then these left edges (x) are exclusive.
*/
- function convertBins(histogram) {
+ function convertBins(histogram, min, max, numBins) {
+ if (numBins === void 0) { numBins = 30; }
if (histogram.bucketRightEdges.length !== histogram.bucketCounts.length) {
throw (new Error('Edges and counts are of different lengths.'));
}
- var previousRightEdge = histogram.min;
- return histogram.bucketRightEdges.map(function (rightEdge, i) {
- // Use the previous bin's rightEdge as the new leftEdge
- var left = previousRightEdge;
- // We need to clip the rightEdge because right-most edge can be
- // infinite-sized
- var right = Math.min(histogram.max, rightEdge);
- // Store rightEdgeValue for next iteration
- previousRightEdge = rightEdge;
- return { x: left, dx: right - left, y: histogram.bucketCounts[i] };
+ var binWidth = (max - min) / numBins;
+ var bucketLeft = min; // Use the min as the starting point for the bins.
+ var bucketPos = 0;
+ return d3.range(min, max, binWidth).map(function (binLeft) {
+ var binRight = binLeft + binWidth;
+ // Take the count of each existing bucket, multiply it by the proportion
+ // of overlap with the new bin, then sum and store as the count for the
+ // new bin. If no overlap, will add to zero, if 100% overlap, will include
+ // the full count into new bin.
+ var binY = 0;
+ while (bucketPos < histogram.bucketRightEdges.length) {
+ // Clip the right edge because right-most edge can be infinite-sized.
+ var bucketRight = Math.min(max, histogram.bucketRightEdges[bucketPos]);
+ var intersect = Math.min(bucketRight, binRight) - Math.max(bucketLeft, binLeft);
+ var count = (intersect / (bucketRight - bucketLeft)) *
+ histogram.bucketCounts[bucketPos];
+ binY += intersect > 0 ? count : 0;
+ // If bucketRight is bigger than binRight, than this bin is finished and
+ // there is data for the next bin, so don't increment bucketPos.
+ if (bucketRight > binRight) {
+ break;
+ }
+ bucketLeft = Math.max(min, bucketRight);
+ bucketPos++;
+ }
+ ;
+ return { x: binLeft, dx: binWidth, y: binY };
});
}
Backend_1.convertBins = convertBins;
@@ -2917,10 +3010,11 @@ var TF;
selectedRuns: Array,
xType: String,
dataProvider: Function,
- _initialized: Boolean,
+ _attached: Boolean,
+ _makeChartAsyncCallbackId: { type: Number, value: null }
},
observers: [
- "_makeChart(tag, dataProvider, xType, colorScale, _initialized)",
+ "_makeChart(tag, dataProvider, xType, colorScale, _attached)",
"_changeRuns(_chart, selectedRuns.*)"
],
_changeRuns: function(chart) {
@@ -2936,23 +3030,26 @@ var TF;
reload: function() {
this._chart.reload();
},
- _makeChart: function(tag, dataProvider, xType, colorScale, _initialized) {
- if (!_initialized) {
- return;
+ _makeChart: function(tag, dataProvider, xType, colorScale, _attached) {
+ if (this._makeChartAsyncCallbackId === null) {
+ this.cancelAsync(this._makeChartAsyncCallbackId);
}
- if (this._chart) this._chart.destroy();
- var chart = new TF.DistributionChart(tag, dataProvider, xType, colorScale);
- var svg = d3.select(this.$.chartsvg);
- this.async(function() {
+
+ this._makeChartAsyncCallbackId = this.async(function() {
+ this._makeChartAsyncCallbackId = null;
+ if (!_attached) return;
+ if (this._chart) this._chart.destroy();
+ var chart = new TF.DistributionChart(tag, dataProvider, xType, colorScale);
+ var svg = d3.select(this.$.chartsvg);
chart.renderTo(svg);
this._chart = chart;
}, 350);
},
attached: function() {
- this._initialized = true;
+ this._attached = true;
},
detached: function() {
- this._initialized = false;
+ this._attached = false;
}
});
@@ -3071,6 +3168,140 @@ var TF;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+