aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Dan Mané <danmane@google.com>2016-08-09 11:17:14 -0800
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2016-08-09 12:32:07 -0700
commit398385c8e165bd9967f9735bba9defff503da288 (patch)
tree8f74cba9f99388ee5fbe8050349f5593cb515c57
parent4959a1291045674a23793212cfe94d4804760f01 (diff)
Autogenerated Change: Release TensorBoard at TAG: 23
Change: 129778477
-rw-r--r--WORKSPACE12
-rw-r--r--bower.BUILD3
-rw-r--r--tensorflow/tensorboard/TAG2
-rw-r--r--tensorflow/tensorboard/bower.json24
-rw-r--r--tensorflow/tensorboard/dist/tf-tensorboard.html1244
5 files changed, 178 insertions, 1107 deletions
diff --git a/WORKSPACE b/WORKSPACE
index 7a59d15ffc..6fb8f8794e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -84,7 +84,7 @@ new_git_repository(
name = "iron_autogrow_textarea",
build_file = "bower.BUILD",
remote = "https://github.com/polymerelements/iron-autogrow-textarea.git",
- tag = "v1.0.11",
+ tag = "v1.0.12",
)
new_git_repository(
@@ -161,7 +161,7 @@ new_git_repository(
name = "iron_input",
build_file = "bower.BUILD",
remote = "https://github.com/polymerelements/iron-input.git",
- tag = "v1.0.7",
+ tag = "1.0.10",
)
new_git_repository(
@@ -210,7 +210,7 @@ new_git_repository(
name = "iron_selector",
build_file = "bower.BUILD",
remote = "https://github.com/polymerelements/iron-selector.git",
- tag = "v1.2.4",
+ tag = "v1.5.2",
)
new_git_repository(
@@ -273,7 +273,7 @@ new_git_repository(
name = "paper_dropdown_menu",
build_file = "bower.BUILD",
remote = "https://github.com/polymerelements/paper-dropdown-menu.git",
- tag = "v1.1.3",
+ tag = "v1.3.2",
)
new_git_repository(
@@ -294,7 +294,7 @@ new_git_repository(
name = "paper_input",
build_file = "bower.BUILD",
remote = "https://github.com/polymerelements/paper-input.git",
- tag = "v1.1.5",
+ tag = "v1.1.14",
)
new_git_repository(
@@ -322,7 +322,7 @@ new_git_repository(
name = "paper_menu_button",
build_file = "bower.BUILD",
remote = "https://github.com/polymerelements/paper-menu-button.git",
- tag = "v1.2.0",
+ tag = "v1.5.0",
)
new_git_repository(
diff --git a/bower.BUILD b/bower.BUILD
index 1a4b6158a4..9f4994944f 100644
--- a/bower.BUILD
+++ b/bower.BUILD
@@ -371,6 +371,9 @@ filegroup(
srcs = [
"index.html",
"paper-dropdown-menu.html",
+ "paper-dropdown-menu-icons.html",
+ "paper-dropdown-menu-light.html",
+ "paper-dropdown-menu-shared-styles.html",
],
)
diff --git a/tensorflow/tensorboard/TAG b/tensorflow/tensorboard/TAG
index 409940768f..a45fd52cc5 100644
--- a/tensorflow/tensorboard/TAG
+++ b/tensorflow/tensorboard/TAG
@@ -1 +1 @@
-23
+24
diff --git a/tensorflow/tensorboard/bower.json b/tensorflow/tensorboard/bower.json
index 26d3d54165..27ca5dc619 100644
--- a/tensorflow/tensorboard/bower.json
+++ b/tensorflow/tensorboard/bower.json
@@ -40,7 +40,7 @@
"iron-a11y-announcer": "PolymerElements/iron-a11y-announcer#1.0.4",
"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.11",
+ "iron-autogrow-textarea": "PolymerElements/iron-autogrow-textarea#1.0.12",
"iron-behaviors": "PolymerElements/iron-behaviors#1.0.16",
"iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#1.0.4",
"iron-collapse": "PolymerElements/iron-collapse#1.0.8",
@@ -51,14 +51,14 @@
"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.7",
+ "iron-input": "PolymerElements/iron-input#1.0.10",
"iron-list": "PolymerElements/iron-list#1.1.7",
"iron-menu-behavior": "PolymerElements/iron-menu-behavior#1.1.8",
"iron-meta": "PolymerElements/iron-meta#1.1.1",
"iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#1.7.6",
"iron-range-behavior": "PolymerElements/iron-range-behavior#1.0.4",
"iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#1.0.3",
- "iron-selector": "PolymerElements/iron-selector#1.2.4",
+ "iron-selector": "PolymerElements/iron-selector#1.5.2",
"iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#1.1.1",
"lodash": "3.8.0",
"neon-animation": "PolymerElements/neon-animation#1.2.2",
@@ -67,14 +67,14 @@
"paper-checkbox": "PolymerElements/paper-checkbox#1.1.3",
"paper-dialog": "PolymerElements/paper-dialog#1.0.4",
"paper-dialog-behavior": "PolymerElements/paper-dialog-behavior#1.2.5",
- "paper-dropdown-menu": "PolymerElements/paper-dropdown-menu#1.1.3",
+ "paper-dropdown-menu": "PolymerElements/paper-dropdown-menu#1.3.2",
"paper-header-panel": "PolymerElements/paper-header-panel#1.1.4",
"paper-icon-button": "PolymerElements/paper-icon-button#1.1.1",
- "paper-input": "PolymerElements/paper-input#1.1.5",
+ "paper-input": "PolymerElements/paper-input#1.1.14",
"paper-item": "PolymerElements/paper-item#1.1.4",
"paper-material": "PolymerElements/paper-material#1.0.6",
"paper-menu": "PolymerElements/paper-menu#1.2.2",
- "paper-menu-button": "PolymerElements/paper-menu-button#1.2.0",
+ "paper-menu-button": "PolymerElements/paper-menu-button#1.5.0",
"paper-progress": "PolymerElements/paper-progress#1.0.9",
"paper-radio-button": "PolymerElements/paper-radio-button#1.1.2",
"paper-radio-group": "PolymerElements/paper-radio-group#1.0.9",
@@ -116,7 +116,7 @@
"iron-a11y-announcer": "1.0.4",
"iron-a11y-keys-behavior": "1.1.2",
"iron-ajax": "1.2.0",
- "iron-autogrow-textarea": "1.0.11",
+ "iron-autogrow-textarea": "1.0.12",
"iron-behaviors": "1.0.16",
"iron-checked-element-behavior": "1.0.4",
"iron-collapse": "1.0.8",
@@ -127,14 +127,14 @@
"iron-icon": "1.0.8",
"iron-icons": "1.1.3",
"iron-iconset-svg": "1.0.9",
- "iron-input": "1.0.7",
+ "iron-input": "1.0.10",
"iron-list": "1.1.7",
"iron-menu-behavior": "1.1.8",
"iron-meta": "1.1.1",
"iron-overlay-behavior": "1.7.6",
"iron-range-behavior": "1.0.4",
"iron-resizable-behavior": "1.0.3",
- "iron-selector": "1.2.4",
+ "iron-selector": "1.5.2",
"iron-validatable-behavior": "1.1.1",
"lodash": "3.8.0",
"neon-animation": "1.2.2",
@@ -143,14 +143,14 @@
"paper-checkbox": "1.1.3",
"paper-dialog": "1.0.4",
"paper-dialog-behavior": "1.2.5",
- "paper-dropdown-menu": "1.1.3",
+ "paper-dropdown-menu": "1.3.2",
"paper-header-panel": "1.1.4",
"paper-icon-button": "1.1.1",
- "paper-input": "1.1.5",
+ "paper-input": "1.1.14",
"paper-item": "1.1.4",
"paper-material": "1.0.6",
"paper-menu": "1.2.2",
- "paper-menu-button": "1.2.0",
+ "paper-menu-button": "1.5.0",
"paper-progress": "1.0.9",
"paper-radio-button": "1.1.2",
"paper-radio-group": "1.0.9",
diff --git a/tensorflow/tensorboard/dist/tf-tensorboard.html b/tensorflow/tensorboard/dist/tf-tensorboard.html
index 8fe8e895ac..effefbd572 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', 'histograms'];
+ Globals.TABS = ['events', 'images', 'audio', 'graphs', 'distributions'];
// 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.
@@ -526,8 +526,8 @@ var TF;
<style include="run-color-style"></style>
<template>
- <div id="outer-container" class="scrollbar">
<paper-input id="runs-regex" no-label-float="" label="Write a regex to filter runs" value="{{regexInput}}"></paper-input>
+ <div id="outer-container" class="scrollbar">
<template is="dom-repeat" items="[[namesMatchingRegex]]">
<div class="run-row">
<div class="checkbox-container vertical-align-container">
@@ -555,9 +555,10 @@ var TF;
height: 100%;
}
#outer-container {
- overflow-y: scroll;
+ overflow-y: auto;
overflow-x: hidden;
width: 100%;
+ height: 0; /* Quirk to make firefox add scrolling instead of expand div */
flex-grow: 1;
flex-shrink: 1;
word-wrap: break-word;
@@ -692,8 +693,9 @@ var TF;
window.requestAnimationFrame(function() {_this.updateStyles();});
},
_checkboxChange: function(e) {
- var name = e.srcElement.name;
- var checked = e.srcElement.checked;
+ var target = e.srcElement || e.target; // Firefox doesn't have srcElement.
+ var name = target.name;
+ var checked = target.checked;
this.runToIsCheckedMapping[name] = checked;
// n.b. notifyPath won't work because run names may have periods.
this.runToIsCheckedMapping = _.clone(this.runToIsCheckedMapping);
@@ -918,22 +920,14 @@ var TF;
</style>
-<dom-module id="tf-x-type-selector" assetpath="../tf-event-dashboard/">
+<dom-module id="tf-option-selector" assetpath="../tf-option-selector/">
<template>
- <div id="buttons">
- <h3>Horizontal Axis</h3>
- <paper-button class="x-button selected" id="step" on-tap="_select">
- step
- </paper-button>
- <paper-button class="x-button" id="relative" on-tap="_select">
- relative
- </paper-button>
- <paper-button class="x-button" id="wall_time" on-tap="_select">
- wall
- </paper-button>
+ <div id="wrap">
+ <h3>[[name]]</h3>
+ <div class="content-wrapper"><content></content></div>
</div>
<style>
- .x-button {
+ .content-wrapper ::content > * {
width: 30%;
font-size: 13px;
background: none;
@@ -941,38 +935,58 @@ var TF;
color: var(--tb-ui-dark-accent);
}
- .x-button:first-of-type {
+ .content-wrapper ::content :first-of-type {
margin-left: 0;
}
- .x-button.selected {
+ .content-wrapper ::content .selected {
background-color: var(--tb-ui-dark-accent);
color: white!important;
}
- #buttons h3 {
+ h3 {
color: var(--paper-grey-800);
margin: 0;
font-weight: normal;
font-size: 14px;
margin-bottom: 5px;
+ display: block;
+ pointer-events: none;
}
</style>
</template>
<script>
Polymer({
- is: "tf-x-type-selector",
+ is: "tf-option-selector",
properties: {
- outXType: {type: String, notify: true, readOnly: true, value: "step"},
+ name: String,
+ selectedId: {
+ type: String,
+ notify: true,
+ observer: '_selectedIdChanged'
+ }
},
- _select: function(e) {
- var _this = this;
- ["step", "wall_time", "relative"].forEach(function(id) {
- _this.$[id].classList.remove("selected");
+ attached: function() {
+ this.async(function() {
+ this.getEffectiveChildren().forEach(function(node) {
+ this.listen(node, 'tap', '_selectTarget');
+ }.bind(this));
});
- this._setOutXType(e.currentTarget.id);
- e.currentTarget.classList.add("selected");
},
+ _selectTarget: function(e) {
+ this.selectedId = e.currentTarget.id;
+ },
+ _selectedIdChanged: function() {
+ var selected = this.queryEffectiveChildren('#' + this.selectedId);
+ if (!selected) {
+ return;
+ }
+
+ this.getEffectiveChildren().forEach(function(node) {
+ node.classList.remove("selected");
+ });
+ selected.classList.add("selected");
+ }
});
</script>
</dom-module>
@@ -1426,25 +1440,9 @@ var Categorizer;
</script>
</dom-module>
-<dom-module id="tf-line-chart" assetpath="../tf-event-dashboard/">
+<dom-module id="tf-chart-scaffold" assetpath="../tf-chart-scaffold/">
<template>
- <svg id="chartsvg"></svg>
- <div id="tooltip">
- <table>
- <thead>
- <tr>
- <th></th>
- <th>Run</th>
- <th>Value</th>
- <th>Step</th>
- <th>Time</th>
- <th>Relative</th>
- </tr>
- </thead>
- <tbody>
- </tbody>
- </table>
- </div>
+ <content></content>
<style>
:host {
-webkit-user-select: none;
@@ -1455,863 +1453,71 @@ var Categorizer;
flex-shrink: 1;
position: relative;
}
- svg {
- -webkit-user-select: none;
- -moz-user-select: none;
- flex-grow: 1;
- flex-shrink: 1;
- }
- td {
- padding-left: 5px;
- padding-right: 5px;
- font-size: 13px;
- opacity: 1;
- }
- #tooltip {
- pointer-events: none;
- position: absolute;
- opacity: 0;
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
- font-size: 14px;
- background: rgba(0, 0, 0, 0.8);
- color: white;
- border-radius: 4px;
- line-height: 1.4em;
- padding: 8px;
- z-index: 5;
- cursor: none;
- }
- .swatch {
- border-radius: 50%;
- width: 14px;
- height: 14px;
- display: block;
- border: 2px solid rgba(0,0,0,0);
- }
- .closest .swatch {
- border: 2px solid white;
- }
- th {
- padding-left: 5px;
- padding-right: 5px;
- text-align: left;
- }
- .distant td {
- opacity: 0.8;
- }
-
- .distant td.swatch {
- opacity: 1;
- }
-
- .ghost {
- opacity: 0.2;
- stroke-width: 1px;
- }
-
</style>
</template>
- <script>/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
-
-Licensed under the Apache License, Version 2.0 (the 'License');
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an 'AS IS' BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-==============================================================================*/
-var __extends = (this && this.__extends) || function (d, b) {
- for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
- function __() { this.constructor = d; }
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
-};
-var Plottable;
-(function (Plottable) {
- var DragZoomLayer = (function (_super) {
- __extends(DragZoomLayer, _super);
- /**
- * Constructs a SelectionBoxLayer with an attached DragInteraction and
- * ClickInteraction. On drag, it triggers an animated zoom into the box
- * that was dragged. On double click, it zooms back out to the original
- * view, before any zooming.
- * The zoom animation uses an easing function (default
- * d3.ease('cubic-in-out')) and is customizable.
- * Usage: Construct the selection box layer and attach x and y scales,
- * and then add the layer over the plot you are zooming on using a
- * Component Group.
- * TODO(danmane) - merge this into Plottable
- */
- function DragZoomLayer(xScale, yScale) {
- _super.call(this);
- this.isZoomed = false;
- this.easeFn = d3.ease('cubic-in-out');
- this._animationTime = 750;
- this.xScale(xScale);
- this.yScale(yScale);
- this._dragInteraction = new Plottable.Interactions.Drag();
- this._dragInteraction.attachTo(this);
- this._doubleClickInteraction = new Plottable.Interactions.DoubleClick();
- this._doubleClickInteraction.attachTo(this);
- this.setupCallbacks();
- }
- /**
- * Register a method that calls when the DragZoom interaction starts.
- */
- DragZoomLayer.prototype.interactionStart = function (cb) { this.onStart = cb; };
- /**
- * Register a method that calls when the DragZoom interaction ends.
- */
- DragZoomLayer.prototype.interactionEnd = function (cb) { this.onEnd = cb; };
- DragZoomLayer.prototype.setupCallbacks = function () {
- var _this = this;
- var dragging = false;
- this._dragInteraction.onDragStart(function (startPoint) {
- _this.bounds({
- topLeft: startPoint,
- bottomRight: startPoint,
- });
- _this.onStart();
- });
- this._dragInteraction.onDrag(function (startPoint, endPoint) {
- _this.bounds({ topLeft: startPoint, bottomRight: endPoint });
- _this.boxVisible(true);
- dragging = true;
- });
- this._dragInteraction.onDragEnd(function (startPoint, endPoint) {
- _this.boxVisible(false);
- _this.bounds({ topLeft: startPoint, bottomRight: endPoint });
- if (dragging) {
- _this.zoom();
- }
- else {
- _this.onEnd();
- }
- dragging = false;
- });
- this._doubleClickInteraction.onDoubleClick(this.unzoom.bind(this));
- };
- DragZoomLayer.prototype.animationTime = function (animationTime) {
- if (animationTime == null) {
- return this._animationTime;
- }
- if (animationTime < 0) {
- throw new Error('animationTime cannot be negative');
- }
- this._animationTime = animationTime;
- return this;
- };
- /**
- * Set the easing function, which determines how the zoom interpolates
- * over time.
- */
- DragZoomLayer.prototype.ease = function (fn) {
- if (typeof (fn) !== 'function') {
- throw new Error('ease function must be a function');
- }
- if (fn(0) !== 0 || fn(1) !== 1) {
- Plottable.Utils.Window.warn('Easing function does not maintain invariant ' +
- 'f(0)==0 && f(1)==1. Bad behavior may result.');
- }
- this.easeFn = fn;
- return this;
- };
- // Zoom into extent of the selection box bounds
- DragZoomLayer.prototype.zoom = function () {
- var x0 = this.xExtent()[0].valueOf();
- var x1 = this.xExtent()[1].valueOf();
- var y0 = this.yExtent()[1].valueOf();
- var y1 = this.yExtent()[0].valueOf();
- if (x0 === x1 || y0 === y1) {
- return;
- }
- if (!this.isZoomed) {
- this.isZoomed = true;
- }
- this.interpolateZoom(x0, x1, y0, y1);
- };
- // Restore the scales to their state before any zoom
- DragZoomLayer.prototype.unzoom = function () {
- if (!this.isZoomed) {
- return;
- }
- this.isZoomed = false;
- // Some Plottable magic follows which ensures that when we un-zoom, we
- // un-zoom to the current extent of the data; i.e. if new data was loaded
- // since we zoomed, we should un-zoom to the extent of the new data.
- // this basically replicates the autoDomain logic in Plottable.
- // it uses the internal methods to get the same boundaries that autoDomain
- // would, but allows us to interpolate the zoom with a nice animation.
- var xScale = this.xScale();
- var yScale = this.yScale();
- xScale._domainMin = null;
- xScale._domainMax = null;
- yScale._domainMin = null;
- yScale._domainMax = null;
- var xDomain = xScale._getExtent();
- var yDomain = yScale._getExtent();
- this.interpolateZoom(xDomain[0], xDomain[1], yDomain[0], yDomain[1]);
- };
- // If we are zooming, disable interactions, to avoid contention
- DragZoomLayer.prototype.isZooming = function (isZooming) {
- this._dragInteraction.enabled(!isZooming);
- this._doubleClickInteraction.enabled(!isZooming);
- };
- DragZoomLayer.prototype.interpolateZoom = function (x0f, x1f, y0f, y1f) {
- var _this = this;
- var x0s = this.xScale().domain()[0].valueOf();
- var x1s = this.xScale().domain()[1].valueOf();
- var y0s = this.yScale().domain()[0].valueOf();
- var y1s = this.yScale().domain()[1].valueOf();
- // Copy a ref to the ease fn, so that changing ease wont affect zooms in
- // progress.
- var ease = this.easeFn;
- var interpolator = function (a, b, p) {
- return d3.interpolateNumber(a, b)(ease(p));
- };
- this.isZooming(true);
- var start = Date.now();
- var draw = function () {
- var now = Date.now();
- var passed = now - start;
- var p = _this._animationTime === 0 ?
- 1 :
- Math.min(1, passed / _this._animationTime);
- var x0 = interpolator(x0s, x0f, p);
- var x1 = interpolator(x1s, x1f, p);
- var y0 = interpolator(y0s, y0f, p);
- var y1 = interpolator(y1s, y1f, p);
- _this.xScale().domain([x0, x1]);
- _this.yScale().domain([y0, y1]);
- if (p < 1) {
- Plottable.Utils.DOM.requestAnimationFramePolyfill(draw);
- }
- else {
- _this.onEnd();
- _this.isZooming(false);
- }
- };
- draw();
- };
- return DragZoomLayer;
- }(Plottable.Components.SelectionBoxLayer));
- Plottable.DragZoomLayer = DragZoomLayer;
-})(Plottable || (Plottable = {}));
-</script>
- <script>/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-==============================================================================*/
-/* tslint:disable:no-namespace variable-name */
-var TF;
-(function (TF) {
- var LineChart = (function () {
- function LineChart(tag, dataFn, xType, colorScale, tooltip) {
- this.dataFn = dataFn;
- this.run2datasets = {};
- this.tag = tag;
- this.colorScale = colorScale;
- this.tooltip = tooltip;
- this.datasets = [];
- this.smoothDatasets = [];
- this.run2smoothDatasets = {};
- // lastPointDataset is a dataset that contains just the last point of
- // every dataset we're currently drawing.
- this.lastPointsDataset = new Plottable.Dataset();
- this.nanDataset = new Plottable.Dataset();
- // need to do a single bind, so we can deregister the callback from
- // old Plottable.Datasets. (Deregistration is done by identity checks.)
- this.onDatasetChanged = this._onDatasetChanged.bind(this);
- this.buildChart(xType);
- }
- LineChart.prototype.buildChart = function (xType) {
- if (this.outer) {
- this.outer.destroy();
- }
- var xComponents = TF.ChartHelpers.getXComponents(xType);
- this.xAccessor = xComponents.accessor;
- this.xScale = xComponents.scale;
- this.xAxis = xComponents.axis;
- this.xAxis.margin(0).tickLabelPadding(3);
- this.yScale = new Plottable.Scales.Linear();
- this.yAxis = new Plottable.Axes.Numeric(this.yScale, 'left');
- var yFormatter = TF.ChartHelpers.multiscaleFormatter(TF.ChartHelpers.Y_AXIS_FORMATTER_PRECISION);
- this.yAxis.margin(0).tickLabelPadding(5).formatter(yFormatter);
- this.yAxis.usesTextWidthApproximation(true);
- this.dzl = new Plottable.DragZoomLayer(this.xScale, this.yScale);
- var center = this.buildPlot(this.xAccessor, this.xScale, this.yScale);
- this.gridlines =
- new Plottable.Components.Gridlines(this.xScale, this.yScale);
- this.center =
- new Plottable.Components.Group([this.gridlines, center, this.dzl]);
- this.outer = new Plottable.Components.Table([
- [this.yAxis, this.center],
- [null, this.xAxis]
- ]);
- };
- LineChart.prototype.buildPlot = function (xAccessor, xScale, yScale) {
- var _this = this;
- this.yAccessor = function (d) { return d.scalar; };
- var linePlot = new Plottable.Plots.Line();
- linePlot.x(xAccessor, xScale);
- linePlot.y(this.yAccessor, yScale);
- linePlot.attr('stroke', function (d, i, dataset) {
- return _this.colorScale.scale(dataset.metadata().run);
- });
- this.linePlot = linePlot;
- var group = this.setupTooltips(linePlot);
- var smoothLinePlot = new Plottable.Plots.Line();
- smoothLinePlot.x(xAccessor, xScale);
- smoothLinePlot.y(this.yAccessor, yScale);
- smoothLinePlot.attr('stroke', function (d, i, dataset) {
- return _this.colorScale.scale(dataset.metadata().run);
- });
- this.smoothLinePlot = smoothLinePlot;
- // The scatterPlot will display the last point for each dataset.
- // This way, if there is only one datum for the series, it is still
- // visible. We hide it when tooltips are active to keep things clean.
- var scatterPlot = new Plottable.Plots.Scatter();
- scatterPlot.x(xAccessor, xScale);
- scatterPlot.y(this.yAccessor, yScale);
- scatterPlot.attr('fill', function (d) { return _this.colorScale.scale(d.run); });
- scatterPlot.attr('opacity', 1);
- scatterPlot.size(TF.ChartHelpers.TOOLTIP_CIRCLE_SIZE * 2);
- scatterPlot.datasets([this.lastPointsDataset]);
- this.scatterPlot = scatterPlot;
- var nanDisplay = new Plottable.Plots.Scatter();
- nanDisplay.x(xAccessor, xScale);
- nanDisplay.y(function (x) { return x.displayY; }, yScale);
- nanDisplay.attr('fill', function (d) { return _this.colorScale.scale(d.run); });
- nanDisplay.attr('opacity', 1);
- nanDisplay.size(TF.ChartHelpers.NAN_SYMBOL_SIZE * 2);
- nanDisplay.datasets([this.nanDataset]);
- nanDisplay.symbol(Plottable.SymbolFactories.triangleUp);
- this.nanDisplay = nanDisplay;
- return new Plottable.Components.Group([nanDisplay, scatterPlot, smoothLinePlot, group]);
- };
- /** Updates the chart when a dataset changes. Called every time the data of
- * a dataset changes to update the charts.
- */
- LineChart.prototype._onDatasetChanged = function (dataset) {
- if (this.smoothingEnabled) {
- this.smoothDataset(this.getSmoothDataset(dataset.metadata().run));
- this.updateSpecialDatasets(this.smoothDatasets);
- }
- else {
- this.updateSpecialDatasets(this.datasets);
- }
- };
- /** Constructs special datasets. Each special dataset contains exceptional
- * values from all of the regular datasets, e.g. last points in series, or
- * NaN values. Those points will have a `run` and `relative` property added
- * (since usually those are context in the surrounding dataset).
- */
- LineChart.prototype.updateSpecialDatasets = function (datasets) {
- var lastPointsData = datasets
- .map(function (d) {
- var datum = null;
- // filter out NaNs to ensure last point is a clean one
- var nonNanData = d.data().filter(function (x) { return !isNaN(x.scalar); });
- if (nonNanData.length > 0) {
- var idx = nonNanData.length - 1;
- datum = nonNanData[idx];
- datum.run = d.metadata().run;
- datum.relative =
- TF.ChartHelpers.relativeAccessor(datum, -1, d);
- }
- return datum;
- })
- .filter(function (x) { return x != null; });
- this.lastPointsDataset.data(lastPointsData);
- // Take a dataset, return an array of NaN data points
- // the NaN points will have a "displayY" property which is the
- // y-value of a nearby point that was not NaN (0 if all points are NaN)
- var datasetToNaNData = function (d) {
- var displayY = null;
- var data = d.data();
- var i = 0;
- while (i < data.length && displayY == null) {
- if (!isNaN(data[i].scalar)) {
- displayY = data[i].scalar;
- }
- i++;
- }
- if (displayY == null) {
- displayY = 0;
- }
- var nanData = [];
- for (i = 0; i < data.length; i++) {
- if (!isNaN(data[i].scalar)) {
- displayY = data[i].scalar;
- }
- else {
- data[i].run = d.metadata().run;
- data[i].displayY = displayY;
- data[i].relative = TF.ChartHelpers.relativeAccessor(data[i], -1, d);
- nanData.push(data[i]);
- }
- }
- return nanData;
- };
- var nanData = _.flatten(datasets.map(datasetToNaNData));
- this.nanDataset.data(nanData);
- };
- LineChart.prototype.setupTooltips = function (plot) {
- var _this = this;
- var pi = new Plottable.Interactions.Pointer();
- pi.attachTo(plot);
- // PointsComponent is a Plottable Component that will hold the little
- // circles we draw over the closest data points
- var pointsComponent = new Plottable.Component();
- var group = new Plottable.Components.Group([plot, pointsComponent]);
- var hideTooltips = function () {
- _this.tooltip.style('opacity', 0);
- _this.scatterPlot.attr('opacity', 1);
- pointsComponent.content().selectAll('.point').remove();
- };
- var enabled = true;
- var disableTooltips = function () {
- enabled = false;
- hideTooltips();
- };
- var enableTooltips = function () { enabled = true; };
- this.dzl.interactionStart(disableTooltips);
- this.dzl.interactionEnd(enableTooltips);
- pi.onPointerMove(function (p) {
- if (!enabled) {
- return;
- }
- var target = {
- x: p.x,
- y: p.y,
- datum: null,
- dataset: null,
- };
- var centerBBox = _this.gridlines.content().node().getBBox();
- var datasets = _this.smoothingEnabled ? _this.smoothDatasets : plot.datasets();
- var points = datasets.map(function (dataset) { return _this.findClosestPoint(target, dataset); });
- var pointsToCircle = points.filter(function (p) { return p != null &&
- Plottable.Utils.DOM.intersectsBBox(p.x, p.y, centerBBox); });
- var pts = pointsComponent.content().selectAll('.point').data(pointsToCircle, function (p) { return p.dataset.metadata().run; });
- if (points.length !== 0) {
- pts.enter().append('circle').classed('point', true);
- pts.attr('r', TF.ChartHelpers.TOOLTIP_CIRCLE_SIZE)
- .attr('cx', function (p) { return p.x; })
- .attr('cy', function (p) { return p.y; })
- .style('stroke', 'none')
- .attr('fill', function (p) { return _this.colorScale.scale(p.dataset.metadata().run); });
- pts.exit().remove();
- _this.drawTooltips(points, target);
- }
- else {
- hideTooltips();
- }
- });
- pi.onPointerExit(hideTooltips);
- return group;
- };
- LineChart.prototype.drawTooltips = function (points, target) {
- var _this = this;
- // Formatters for value, step, and wall_time
- this.scatterPlot.attr('opacity', 0);
- var valueFormatter = TF.ChartHelpers.multiscaleFormatter(TF.ChartHelpers.Y_TOOLTIP_FORMATTER_PRECISION);
- var dist = function (p) {
- return Math.pow(p.x - target.x, 2) + Math.pow(p.y - target.y, 2);
- };
- var closestDist = _.min(points.map(dist));
- points = _.sortBy(points, function (d) { return d.dataset.metadata().run; });
- var rows = this.tooltip.select('tbody')
- .html('')
- .selectAll('tr')
- .data(points)
- .enter()
- .append('tr');
- // Grey out the point if any of the following are true:
- // - The cursor is outside of the x-extent of the dataset
- // - The point is rendered above or below the screen
- // - The point's y value is NaN
- rows.classed('distant', function (d) {
- var firstPoint = d.dataset.data()[0];
- var lastPoint = _.last(d.dataset.data());
- var firstX = _this.xScale.scale(_this.xAccessor(firstPoint, 0, d.dataset));
- var lastX = _this.xScale.scale(_this.xAccessor(lastPoint, 0, d.dataset));
- var s = d.datum.scalar;
- var yD = _this.yScale.domain();
- return target.x < firstX || target.x > lastX || s < yD[0] ||
- s > yD[1] || isNaN(s);
- });
- rows.classed('closest', function (p) { return dist(p) === closestDist; });
- // It is a bit hacky that we are manually applying the width to the swatch
- // and the nowrap property to the text here. The reason is as follows:
- // the style gets updated asynchronously by Polymer scopeSubtree observer.
- // Which means we would get incorrect sizing information since the text
- // would wrap by default. However, we need correct measurements so that
- // we can stop the text from falling off the edge of the screen.
- // therefore, we apply the size-critical styles directly.
- rows.style('white-space', 'nowrap');
- rows.append('td')
- .append('span')
- .classed('swatch', true)
- .style('background-color', function (d) { return _this.colorScale.scale(d.dataset.metadata().run); });
- rows.append('td').text(function (d) { return d.dataset.metadata().run; });
- rows.append('td').text(function (d) {
- return isNaN(d.datum.scalar) ? 'NaN' : valueFormatter(d.datum.scalar);
- });
- rows.append('td').text(function (d) { return TF.ChartHelpers.stepFormatter(d.datum.step); });
- rows.append('td').text(function (d) { return TF.ChartHelpers.timeFormatter(d.datum.wall_time); });
- rows.append('td').text(function (d) { return TF.ChartHelpers.relativeFormatter(TF.ChartHelpers.relativeAccessor(d.datum, -1, d.dataset)); });
- // compute left position
- var documentWidth = document.body.clientWidth;
- var node = this.tooltip.node();
- var parentRect = node.parentElement.getBoundingClientRect();
- var nodeRect = node.getBoundingClientRect();
- // prevent it from falling off the right side of the screen
- var left = Math.min(0, documentWidth - parentRect.left - nodeRect.width - 60);
- this.tooltip.style('left', left + 'px');
- // compute top position
- if (parentRect.bottom + nodeRect.height +
- TF.ChartHelpers.TOOLTIP_Y_PIXEL_OFFSET <
- document.body.clientHeight) {
- this.tooltip.style('top', parentRect.bottom + TF.ChartHelpers.TOOLTIP_Y_PIXEL_OFFSET);
- }
- else {
- this.tooltip.style('bottom', parentRect.top - TF.ChartHelpers.TOOLTIP_Y_PIXEL_OFFSET);
- }
- this.tooltip.style('opacity', 1);
- };
- LineChart.prototype.findClosestPoint = function (target, dataset) {
- var _this = this;
- var points = dataset.data().map(function (d, i) {
- var x = _this.xAccessor(d, i, dataset);
- var y = _this.yAccessor(d, i, dataset);
- return {
- x: _this.xScale.scale(x),
- y: _this.yScale.scale(y),
- datum: d,
- dataset: dataset,
- };
- });
- var idx = _.sortedIndex(points, target, function (p) { return p.x; });
- if (idx === points.length) {
- return points[points.length - 1];
- }
- else if (idx === 0) {
- return points[0];
- }
- else {
- var prev = points[idx - 1];
- var next = points[idx];
- var prevDist = Math.abs(prev.x - target.x);
- var nextDist = Math.abs(next.x - target.x);
- return prevDist < nextDist ? prev : next;
- }
- };
- LineChart.prototype.getSmoothDataset = function (run) {
- if (this.run2smoothDatasets[run] === undefined) {
- this.run2smoothDatasets[run] =
- new Plottable.Dataset([], { run: run, tag: this.tag });
- }
- return this.run2smoothDatasets[run];
- };
- LineChart.prototype.smoothDataset = function (dataset) {
- var _this = this;
- var data = this.getDataset(dataset.metadata().run).data();
- // EMA with first step initialized to first element.
- var smoothedData = _.cloneDeep(data);
- smoothedData.forEach(function (d, i) {
- if (i === 0) {
- return;
- }
- d.scalar = (1.0 - _this.smoothingDecay) * d.scalar +
- _this.smoothingDecay * smoothedData[i - 1].scalar;
- });
- dataset.data(smoothedData);
- };
- LineChart.prototype.getDataset = function (run) {
- if (this.run2datasets[run] === undefined) {
- this.run2datasets[run] =
- new Plottable.Dataset([], { run: run, tag: this.tag });
- }
- return this.run2datasets[run];
- };
- /**
- * Change the runs on the chart.
- * Changing runs automatically triggers a reload; this ensures that the
- * newly selected run will have data, and that all the runs will be current
- * (it would be weird if one run was ahead of the others, and the display
- * depended on the order in which runs were added)
- */
- LineChart.prototype.changeRuns = function (runs) {
- var _this = this;
- this.runs = runs;
- this.reload();
- runs.reverse(); // draw first run on top
- this.datasets.forEach(function (d) { return d.offUpdate(_this.onDatasetChanged); });
- this.datasets = runs.map(function (r) { return _this.getDataset(r); });
- this.datasets.forEach(function (d) { return d.onUpdate(_this.onDatasetChanged); });
- this.linePlot.datasets(this.datasets);
- if (this.smoothingEnabled) {
- this.smoothDatasets = runs.map(function (r) { return _this.getSmoothDataset(r); });
- this.smoothLinePlot.datasets(this.smoothDatasets);
- }
- };
- LineChart.prototype.smoothingUpdate = function (decay) {
- var _this = this;
- if (!this.smoothingEnabled) {
- this.linePlot.addClass('ghost');
- this.smoothingEnabled = true;
- this.smoothDatasets = this.runs.map(function (r) { return _this.getSmoothDataset(r); });
- this.smoothLinePlot.datasets(this.smoothDatasets);
- }
- this.smoothingDecay = decay;
- this.smoothDatasets.forEach(function (d) { return _this.smoothDataset(d); });
- this.updateSpecialDatasets(this.smoothDatasets);
- };
- LineChart.prototype.smoothingDisable = function () {
- if (this.smoothingEnabled) {
- this.linePlot.removeClass('ghost');
- this.smoothDatasets = [];
- this.smoothLinePlot.datasets(this.smoothDatasets);
- this.smoothingEnabled = false;
- this.updateSpecialDatasets(this.datasets);
- }
- };
- /**
- * Reload data for each run in view.
- */
- LineChart.prototype.reload = function () {
- var _this = this;
- this.runs.forEach(function (run) {
- var dataset = _this.getDataset(run);
- _this.dataFn(_this.tag, run).then(function (x) { return dataset.data(x); });
- });
- };
- LineChart.prototype.renderTo = function (target) { this.outer.renderTo(target); };
- LineChart.prototype.redraw = function () { this.outer.redraw(); };
- LineChart.prototype.destroy = function () { this.outer.destroy(); };
- return LineChart;
- }());
- TF.LineChart = LineChart;
-})(TF || (TF = {}));
-</script>
- <script>/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-==============================================================================*/
-/* tslint:disable:no-namespace variable-name */
-var TF;
-(function (TF) {
- var ChartHelpers;
- (function (ChartHelpers) {
- ChartHelpers.Y_TOOLTIP_FORMATTER_PRECISION = 4;
- ChartHelpers.STEP_FORMATTER_PRECISION = 4;
- ChartHelpers.Y_AXIS_FORMATTER_PRECISION = 3;
- ChartHelpers.TOOLTIP_Y_PIXEL_OFFSET = 20;
- ChartHelpers.TOOLTIP_CIRCLE_SIZE = 4;
- ChartHelpers.NAN_SYMBOL_SIZE = 6;
- /* Create a formatter function that will switch between exponential and
- * regular display depending on the scale of the number being formatted,
- * and show `digits` significant digits.
- */
- function multiscaleFormatter(digits) {
- return function (v) {
- var absv = Math.abs(v);
- if (absv < 1E-15) {
- // Sometimes zero-like values get an annoying representation
- absv = 0;
- }
- var f;
- if (absv >= 1E4) {
- f = d3.format('.' + digits + 'e');
- }
- else if (absv > 0 && absv < 0.01) {
- f = d3.format('.' + digits + 'e');
- }
- else {
- f = d3.format('.' + digits + 'g');
- }
- return f(v);
- };
- }
- ChartHelpers.multiscaleFormatter = multiscaleFormatter;
- function accessorize(key) {
- return function (d, index, dataset) { return d[key]; };
- }
- ChartHelpers.accessorize = accessorize;
- ChartHelpers.stepFormatter = Plottable.Formatters.siSuffix(ChartHelpers.STEP_FORMATTER_PRECISION);
- function stepX() {
- var scale = new Plottable.Scales.Linear();
- var axis = new Plottable.Axes.Numeric(scale, 'bottom');
- axis.formatter(ChartHelpers.stepFormatter);
- return {
- scale: scale,
- axis: axis,
- accessor: function (d) { return d.step; },
- };
- }
- ChartHelpers.stepX = stepX;
- ChartHelpers.timeFormatter = Plottable.Formatters.time('%a %b %e, %H:%M:%S');
- function wallX() {
- var scale = new Plottable.Scales.Time();
- return {
- scale: scale,
- axis: new Plottable.Axes.Time(scale, 'bottom'),
- accessor: function (d) { return d.wall_time; },
- };
- }
- ChartHelpers.wallX = wallX;
- ChartHelpers.relativeAccessor = function (d, index, dataset) {
- // We may be rendering the final-point datum for scatterplot.
- // If so, we will have already provided the 'relative' property
- if (d.relative != null) {
- return d.relative;
- }
- var data = dataset.data();
- // I can't imagine how this function would be called when the data is
- // empty (after all, it iterates over the data), but lets guard just
- // to be safe.
- var first = data.length > 0 ? +data[0].wall_time : 0;
- return (+d.wall_time - first) / (60 * 60 * 1000); // ms to hours
- };
- ChartHelpers.relativeFormatter = function (n) {
- // we will always show 2 units of precision, e.g days and hours, or
- // minutes and seconds, but not hours and minutes and seconds
- var ret = '';
- var days = Math.floor(n / 24);
- n -= (days * 24);
- if (days) {
- ret += days + 'd ';
- }
- var hours = Math.floor(n);
- n -= hours;
- n *= 60;
- if (hours || days) {
- ret += hours + 'h ';
- }
- var minutes = Math.floor(n);
- n -= minutes;
- n *= 60;
- if (minutes || hours || days) {
- ret += minutes + 'm ';
- }
- var seconds = Math.floor(n);
- return ret + seconds + 's';
- };
- function relativeX() {
- var scale = new Plottable.Scales.Linear();
- return {
- scale: scale,
- axis: new Plottable.Axes.Numeric(scale, 'bottom'),
- accessor: ChartHelpers.relativeAccessor,
- };
- }
- ChartHelpers.relativeX = relativeX;
- // a very literal definition of NaN: true for NaN for a non-number type
- // or null, etc. False for Infinity or -Infinity
- ChartHelpers.isNaN = function (x) { return +x !== x; };
- function getXComponents(xType) {
- switch (xType) {
- case 'step':
- return stepX();
- case 'wall_time':
- return wallX();
- case 'relative':
- return relativeX();
- default:
- throw new Error('invalid xType: ' + xType);
- }
- }
- ChartHelpers.getXComponents = getXComponents;
- })(ChartHelpers = TF.ChartHelpers || (TF.ChartHelpers = {}));
-})(TF || (TF = {}));
-</script>
<script>
Polymer({
- is: "tf-line-chart",
+ is: "tf-chart-scaffold",
properties: {
- _chart: Object,
- colorScale: Object,
tag: String,
- selectedRuns: Array,
- smoothingDecay: Number,
- smoothingEnabled: Boolean,
- xType: String,
dataProvider: Function,
- _initialized: Boolean,
+ visibleSeries: Array,
+ _attached: {
+ type: Boolean,
+ value: false
+ }
},
observers: [
- "_makeChart(tag, dataProvider, xType, colorScale, _initialized)",
- "_changeRuns(_chart, selectedRuns.*)",
- "_smoothingChanged(smoothingDecay, smoothingEnabled, _chart)"
+ "reload(tag, dataProvider)",
+ "_changeSeries(visibleSeries.*)"
],
- _changeRuns: function(chart) {
- if (chart.tag !== this.tag) {
- return; // hack around some weird polymer bug :(
- }
- this._chart.changeRuns(this.selectedRuns);
- this.redraw();
+ attached: function() {
+ this._attached = true;
+ this._changeSeries();
},
- redraw: function() {
- this._chart.redraw();
+ detached: function() {
+ this._attached = false;
},
reload: function() {
- this._chart.reload();
- },
- _makeChart: function(tag, dataProvider, xType, colorScale, _initialized) {
- if (!_initialized) {
- return;
- }
- if (this._chart) this._chart.destroy();
- var tooltip = d3.select(this.$.tooltip);
- this.scopeSubtree(this.$.tooltip, true);
- var chart = new TF.LineChart(tag, dataProvider, xType, colorScale, tooltip);
- var svg = d3.select(this.$.chartsvg);
- this.async(function() {
- chart.renderTo(svg);
- this.scopeSubtree(this.$.chartsvg, true);
- this._chart = chart;
- }, 350);
- },
- _smoothingChanged: function() {
- if(!this._chart) {
+ if (!this._attached) {
return;
}
- if(this.smoothingEnabled) {
- this._chart.smoothingUpdate(this.smoothingDecay);
+ else if (!this.dataProvider) {
+ throw new Error('tf-chart-scaffold requires a dataProvider.');
}
- else {
- this._chart.smoothingDisable();
+ else if (!this.tag) {
+ throw new Error('tf-chart-scaffold requires a tag.');
}
+
+ this.visibleSeries.forEach(function(name) {
+ this.dataProvider(this.tag, name).then(function(data) {
+ this.chart().setSeriesData(name, data);
+ }.bind(this));
+ }.bind(this));
},
- attached: function() {
- this._initialized = true;
+ _changeSeries: function() {
+ if (!this._attached) {
+ return;
+ }
+ else if (!this.visibleSeries) {
+ throw new Error('tf-chart-scaffold requires a visibleSeries.');
+ }
+
+ this.chart().setVisibleSeries(this.visibleSeries);
+ this.reload();
},
- detached: function() {
- this._initialized = false;
+ chart: function() {
+ var children = this.getEffectiveChildren();
+ if (!children.length) {
+ throw new Error('tf-chart-scaffold has no children');
+ }
+
+ var child = children[0];
+ if (!child.setVisibleSeries || !child.setSeriesData) {
+ throw new Error("tf-chart-scaffold's content doesn't implement the " +
+ "required interface");
+ }
+ return child;
}
});
</script>
@@ -2438,7 +1644,7 @@ var TF;
#center {
height: 100%;
- overflow-y: scroll;
+ overflow-y: auto;
flex-grow: 1;
flex-shrink: 1;
}
@@ -2490,9 +1696,9 @@ var TF;
display: flex;
}
.card .card-bottom-row {
- flex-grow: 0;
- flex-shrink: 0;
- padding-left: 10px;
+ position: absolute;
+ left: 50px;
+ bottom: 0;
padding-right: 10px;
}
@@ -2501,14 +1707,10 @@ var TF;
width: 100%;
}
- [shift] {
- bottom: 20px !important;
- }
-
.expand-button {
position: absolute;
left: 0px;
- bottom: 20px;
+ bottom: 0px;
color: #2196F3;
display: block;
}
@@ -2578,7 +1780,7 @@ var TF;
display: block;
}
paper-dropdown-menu {
- width: 220px;
+ width: 180px;
--paper-input-container-label: {
font-size: 10px;
}
@@ -3452,7 +2654,11 @@ var TF;
<tf-smoothing-input enabled="{{_smoothingEnabled}}" decay="{{_smoothingDecay}}" step="0.001" min="0" max="1"></tf-smoothing-input>
</div>
<div class="sidebar-section">
- <tf-x-type-selector id="xTypeSelector" out-x-type="{{xType}}"></tf-x-type-selector>
+ <tf-option-selector id="xTypeSelector" name="Horizontal Axis" selected-id="{{_xType}}">
+ <paper-button id="step">step</paper-button>
+ <paper-button id="relative">relative</paper-button>
+ <paper-button id="wall_time">wall</paper-button>
+ </tf-option-selector>
</div>
<div class="sidebar-section">
<tf-run-selector id="runSelector" runs="[[runs]]" color-scale="[[colorScale]]" out-selected="{{selectedRuns}}"></tf-run-selector>
@@ -3467,8 +2673,10 @@ var TF;
<div class="card">
<span class="card-title">[[tag]]</span>
<div class="card-content">
- <tf-line-chart tag="[[tag]]" data-provider="[[dataProvider]]" id="chart" selected-runs="[[validRuns(tag, selectedRuns.*, run2tag.*)]]" x-type="[[xType]]" color-scale="[[colorScale]]" smoothing-decay="[[_smoothingDecay]]" smoothing-enabled="[[_smoothingEnabled]]" on-keyup="toggleSelected" tabindex="2"></tf-line-chart>
- <paper-icon-button class="expand-button" shift$="[[_showDownloadLinks]]" icon="fullscreen" on-tap="toggleSelected"></paper-icon-button>
+ <tf-chart-scaffold tag="[[tag]]" data-provider="[[dataProvider]]" visible-series="[[validRuns(tag, selectedRuns.*, run2tag.*)]]">
+ <vz-line-chart id="chart" x-type="[[_xType]]" color-scale="[[colorScale]]" smoothing-decay="[[_smoothingDecay]]" smoothing-enabled="[[_smoothingEnabled]]" on-keyup="toggleSelected" tabindex="2"></vz-line-chart>
+ </tf-chart-scaffold>
+ <paper-icon-button class="expand-button" icon="fullscreen" on-tap="toggleSelected"></paper-icon-button>
</div>
<template is="dom-if" if="[[_showDownloadLinks]]">
<div class="card-bottom-row">
@@ -3492,7 +2700,7 @@ var TF;
Polymer({
is: "tf-event-dashboard",
behaviors: [
- TF.Dashboard.ReloadBehavior("tf-line-chart"),
+ TF.Dashboard.ReloadBehavior("tf-chart-scaffold"),
TF.Backend.Behavior,
],
properties: {
@@ -3519,19 +2727,16 @@ var TF;
type: Object,
notify: true,
},
+ _xType: {
+ type: String,
+ value: "step"
+ }
},
attached: function() {
this.async(function() {
this.fire("rendered");
});
},
- observers: ['redraw(_showDownloadLinks)'],
- redraw: function(_showDownloadLinks) {
- var els = this.getElementsByTagName("tf-line-chart");
- for (var i=0; i<els.length; i++) {
- els[i].redraw();
- }
- },
_getVisibleTags: function() {
var keys = this.selectedRuns;
var dict = this.run2tag;
@@ -3546,9 +2751,9 @@ var TF;
var currentTarget = Polymer.dom(e.currentTarget);
var parentDiv = currentTarget.parentNode.parentNode;
parentDiv.classList.toggle("selected");
- var chart = currentTarget.previousElementSibling;
- if (chart) {
- chart.redraw();
+ var chartScaffold = currentTarget.previousElementSibling;
+ if (chartScaffold) {
+ chartScaffold.chart().redraw();
}
},
validRuns: function(tag, runsChange, run2tagChange) {
@@ -3561,7 +2766,7 @@ var TF;
});
</script>
</dom-module>
-<dom-module id="tf-obsolete-histogram-chart" assetpath="../tf-histogram-dashboard/">
+<dom-module id="tf-distribution-chart" assetpath="../tf-distribution-dashboard/">
<template>
<svg id="chartsvg"></svg>
<style>
@@ -3600,8 +2805,8 @@ limitations under the License.
/* tslint:disable:no-namespace variable-name */
var TF;
(function (TF) {
- var HistogramChart = (function () {
- function HistogramChart(tag, dataFn, xType, colorScale, tooltip) {
+ var DistributionChart = (function () {
+ function DistributionChart(tag, dataFn, xType, colorScale, tooltip) {
this.dataFn = dataFn;
this.run2datasets = {};
this.tag = tag;
@@ -3617,7 +2822,7 @@ var TF;
* (it would be weird if one run was ahead of the others, and the display
* depended on the order in which runs were added)
*/
- HistogramChart.prototype.changeRuns = function (runs) {
+ DistributionChart.prototype.changeRuns = function (runs) {
var _this = this;
this.runs = runs;
this.reload();
@@ -3627,32 +2832,32 @@ var TF;
/**
* Reload data for each run in view.
*/
- HistogramChart.prototype.reload = function () {
+ DistributionChart.prototype.reload = function () {
var _this = this;
this.runs.forEach(function (run) {
var dataset = _this.getDataset(run);
_this.dataFn(_this.tag, run).then(function (x) { return dataset.data(x); });
});
};
- HistogramChart.prototype.getDataset = function (run) {
+ DistributionChart.prototype.getDataset = function (run) {
if (this.run2datasets[run] === undefined) {
this.run2datasets[run] =
new Plottable.Dataset([], { run: run, tag: this.tag });
}
return this.run2datasets[run];
};
- HistogramChart.prototype.buildChart = function (xType) {
+ DistributionChart.prototype.buildChart = function (xType) {
if (this.outer) {
this.outer.destroy();
}
- var xComponents = TF.ChartHelpers.getXComponents(xType);
+ var xComponents = VZ.ChartHelpers.getXComponents(xType);
this.xAccessor = xComponents.accessor;
this.xScale = xComponents.scale;
this.xAxis = xComponents.axis;
this.xAxis.margin(0).tickLabelPadding(3);
this.yScale = new Plottable.Scales.Linear();
this.yAxis = new Plottable.Axes.Numeric(this.yScale, 'left');
- var yFormatter = TF.ChartHelpers.multiscaleFormatter(TF.ChartHelpers.Y_AXIS_FORMATTER_PRECISION);
+ var yFormatter = VZ.ChartHelpers.multiscaleFormatter(VZ.ChartHelpers.Y_AXIS_FORMATTER_PRECISION);
this.yAxis.margin(0).tickLabelPadding(5).formatter(yFormatter);
this.yAxis.usesTextWidthApproximation(true);
var center = this.buildPlot(this.xAccessor, this.xScale, this.yScale);
@@ -3661,7 +2866,7 @@ var TF;
this.center = new Plottable.Components.Group([this.gridlines, center]);
this.outer = new Plottable.Components.Table([[this.yAxis, this.center], [null, this.xAxis]]);
};
- HistogramChart.prototype.buildPlot = function (xAccessor, xScale, yScale) {
+ DistributionChart.prototype.buildPlot = function (xAccessor, xScale, yScale) {
var _this = this;
var percents = [0, 228, 1587, 3085, 5000, 6915, 8413, 9772, 10000];
var opacities = _.range(percents.length - 1)
@@ -3694,158 +2899,17 @@ var TF;
this.plots = plots;
return new Plottable.Components.Group(plots);
};
- HistogramChart.prototype.renderTo = function (target) { this.outer.renderTo(target); };
- HistogramChart.prototype.redraw = function () { this.outer.redraw(); };
- HistogramChart.prototype.destroy = function () { this.outer.destroy(); };
- return HistogramChart;
+ DistributionChart.prototype.renderTo = function (target) { this.outer.renderTo(target); };
+ DistributionChart.prototype.redraw = function () { this.outer.redraw(); };
+ DistributionChart.prototype.destroy = function () { this.outer.destroy(); };
+ return DistributionChart;
}());
- TF.HistogramChart = HistogramChart;
-})(TF || (TF = {}));
-</script>
- <script>/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-==============================================================================*/
-/* tslint:disable:no-namespace variable-name */
-var TF;
-(function (TF) {
- var ChartHelpers;
- (function (ChartHelpers) {
- ChartHelpers.Y_TOOLTIP_FORMATTER_PRECISION = 4;
- ChartHelpers.STEP_FORMATTER_PRECISION = 4;
- ChartHelpers.Y_AXIS_FORMATTER_PRECISION = 3;
- ChartHelpers.TOOLTIP_Y_PIXEL_OFFSET = 20;
- ChartHelpers.TOOLTIP_CIRCLE_SIZE = 4;
- ChartHelpers.NAN_SYMBOL_SIZE = 6;
- /* Create a formatter function that will switch between exponential and
- * regular display depending on the scale of the number being formatted,
- * and show `digits` significant digits.
- */
- function multiscaleFormatter(digits) {
- return function (v) {
- var absv = Math.abs(v);
- if (absv < 1E-15) {
- // Sometimes zero-like values get an annoying representation
- absv = 0;
- }
- var f;
- if (absv >= 1E4) {
- f = d3.format('.' + digits + 'e');
- }
- else if (absv > 0 && absv < 0.01) {
- f = d3.format('.' + digits + 'e');
- }
- else {
- f = d3.format('.' + digits + 'g');
- }
- return f(v);
- };
- }
- ChartHelpers.multiscaleFormatter = multiscaleFormatter;
- function accessorize(key) {
- return function (d, index, dataset) { return d[key]; };
- }
- ChartHelpers.accessorize = accessorize;
- ChartHelpers.stepFormatter = Plottable.Formatters.siSuffix(ChartHelpers.STEP_FORMATTER_PRECISION);
- function stepX() {
- var scale = new Plottable.Scales.Linear();
- var axis = new Plottable.Axes.Numeric(scale, 'bottom');
- axis.formatter(ChartHelpers.stepFormatter);
- return {
- scale: scale,
- axis: axis,
- accessor: function (d) { return d.step; },
- };
- }
- ChartHelpers.stepX = stepX;
- ChartHelpers.timeFormatter = Plottable.Formatters.time('%a %b %e, %H:%M:%S');
- function wallX() {
- var scale = new Plottable.Scales.Time();
- return {
- scale: scale,
- axis: new Plottable.Axes.Time(scale, 'bottom'),
- accessor: function (d) { return d.wall_time; },
- };
- }
- ChartHelpers.wallX = wallX;
- ChartHelpers.relativeAccessor = function (d, index, dataset) {
- // We may be rendering the final-point datum for scatterplot.
- // If so, we will have already provided the 'relative' property
- if (d.relative != null) {
- return d.relative;
- }
- var data = dataset.data();
- // I can't imagine how this function would be called when the data is
- // empty (after all, it iterates over the data), but lets guard just
- // to be safe.
- var first = data.length > 0 ? +data[0].wall_time : 0;
- return (+d.wall_time - first) / (60 * 60 * 1000); // ms to hours
- };
- ChartHelpers.relativeFormatter = function (n) {
- // we will always show 2 units of precision, e.g days and hours, or
- // minutes and seconds, but not hours and minutes and seconds
- var ret = '';
- var days = Math.floor(n / 24);
- n -= (days * 24);
- if (days) {
- ret += days + 'd ';
- }
- var hours = Math.floor(n);
- n -= hours;
- n *= 60;
- if (hours || days) {
- ret += hours + 'h ';
- }
- var minutes = Math.floor(n);
- n -= minutes;
- n *= 60;
- if (minutes || hours || days) {
- ret += minutes + 'm ';
- }
- var seconds = Math.floor(n);
- return ret + seconds + 's';
- };
- function relativeX() {
- var scale = new Plottable.Scales.Linear();
- return {
- scale: scale,
- axis: new Plottable.Axes.Numeric(scale, 'bottom'),
- accessor: ChartHelpers.relativeAccessor,
- };
- }
- ChartHelpers.relativeX = relativeX;
- // a very literal definition of NaN: true for NaN for a non-number type
- // or null, etc. False for Infinity or -Infinity
- ChartHelpers.isNaN = function (x) { return +x !== x; };
- function getXComponents(xType) {
- switch (xType) {
- case 'step':
- return stepX();
- case 'wall_time':
- return wallX();
- case 'relative':
- return relativeX();
- default:
- throw new Error('invalid xType: ' + xType);
- }
- }
- ChartHelpers.getXComponents = getXComponents;
- })(ChartHelpers = TF.ChartHelpers || (TF.ChartHelpers = {}));
+ TF.DistributionChart = DistributionChart;
})(TF || (TF = {}));
</script>
- <script>
+ <script>
Polymer({
- is: "tf-obsolete-histogram-chart",
+ is: "tf-distribution-chart",
properties: {
_chart: Object,
colorScale: Object,
@@ -3877,7 +2941,7 @@ var TF;
return;
}
if (this._chart) this._chart.destroy();
- var chart = new TF.HistogramChart(tag, dataProvider, xType, colorScale);
+ var chart = new TF.DistributionChart(tag, dataProvider, xType, colorScale);
var svg = d3.select(this.$.chartsvg);
this.async(function() {
chart.renderTo(svg);
@@ -3894,7 +2958,7 @@ var TF;
</script>
</dom-module>
-<dom-module id="tf-histogram-dashboard" assetpath="../tf-histogram-dashboard/">
+<dom-module id="tf-distribution-dashboard" assetpath="../tf-distribution-dashboard/">
<template>
<div id="plumbing">
<tf-color-scale id="colorScale" runs="[[runs]]" out-color-scale="{{colorScale}}"></tf-color-scale>
@@ -3906,7 +2970,11 @@ var TF;
<tf-categorizer id="categorizer" tags="[[_visibleTags]]" categories="{{categories}}"></tf-categorizer>
</div>
<div class="sidebar-section">
- <tf-x-type-selector id="xTypeSelector" out-x-type="{{xType}}"></tf-x-type-selector>
+ <tf-option-selector id="xTypeSelector" name="Horizontal Axis" selected-id="{{_xType}}">
+ <paper-button id="step">step</paper-button>
+ <paper-button id="relative">relative</paper-button>
+ <paper-button id="wall_time">wall</paper-button>
+ </tf-option-selector>
</div>
<div class="sidebar-section">
<tf-run-selector id="runSelector" runs="[[runs]]" color-scale="[[colorScale]]" out-selected="{{selectedRuns}}"></tf-run-selector>
@@ -3914,7 +2982,7 @@ var TF;
</div>
<div class="center">
- <tf-no-data-warning data-type="histogram" show-warning="[[dataNotFound]]"></tf-no-data-warning>
+ <tf-no-data-warning data-type="distribution" show-warning="[[dataNotFound]]"></tf-no-data-warning>
<template is="dom-repeat" items="[[categories]]">
<tf-collapsable-pane name="[[item.name]]" count="[[_count(item.tags, selectedRuns.*, runToCompressedHistograms.*)]]">
<div class="layout horizontal wrap">
@@ -3924,7 +2992,7 @@ var TF;
<div class="card">
<span class="card-title">[[tag]]</span>
<div class="card-content">
- <tf-obsolete-histogram-chart tag="[[tag]]" id="chart" selected-runs="[[_array(run)]]" x-type="[[xType]]" data-provider="[[dataProvider]]" color-scale="[[colorScale]]" on-keyup="toggleSelected" tabindex="2"></tf-obsolete-histogram-chart>
+ <tf-distribution-chart tag="[[tag]]" id="chart" selected-runs="[[_array(run)]]" x-type="[[_xType]]" data-provider="[[dataProvider]]" color-scale="[[colorScale]]" on-keyup="toggleSelected" tabindex="2"></tf-distribution-chart>
<paper-icon-button class="expand-button" icon="fullscreen" on-tap="toggleSelected"></paper-icon-button>
</div>
</div>
@@ -3942,9 +3010,9 @@ var TF;
<script>
Polymer({
- is: "tf-histogram-dashboard",
+ is: "tf-distribution-dashboard",
behaviors: [
- TF.Dashboard.ReloadBehavior("tf-obsolete-histogram-chart"),
+ TF.Dashboard.ReloadBehavior("tf-distribution-chart"),
TF.Backend.Behavior,
],
properties: {
@@ -3952,6 +3020,10 @@ var TF;
type: Array,
computed: "_getVisibleTags(selectedRuns.*, run2tag.*)"
},
+ _xType: {
+ type: String,
+ value: "step"
+ },
dataType: {value: "compressedHistogram"},
},
_exists: function(run, tag) {
@@ -4088,7 +3160,7 @@ var TF;
height: 100%;
flex-direction: column;
padding-top: 20px;
- overflow: scroll;
+ overflow: auto;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
@@ -4126,7 +3198,7 @@ var TF;
}
.run-name-cell {
width: 300px;
- height: 30px;
+ word-break:break-all;
text-align: center;
}
.noshrink {
@@ -4163,8 +3235,6 @@ var TF;
<style>
.center {
- padding-left: 10px;
- padding-right: 10px;
height: 100%;
width: 100%;
-webkit-box-sizing: border-box;
@@ -4295,7 +3365,7 @@ var TF;
height: 100%;
flex-direction: column;
padding-top: 20px;
- overflow: scroll;
+ overflow: auto;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
@@ -4368,8 +3438,6 @@ var TF;
<style>
.center {
- padding-left: 10px;
- padding-right: 10px;
height: 100%;
width: 100%;
-webkit-box-sizing: border-box;
@@ -13268,7 +12336,7 @@ Polymer({
_getHasDisplayableNodeStats: function(stats) {
return tf.graph.util.hasDisplayableNodeStats(stats);
},
- _getNodeStatsFormattedBytes(stats) {
+ _getNodeStatsFormattedBytes: function(stats) {
if (!stats || !stats.totalBytes) {
return;
}
@@ -13276,7 +12344,7 @@ Polymer({
return tf.graph.util.convertUnitsToHumanReadable(
stats.totalBytes, tf.graph.util.MEMORY_UNITS);
},
- _getNodeStatsFormattedComputeTime(stats) {
+ _getNodeStatsFormattedComputeTime: function(stats) {
if (!stats || !stats.totalMicros) {
return;
}
@@ -13284,7 +12352,7 @@ Polymer({
return tf.graph.util.convertUnitsToHumanReadable(
stats.totalMicros, tf.graph.util.TIME_UNITS);
},
- _getNodeStatsFormattedOutputSizes(stats) {
+ _getNodeStatsFormattedOutputSizes: function(stats) {
if (!stats || !stats.outputSize || !stats.outputSize.length) {
return;
}
@@ -14491,8 +13559,8 @@ Polymer({
<tf-graph-dashboard id="graphs" backend="[[_backend]]"></tf-graph-dashboard>
</template>
- <template is="dom-if" if="[[_modeIsHistograms(mode)]]">
- <tf-histogram-dashboard id="histograms" backend="[[_backend]]"></tf-histogram-dashboard>
+ <template is="dom-if" if="[[_modeIsDistributions(mode)]]">
+ <tf-distribution-dashboard id="distributions" backend="[[_backend]]"></tf-distribution-dashboard>
</template>
</div>
</paper-header-panel>
@@ -14625,8 +13693,8 @@ Polymer({
_modeIsGraphs: function(mode) {
return mode === "graphs";
},
- _modeIsHistograms: function(mode) {
- return mode === "histograms";
+ _modeIsDistributions: function(mode) {
+ return mode === "distributions";
},
selectedDashboard: function() {
var dashboard = this.$$("#" + this.mode);