aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Dan Mané <danmane@gmail.com>2016-03-11 14:57:33 -0800
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2016-03-11 20:45:08 -0800
commit65c9124086240616747e26e0aa5ef3412a3be55d (patch)
tree96efafa6cf7cee517ccdc2f4e02ba94823e48106
parentdbc57b9068da9b823dbcc3101e599da6f65f658a (diff)
Release a new TensorBoard version
Change: 117011137
-rw-r--r--WORKSPACE10
-rw-r--r--tensorflow/tensorboard/TAG2
-rw-r--r--tensorflow/tensorboard/dist/tf-tensorboard.html1158
3 files changed, 786 insertions, 384 deletions
diff --git a/WORKSPACE b/WORKSPACE
index 60b69a9c1a..981ac77ea4 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -56,7 +56,7 @@ new_git_repository(
new_git_repository(
name = "iron_a11y_keys_behavior",
build_file = "bower.BUILD",
- remote = "https://github.com/PolymerElements/iron-a11y-keys-behavior.git",
+ remote = "https://github.com/polymerelements/iron-a11y-keys-behavior.git",
tag = "v1.1.1",
)
@@ -77,7 +77,7 @@ new_git_repository(
new_git_repository(
name = "iron_behaviors",
build_file = "bower.BUILD",
- remote = "https://github.com/polymerelements/iron-behaviors.git",
+ remote = "https://github.com/PolymerElements/iron-behaviors.git",
tag = "v1.0.13",
)
@@ -168,7 +168,7 @@ new_git_repository(
new_git_repository(
name = "iron_meta",
build_file = "bower.BUILD",
- remote = "https://github.com/PolymerElements/iron-meta.git",
+ remote = "https://github.com/polymerelements/iron-meta.git",
tag = "v1.1.1",
)
@@ -322,7 +322,7 @@ new_git_repository(
new_git_repository(
name = "paper_ripple",
build_file = "bower.BUILD",
- remote = "https://github.com/polymerelements/paper-ripple.git",
+ remote = "https://github.com/PolymerElements/paper-ripple.git",
tag = "v1.0.5",
)
@@ -371,7 +371,7 @@ new_git_repository(
new_git_repository(
name = "polymer",
build_file = "bower.BUILD",
- remote = "https://github.com/polymer/polymer.git",
+ remote = "https://github.com/Polymer/polymer.git",
tag = "v1.3.1",
)
diff --git a/tensorflow/tensorboard/TAG b/tensorflow/tensorboard/TAG
index b1bd38b62a..8351c19397 100644
--- a/tensorflow/tensorboard/TAG
+++ b/tensorflow/tensorboard/TAG
@@ -1 +1 @@
-13
+14
diff --git a/tensorflow/tensorboard/dist/tf-tensorboard.html b/tensorflow/tensorboard/dist/tf-tensorboard.html
index 3fcd43c7d5..492a5d45ce 100644
--- a/tensorflow/tensorboard/dist/tf-tensorboard.html
+++ b/tensorflow/tensorboard/dist/tf-tensorboard.html
@@ -16,8 +16,6 @@ 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.
==============================================================================*/
-/// <reference path="../../typings/tsd.d.ts" />
-/// <reference path="../plottable/plottable.d.ts" />
var TF;
(function (TF) {
/* The DataCoordinator generates TF.Datasets for each run/tag combination,
@@ -65,11 +63,16 @@ var TF;
return dataset;
};
return DataCoordinator;
- })();
+ }());
TF.DataCoordinator = DataCoordinator;
})(TF || (TF = {}));
</script>
- <script>/* Copyright 2015 Google Inc. All Rights Reserved.
+ <script>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 __());
+};
+/* Copyright 2015 Google Inc. 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.
@@ -83,13 +86,6 @@ 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 __());
-};
-/// <reference path="../../typings/tsd.d.ts" />
-/// <reference path="../plottable/plottable.d.ts" />
var TF;
(function (TF) {
/* An extension of Plottable.Dataset that knows how to load data from a backend.
@@ -123,7 +119,7 @@ var TF;
});
};
return Dataset;
- })(Plottable.Dataset);
+ }(Plottable.Dataset));
TF.Dataset = Dataset;
})(TF || (TF = {}));
</script>
@@ -770,8 +766,6 @@ 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.
==============================================================================*/
-/// <reference path="../../typings/tsd.d.ts" />
-/// <reference path="../plottable/plottable.d.ts" />
var TF;
(function (TF) {
var Urls;
@@ -791,8 +785,18 @@ var TF;
function individualImageUrl(query) {
return "/data/individualImage?" + query;
}
- function graphUrl(run) {
- return "/data/graph?run=" + encodeURIComponent(run);
+ function graphUrl(run, limit_attr_size, large_attrs_key) {
+ var query_params = [["run", run]];
+ if (limit_attr_size != null) {
+ query_params.push(["limit_attr_size", String(limit_attr_size)]);
+ }
+ if (large_attrs_key != null) {
+ query_params.push(["large_attrs_key", large_attrs_key]);
+ }
+ var query = query_params.map(function (param) {
+ return param[0] + "=" + encodeURIComponent(param[1]);
+ }).join("&");
+ return "/data/graph?" + query;
}
return {
runs: function () { return "/data/runs"; },
@@ -806,7 +810,21 @@ var TF;
}
Urls.productionRouter = productionRouter;
;
- function demoRouter(dataDir) {
+ function demoRouter(dataDir, oldVersion) {
+ if (oldVersion === void 0) { oldVersion = false; }
+ if (oldVersion) {
+ return {
+ runs: function () { return dataDir + "runs.json"; },
+ graph: function (run) { return dataDir + run + "-graph.pbtxt"; },
+ scalars: function (tag, run) {
+ return dataDir + run.split("_")[0] + ".json";
+ },
+ histograms: function () { return null; },
+ compressedHistograms: function () { return null; },
+ images: function () { return null; },
+ individualImage: function () { return null; }
+ };
+ }
/* Retrieves static .json data generated by demo_from_server.py */
function demoRoute(route) {
return function (tag, run) {
@@ -858,7 +876,7 @@ var TF;
},
};
TF.Urls.routes.forEach(function(route) {
- /* for each route (other than runs, handled seperately):
+ /* for each route (other than runs, handled separately):
* out`RouteName`: {
* type: Function,
* readOnly: true,
@@ -1254,7 +1272,6 @@ 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.
==============================================================================*/
-/// <reference path="../../typings/tsd.d.ts" />
var Categorizer;
(function (Categorizer) {
/* Canonical TensorFlow ops are namespaced using forward slashes.
@@ -1568,11 +1585,16 @@ var Plottable;
draw();
};
return DragZoomLayer;
- })(Plottable.Components.SelectionBoxLayer);
+ }(Plottable.Components.SelectionBoxLayer));
Plottable.DragZoomLayer = DragZoomLayer;
})(Plottable || (Plottable = {}));
</script>
- <script>/* Copyright 2015 Google Inc. All Rights Reserved.
+ <script>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 __());
+};
+/* Copyright 2015 Google Inc. 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.
@@ -1586,13 +1608,6 @@ 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 __());
-};
-/// <reference path="../../typings/tsd.d.ts" />
-/// <reference path="../plottable/plottable.d.ts" />
var TF;
(function (TF) {
var Y_TOOLTIP_FORMATTER_PRECISION = 4;
@@ -1710,7 +1725,7 @@ var TF;
this.outer.destroy();
};
return BaseChart;
- })();
+ }());
TF.BaseChart = BaseChart;
var LineChart = (function (_super) {
__extends(LineChart, _super);
@@ -1732,7 +1747,7 @@ var TF;
this.plot.datasets(datasets);
};
return LineChart;
- })(BaseChart);
+ }(BaseChart));
TF.LineChart = LineChart;
var HistogramChart = (function (_super) {
__extends(HistogramChart, _super);
@@ -1773,7 +1788,7 @@ var TF;
return new Plottable.Components.Group([new Plottable.Components.Group(plots), group]);
};
return HistogramChart;
- })(BaseChart);
+ }(BaseChart));
TF.HistogramChart = HistogramChart;
/* Create a formatter function that will switch between exponential and
* regular display depending on the scale of the number being formatted,
@@ -2333,19 +2348,19 @@ var TF;
<div id="fullContainer" class="container scrollbar">
<div id="topRow" class="container">
<div class="noshrink" id="paddingCell"></div>
- <template is="dom-repeat" items="[[_runs]]" sort="_sort" as="run">
+ <template is="dom-repeat" items="[[_runs]]" as="run">
<div class="run-name-cell noshrink">
<span>[[run]]</span>
</div>
</template>
</div>
<div id="bottomContainer" class="container">
- <template is="dom-repeat" items="[[_tags]]" sort="_sort" as="tag">
+ <template is="dom-repeat" items="[[_tags]]" as="tag">
<div class="image-row container noshrink">
<div class="tag-name-cell noshrink">
<span class="tag-name">[[tag]]</span>
</div>
- <template is="dom-repeat" items="[[_runs]]" sort="_sort" as="run">
+ <template is="dom-repeat" items="[[_runs]]" as="run">
<div class="image-cell noshrink">
<template is="dom-if" if="[[_exists(run, tag, runToImages.*)]]">
<tf-image-loader id="loader" run="[[run]]" tag="[[tag]]" images-generator="[[imagesGenerator]]" individual-image-generator="[[individualImageGenerator]]">
@@ -2429,18 +2444,16 @@ var TF;
individualImageGenerator: Function,
},
_getTags: function(runToImages) {
- return _.chain(runToImages.base).values().flatten().union().value();
+ var r2i = runToImages.base;
+ return _.chain(r2i).values().flatten().union().value().sort();
},
_getRuns: function(runToImages) {
var r2i = runToImages.base;
- return _.keys(r2i).filter(function(x) {return r2i[x].length > 0;});
+ return _.keys(r2i).filter((x) => r2i[x].length > 0).sort();
},
_exists: function (run, tag, runToImages) {
- runToImages = runToImages.base;
- return runToImages[run].indexOf(tag) !== -1;
- },
- _sort: function(a, b) {
- return a > b;
+ var r2i = runToImages.base;
+ return r2i[run].indexOf(tag) !== -1;
},
});
</script>
@@ -2527,7 +2540,6 @@ Polymer({
progress: {
type: Object,
notify: true,
- readOnly: true // Produces, does not consume.
},
datasets: Array,
hasStats: {
@@ -2554,39 +2566,35 @@ Polymer({
type: String,
readOnly: true,
notify: true
- }
+ },
+ outHierarchyParams: {
+ type: Object,
+ readOnly: true,
+ notify: true
+ },
},
observers: [
'_selectedDatasetChanged(selectedDataset, datasets)'
],
_parseAndConstructHierarchicalGraph: function(dataset, pbTxtContent) {
- var self = this;
// Reset the progress bar to 0.
- self._setProgress({
+ this.set('progress', {
value: 0,
msg: ''
});
- var tracker = {
- setMessage: function(msg) {
- self._setProgress({
- value: self.progress.value,
- msg: msg
- });
- },
- updateProgress: function(value) {
- self._setProgress({
- value: self.progress.value + value,
- msg: self.progress.msg
- });
- },
- reportError: function(msg) {
- self._setProgress({
- value: self.progress.value,
- msg: msg,
- error: true
- });
- },
+ var tracker = tf.getTracker(this);
+ var hierarchyParams = {
+ verifyTemplate: true,
+ // If a set of numbered op nodes has at least this number of nodes
+ // then group them into a series node.
+ seriesNodeMinSize: 5,
+ // A map of series node names to series grouping settings, to indicate
+ // if a series is to be rendered as grouped or ungrouped.
+ // Starts out empty which allows the renderer to decide which series
+ // are initially rendered grouped and which aren't.
+ seriesMap: {},
};
+ this._setOutHierarchyParams(hierarchyParams);
var statsJson;
var dataTracker = tf.getSubtaskTracker(tracker, 30, 'Data');
tf.graph.parser.readAndParseData(dataset, pbTxtContent, dataTracker)
@@ -2630,12 +2638,6 @@ Polymer({
tf.graph.joinStatsInfoWithGraph(graph, statsJson);
});
}
- var hierarchyParams = {
- verifyTemplate: true,
- // If a set of numbered op nodes has at least this number of nodes
- // then group them into a series node.
- seriesNodeMinSize: 5,
- };
var hierarchyTracker = tf.getSubtaskTracker(tracker, 50,
'Namespace hierarchy');
return tf.graph.hierarchy.build(graph, hierarchyParams, hierarchyTracker);
@@ -2646,8 +2648,10 @@ Polymer({
this._setHasStats(statsJson != null);
this._setOutGraphHierarchy(graphHierarchy);
}.bind(this))
- .catch(function(reason) {
- tracker.reportError("Graph visualization failed: " + reason);
+ .catch(function(e) {
+ // Generic error catch, for errors that happened outside
+ // asynchronous tasks.
+ tracker.reportError("Graph visualization failed: " + e, e);
});
},
_selectedDatasetChanged: function(datasetIndex, datasets) {
@@ -2692,7 +2696,6 @@ 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.
==============================================================================*/
-/// <reference path="../../../typings/tsd.d.ts" />
var tf;
(function (tf) {
/**
@@ -2710,6 +2713,40 @@ var tf;
}
tf.time = time;
/**
+ * Creates a tracker that sets the progress property of the
+ * provided polymer component. The provided component must have
+ * a property called 'progress' that is not read-only. The progress
+ * property is an object with a numerical 'value' property and a
+ * string 'msg' property.
+ */
+ function getTracker(polymerComponent) {
+ return {
+ setMessage: function (msg) {
+ polymerComponent.set("progress", {
+ value: polymerComponent.progress.value,
+ msg: msg
+ });
+ },
+ updateProgress: function (value) {
+ polymerComponent.set("progress", {
+ value: polymerComponent.progress.value + value,
+ msg: polymerComponent.progress.msg
+ });
+ },
+ reportError: function (msg, err) {
+ // Log the stack trace in the console.
+ console.error(err.stack);
+ // And send a user-friendly message to the UI.
+ polymerComponent.set("progress", {
+ value: polymerComponent.progress.value,
+ msg: msg,
+ error: true
+ });
+ },
+ };
+ }
+ tf.getTracker = getTracker;
+ /**
* Creates a tracker for a subtask given the parent tracker, the total progress
* of the subtask and the subtask message. The parent task should pass a
* subtracker to its subtasks. The subtask reports its own progress which
@@ -2720,7 +2757,7 @@ var tf;
setMessage: function (progressMsg) {
// The parent should show a concatenation of its message along with
// its subtask tracker message.
- parentTracker.setMessage(subtaskMsg + " : " + progressMsg);
+ parentTracker.setMessage(subtaskMsg + ": " + progressMsg);
},
updateProgress: function (incrementValue) {
// Update the parent progress relative to the child progress.
@@ -2729,10 +2766,10 @@ var tf;
parentTracker
.updateProgress(incrementValue * impactOnTotalProgress / 100);
},
- reportError: function (errorMsg) {
+ reportError: function (msg, err) {
// The parent should show a concatenation of its message along with
// its subtask error message.
- parentTracker.reportError(subtaskMsg + " : " + errorMsg);
+ parentTracker.reportError(subtaskMsg + ": " + msg, err);
}
};
}
@@ -2755,7 +2792,9 @@ var tf;
resolve(result);
}
catch (e) {
- reject(result);
+ // Errors that happen inside asynchronous tasks are
+ // reported to the tracker using a user-friendly message.
+ tracker.reportError("Failed " + msg, e);
}
}, ASYNC_TASK_DELAY);
});
@@ -2785,8 +2824,6 @@ 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.
==============================================================================*/
-/// <reference path="../../../typings/tsd.d.ts" />
-/// <reference path="common.ts" />
var tf;
(function (tf) {
var graph;
@@ -2794,6 +2831,13 @@ var tf;
/** Delimiter used in node names to denote namespaces. */
graph_1.NAMESPACE_DELIM = "/";
graph_1.ROOT_NAME = "__root__";
+ /** Attribute key used for storing attributes that are too large. */
+ graph_1.LARGE_ATTRS_KEY = "_too_large_attrs";
+ /**
+ * Maximum allowed size in bytes, before the attribute is considered large
+ * and filtered out of the graph.
+ */
+ graph_1.LIMIT_ATTR_SIZE = 1024;
// Separator between the source and the destination name of the edge.
graph_1.EDGE_KEY_DELIM = "--";
(function (GraphType) {
@@ -2825,6 +2869,15 @@ var tf;
})(graph_1.InclusionType || (graph_1.InclusionType = {}));
var InclusionType = graph_1.InclusionType;
;
+ /** Indicates if a series is to be grouped in the graph when rendered. */
+ (function (SeriesGroupingType) {
+ SeriesGroupingType[SeriesGroupingType["GROUP"] = 0] = "GROUP";
+ SeriesGroupingType[SeriesGroupingType["UNGROUP"] = 1] = "UNGROUP";
+ })(graph_1.SeriesGroupingType || (graph_1.SeriesGroupingType = {}));
+ var SeriesGroupingType = graph_1.SeriesGroupingType;
+ ;
+ /** Attribute key reserved for the shapes of the output tensors. */
+ var OUTPUT_SHAPES_KEY = "_output_shapes";
/**
* A SlimGraph is inspired by graphlib.Graph, but having only the functionality
* that we need.
@@ -2835,7 +2888,7 @@ var tf;
this.edges = [];
}
return SlimGraph;
- })();
+ }());
graph_1.SlimGraph = SlimGraph;
var EllipsisNodeImpl = (function () {
/**
@@ -2857,7 +2910,7 @@ var tf;
this.name = "... " + numNodes + " more";
};
return EllipsisNodeImpl;
- })();
+ }());
graph_1.EllipsisNodeImpl = EllipsisNodeImpl;
;
/**
@@ -2869,17 +2922,18 @@ var tf;
* Constructs a new Op node.
*
* @param rawNode The raw node.
- * @param normalizedInputs An array of normalized
- * inputs that denote the incoming edges to the current node. Each input
- * contains the normalized name of the source node, whether it has a
- * number part and whether it is a control dependency.
*/
- function OpNodeImpl(rawNode, normalizedInputs) {
+ function OpNodeImpl(rawNode) {
this.op = rawNode.op;
this.name = rawNode.name;
this.device = rawNode.device;
this.attr = rawNode.attr;
- this.inputs = normalizedInputs;
+ // An array of normalized inputs that denote the incoming edges to
+ // the current node. Each input contains the normalized name of the
+ // source node, whether it has a number part and whether it is a
+ // control dependency.
+ this.inputs = normalizeInputs(rawNode.input);
+ this.outputShapes = extractOutputShapes(rawNode.attr);
// additional properties
this.type = NodeType.OP;
this.isGroupNode = false;
@@ -2888,9 +2942,10 @@ var tf;
this.outEmbeddings = [];
this.parentNode = null;
this.include = InclusionType.UNSPECIFIED;
+ this.owningSeries = null;
}
return OpNodeImpl;
- })();
+ }());
;
function createMetanode(name, opt) {
if (opt === void 0) { opt = {}; }
@@ -2912,11 +2967,11 @@ var tf;
nodeStats.nodeName + graph_1.NAMESPACE_DELIM + "(" + nodeStats.nodeName + ")";
if (nodeName in graph.nodes) {
// Compute the total bytes used.
- var totalBytes = 0;
+ var totalBytes_1 = 0;
if (nodeStats.memory) {
_.each(nodeStats.memory, function (alloc) {
if (alloc.totalBytes) {
- totalBytes += Number(alloc.totalBytes);
+ totalBytes_1 += Number(alloc.totalBytes);
}
});
}
@@ -2926,7 +2981,7 @@ var tf;
return _.map(output.tensorDescription.shape.dim, function (dim) { return Number(dim.size); });
});
}
- graph.nodes[nodeName].stats = new NodeStats(totalBytes, Number(nodeStats.allEndRelMicros), outputSize);
+ graph.nodes[nodeName].stats = new NodeStats(totalBytes_1, Number(nodeStats.allEndRelMicros), outputSize);
}
});
});
@@ -2955,7 +3010,7 @@ var tf;
}
};
return NodeStats;
- })();
+ }());
graph_1.NodeStats = NodeStats;
var MetanodeImpl = (function () {
/** A label object for meta-nodes in the graph hierarchy */
@@ -3025,7 +3080,7 @@ var tf;
return leaves;
};
return MetanodeImpl;
- })();
+ }());
;
function createMetaedge(v, w) {
return new MetaedgeImpl(v, w);
@@ -3043,8 +3098,9 @@ var tf;
this.numRegularEdges = 0;
this.numControlEdges = 0;
this.numRefEdges = 0;
+ this.totalSize = 0;
}
- MetaedgeImpl.prototype.addBaseEdge = function (edge) {
+ MetaedgeImpl.prototype.addBaseEdge = function (edge, h) {
this.baseEdgeList.push(edge);
if (edge.isControlDependency) {
this.numControlEdges += 1;
@@ -3055,9 +3111,39 @@ var tf;
if (edge.isReferenceEdge) {
this.numRefEdges += 1;
}
+ // Compute the size of the tensor flowing through this
+ // base edge.
+ this.totalSize += MetaedgeImpl.computeSizeOfEdge(edge, h);
+ };
+ MetaedgeImpl.computeSizeOfEdge = function (edge, h) {
+ var opNode = h.node(edge.v);
+ if (opNode.outputShapes == null) {
+ // No shape information. Asssume a single number. This gives
+ // a lower bound for the total size.
+ return 1;
+ }
+ // Sum the sizes of all output tensors.
+ return _(opNode.outputShapes).map(function (shape) {
+ // If the shape is unknown, treat it as 1 when computing
+ // total size. This gives a lower bound for the total size.
+ if (shape == null) {
+ return 1;
+ }
+ // Multiply all shapes to get the total size of the tensor.
+ // E.g. The total size of [4, 2, 1] is 4 * 2 * 1.
+ return _(shape).reduce(function (accumulated, currSize) {
+ // If this particular dimension is unknown, treat
+ // it as 1 when computing total size. This gives a lower bound
+ // for the total size.
+ if (currSize === -1) {
+ currSize = 1;
+ }
+ return accumulated * currSize;
+ }, 1);
+ }).sum();
};
return MetaedgeImpl;
- })();
+ }());
function createSeriesNode(prefix, suffix, parent, clusterId, name) {
return new SeriesNodeImpl(prefix, suffix, parent, clusterId, name);
}
@@ -3091,7 +3177,49 @@ var tf;
this.include = InclusionType.UNSPECIFIED;
}
return SeriesNodeImpl;
- })();
+ }());
+ /**
+ * Extracts the shapes of the output tensors from the attr property in the
+ * node proto.
+ */
+ function extractOutputShapes(attr) {
+ var result = null;
+ // We don't know anything about the output tensors.
+ if (!attr) {
+ return null;
+ }
+ for (var i = 0; i < attr.length; i++) {
+ var _a = attr[i], key = _a.key, value = _a.value;
+ if (key === OUTPUT_SHAPES_KEY) {
+ // Map all output tensors into array of numbers denoting their shape.
+ var result_1 = value.list.shape.map(function (shape) {
+ if (shape.unknown_rank) {
+ // This output tensor is of unknown rank. We don't know if it is a
+ // scalar, or a tensor, or of what shape it is.
+ return null;
+ }
+ if (shape.dim == null ||
+ (shape.dim.length === 1 && shape.dim[0].size == null)) {
+ // This output tensor is a scalar.
+ return [];
+ }
+ // This output tensor has a known rank. Map each dimension size
+ // into a number.
+ return shape.dim.map(function (dim) {
+ // Size can be -1 if this particular dimension is unknown.
+ return dim.size;
+ });
+ });
+ // Since we already processed it, remove the entry from the attribute
+ // list (saves memory).
+ attr.splice(i, 1);
+ return result_1;
+ }
+ }
+ // We didn't find OUTPUT_SHAPES_KEY in attributes, so we don't know anything
+ // about the output tensors.
+ return result;
+ }
/**
* Normalizes the inputs and extracts associated metadata:
* 1) Inputs can contain a colon followed by a number at the end
@@ -3169,8 +3297,7 @@ var tf;
var opNodes = new Array(rawNodes.length);
var index = 0;
_.each(rawNodes, function (rawNode) {
- var normalizedInputs = normalizeInputs(rawNode.input);
- var opNode = new OpNodeImpl(rawNode, normalizedInputs);
+ var opNode = new OpNodeImpl(rawNode);
if (isInEmbeddedPred(opNode)) {
embeddingNodeNames.push(opNode.name);
inEmbedding[opNode.name] = opNode;
@@ -3252,9 +3379,6 @@ var tf;
});
return graph;
}, tracker);
- })
- .catch(function (reason) {
- throw new Error("Failure creating graph");
});
}
graph_1.build = build;
@@ -3410,6 +3534,34 @@ var tf;
}
graph_1.getIncludeNodeButtonString = getIncludeNodeButtonString;
;
+ /**
+ * Returns the string for the series node grouping toggle button, dependant
+ * on the provided current SeriesGroupingType.
+ */
+ function getGroupSeriesNodeButtonString(group) {
+ if (group === tf.graph.SeriesGroupingType.GROUP) {
+ return "Ungroup this series of nodes";
+ }
+ else {
+ return "Group this series of nodes";
+ }
+ }
+ graph_1.getGroupSeriesNodeButtonString = getGroupSeriesNodeButtonString;
+ ;
+ /**
+ * Toggle the node series grouping option in the provided map, setting it
+ * to ungroup if the series is not already in the map.
+ */
+ function toggleNodeSeriesGroup(map, name) {
+ if (!(name in map) || map[name] === tf.graph.SeriesGroupingType.GROUP) {
+ map[name] = tf.graph.SeriesGroupingType.UNGROUP;
+ }
+ else {
+ map[name] = tf.graph.SeriesGroupingType.GROUP;
+ }
+ }
+ graph_1.toggleNodeSeriesGroup = toggleNodeSeriesGroup;
+ ;
})(graph = tf.graph || (tf.graph = {}));
})(tf || (tf = {})); // close module tf.graph
</script>
@@ -3427,8 +3579,6 @@ 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.
==============================================================================*/
-/// <reference path="../../../typings/tsd.d.ts" />
-/// <reference path="common.ts" />
var tf;
(function (tf) {
var graph;
@@ -3512,9 +3662,6 @@ var tf;
nodes: nodes,
statsJson: statsJson
};
- })
- .catch(function (reason) {
- throw new Error("Failure parsing graph definition");
});
}
parser.readAndParseData = readAndParseData;
@@ -3552,7 +3699,10 @@ var tf;
"node.attr.value.list.type": true,
"node.attr.value.shape.dim": true,
"node.attr.value.tensor.string_val": true,
- "node.attr.value.tensor.tensor_shape.dim": true
+ "node.attr.value.tensor.tensor_shape.dim": true,
+ "node.attr.value.list.shape": true,
+ "node.attr.value.list.shape.dim": true,
+ "node.attr.value.list.s": true
};
/**
* Adds a value, given the attribute name and the host object. If the
@@ -3630,8 +3780,6 @@ 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.
==============================================================================*/
-/// <reference path="graph.ts" />
-/// <reference path="template.ts" />
/**
* Package for the Graph Hierarchy for TensorFlow graph.
*/
@@ -3727,7 +3875,7 @@ var tf;
}
// Copy the BaseEdge from the parent's Metaedge into this
// bridgegraph Metaedge.
- bridgeMetaedge.addBaseEdge(baseEdge);
+ bridgeMetaedge.addBaseEdge(baseEdge, _this);
});
})
.value(); // force lodash chain execution.
@@ -3819,16 +3967,14 @@ var tf;
HierarchyImpl.prototype.getOneWayEdges = function (node, inEdges) {
var edges = { control: [], regular: [] };
// A node with no parent cannot have any edges.
- if (!node.parentNode) {
+ if (!node.parentNode || !node.parentNode.isGroupNode) {
return edges;
}
- if (node.parentNode.isGroupNode) {
- var parentNode = node.parentNode;
- var metagraph = parentNode.metagraph;
- var bridgegraph = this.getBridgegraph(parentNode.name);
- findEdgeTargetsInGraph(metagraph, node, inEdges, edges);
- findEdgeTargetsInGraph(bridgegraph, node, inEdges, edges);
- }
+ var parentNode = node.parentNode;
+ var metagraph = parentNode.metagraph;
+ var bridgegraph = this.getBridgegraph(parentNode.name);
+ findEdgeTargetsInGraph(metagraph, node, inEdges, edges);
+ findEdgeTargetsInGraph(bridgegraph, node, inEdges, edges);
return edges;
};
/**
@@ -3909,7 +4055,7 @@ var tf;
return function (templateId) { return templateIndex(templateId); };
};
return HierarchyImpl;
- })();
+ }());
/**
* Internal utility function - given a graph (should be either a metagraph or a
* bridgegraph) and a node which is known to be in that graph, determine
@@ -3923,21 +4069,23 @@ var tf;
* Discovered target names are appended to the targets array.
*/
function findEdgeTargetsInGraph(graph, node, inbound, targets) {
- _.each(graph.edges(), function (e) {
- var _a = inbound ? [e.w, e.v] : [e.v, e.w], selfName = _a[0], otherName = _a[1];
- if (selfName === node.name) {
- if (node.isGroupNode) {
- var targetList = graph.edge(e).numRegularEdges
- ? targets.regular : targets.control;
- targetList.push(otherName);
- }
- else {
- _.each(graph.edge(e).baseEdgeList, function (baseEdge) {
- var targetList = baseEdge.isControlDependency
- ? targets.control : targets.regular;
- targetList.push(inbound ? baseEdge.v : baseEdge.w);
- });
- }
+ var edges = inbound ? graph.inEdges(node.name) : graph.outEdges(node.name);
+ _.each(edges, function (e) {
+ var otherName = inbound ? e.v : e.w;
+ var metaedge = graph.edge(e);
+ if (node.isGroupNode && metaedge.baseEdgeList.length > 1) {
+ var targetList = metaedge.numRegularEdges
+ ? targets.regular : targets.control;
+ targetList.push(otherName);
+ }
+ else {
+ // Enumerate all the base edges if the node is an OpNode, or the
+ // metaedge has only 1 edge in it.
+ _.each(metaedge.baseEdgeList, function (baseEdge) {
+ var targetList = baseEdge.isControlDependency
+ ? targets.control : targets.regular;
+ targetList.push(inbound ? baseEdge.v : baseEdge.w);
+ });
}
});
}
@@ -3962,7 +4110,7 @@ var tf;
.then(function () {
return tf.runAsyncTask("Detect series", 20, function () {
if (params.seriesNodeMinSize > 0) {
- groupSeries(h.root, h, seriesNames, params.seriesNodeMinSize);
+ groupSeries(h.root, h, seriesNames, params.seriesNodeMinSize, params.seriesMap);
}
}, tracker);
})
@@ -3978,8 +4126,6 @@ var tf;
})
.then(function () {
return h;
- }).catch(function (reason) {
- throw new Error("Failure creating graph hierarchy");
});
}
hierarchy_1.build = build;
@@ -4091,7 +4237,7 @@ var tf;
!baseEdge.isControlDependency) {
sharedAncestorNode.hasNonControlEdges = true;
}
- metaedge.addBaseEdge(baseEdge);
+ metaedge.addBaseEdge(baseEdge, h);
});
}
;
@@ -4103,17 +4249,21 @@ var tf;
*
* @param metanode
* @param hierarchy
+ * @param seriesNames Map of node names to their series they are contained in.
+ * This should be provided empty and is populated by this method.
* @param threshold If the series has this many nodes or more, then group them
* into a series.
+ * @param map Map of series names to their series grouping type, if one has
+ * been set.
* @return A dictionary from node name to series node name that contains the
* node.
*/
- function groupSeries(metanode, hierarchy, seriesNames, threshold) {
+ function groupSeries(metanode, hierarchy, seriesNames, threshold, map) {
var metagraph = metanode.metagraph;
_.each(metagraph.nodes(), function (n) {
var child = metagraph.node(n);
if (child.type === tf.graph.NodeType.META) {
- groupSeries(child, hierarchy, seriesNames, threshold);
+ groupSeries(child, hierarchy, seriesNames, threshold, map);
}
});
var clusters = clusterNodes(metagraph);
@@ -4122,7 +4272,21 @@ var tf;
// metagraph.
_.each(seriesDict, function (seriesNode, seriesName) {
var nodeMemberNames = seriesNode.metagraph.nodes();
- if (nodeMemberNames.length < threshold) {
+ _.each(nodeMemberNames, function (n) {
+ var child = metagraph.node(n);
+ if (!child.owningSeries) {
+ child.owningSeries = seriesName;
+ }
+ });
+ // If the series contains less than the threshold number of nodes and
+ // this series has not been adding to the series map, then set this
+ // series to be shown ungrouped in the map.
+ if (nodeMemberNames.length < threshold && !(seriesNode.name in map)) {
+ map[seriesNode.name] = tf.graph.SeriesGroupingType.UNGROUP;
+ }
+ // If the series is in the map as ungrouped then do not group the series.
+ if (seriesNode.name in map
+ && map[seriesNode.name] === tf.graph.SeriesGroupingType.UNGROUP) {
return;
}
hierarchy.setNode(seriesName, seriesNode); // add to the index
@@ -4202,9 +4366,6 @@ var tf;
}
else {
prefix = isGroup ? leaf.substr(0, leaf.length - 1) : leaf;
- if (prefix.charAt(prefix.length - 1) !== "_") {
- prefix += "_";
- }
id = 0;
suffix = isGroup ? "*" : "";
}
@@ -4252,19 +4413,24 @@ var tf;
function addSeriesToDict(seriesNodes, seriesDict, clusterId, metagraph) {
if (seriesNodes.length > 1) {
var curSeriesName = graph_1.getSeriesNodeName(seriesNodes[0].prefix, seriesNodes[0].suffix, seriesNodes[0].parent, seriesNodes[0].clusterId, seriesNodes[seriesNodes.length - 1].clusterId);
- var curSeriesNode = graph_1.createSeriesNode(seriesNodes[0].prefix, seriesNodes[0].suffix, seriesNodes[0].parent, clusterId, curSeriesName);
+ var curSeriesNode_1 = graph_1.createSeriesNode(seriesNodes[0].prefix, seriesNodes[0].suffix, seriesNodes[0].parent, clusterId, curSeriesName);
_.each(seriesNodes, function (node) {
- curSeriesNode.ids.push(node.clusterId);
- curSeriesNode.metagraph.setNode(node.name, metagraph.node(node.name));
+ curSeriesNode_1.ids.push(node.clusterId);
+ curSeriesNode_1.metagraph.setNode(node.name, metagraph.node(node.name));
});
- seriesDict[curSeriesName] = curSeriesNode;
+ seriesDict[curSeriesName] = curSeriesNode_1;
}
}
})(hierarchy = graph_1.hierarchy || (graph_1.hierarchy = {}));
})(graph = tf.graph || (tf.graph = {}));
})(tf || (tf = {})); // close module tf.graph.hierarchy
</script>
-<script>/* Copyright 2015 Google Inc. All Rights Reserved.
+<script>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 __());
+};
+/* Copyright 2015 Google Inc. 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.
@@ -4278,13 +4444,6 @@ 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 __());
-};
-/// <reference path="graph.ts" />
-/// <reference path="hierarchy.ts" />
/**
* Package for the Render Hierarchy for TensorFlow graph.
*/
@@ -4346,6 +4505,14 @@ var tf;
DEFAULT_FILL: "white",
DEFAULT_STROKE: "#b2b2b2"
};
+ /** The minimum stroke width of an edge. */
+ var MIN_EDGE_WIDTH = 0.75;
+ /** The maximum stroke width of an edge. */
+ var MAX_EDGE_WIDTH = 12;
+ /** The exponent used in the power scale for edge thickness. */
+ var EDGE_WIDTH_SCALE_EXPONENT = 0.3;
+ /** The domain (min and max value) for the edge width. */
+ var DOMAIN_EDGE_WIDTH_SCALE = [1, 5E6];
/**
* Stores the rendering information, such as x and y coordinates,
* for each node in the graph.
@@ -4357,6 +4524,11 @@ var tf;
this.deviceColorMap = d3.scale.ordinal()
.domain(hierarchy.devices)
.range(_.map(d3.range(hierarchy.devices.length), render.MetanodeColors.DEVICE_PALETTE));
+ this.edgeWidthScale = d3.scale.pow()
+ .exponent(EDGE_WIDTH_SCALE_EXPONENT)
+ .domain(DOMAIN_EDGE_WIDTH_SCALE)
+ .range([MIN_EDGE_WIDTH, MAX_EDGE_WIDTH])
+ .clamp(true);
var topLevelGraph = hierarchy.root.metagraph;
// Find the maximum and minimum memory usage.
var memoryExtent = d3.extent(topLevelGraph.nodes(), function (nodeName, index) {
@@ -4396,6 +4568,12 @@ var tf;
return this.index[nodeName];
};
/**
+ * Get the underlying node in the hierarchical graph by its name.
+ */
+ RenderGraphInfo.prototype.getNodeByName = function (nodeName) {
+ return this.hierarchy.node(nodeName);
+ };
+ /**
* Get a previously created RenderNodeInfo for the specified node name,
* or create one if it hasn't been created yet.
*/
@@ -4409,6 +4587,12 @@ var tf;
return this.index[nodeName];
}
var node = this.hierarchy.node(nodeName);
+ // Exit early if the node does not exist in the hierarchy. This can happen
+ // when a graph is reloaded while the infocard points to a node not visible
+ // at the top-level.
+ if (!node) {
+ return null;
+ }
var renderInfo = node.isGroupNode ?
new RenderGroupNodeInfo(node) :
new RenderNodeInfo(node);
@@ -4424,11 +4608,11 @@ var tf;
var pairs = _.pairs(node.deviceHistogram);
if (pairs.length > 0) {
// Compute the total # of devices.
- var numDevices = _.sum(pairs, _.last);
+ var numDevices_1 = _.sum(pairs, _.last);
renderInfo.deviceColors = _.map(pairs, function (pair) { return ({
color: _this.deviceColorMap(pair[0]),
// Normalize to a proportion of total # of devices.
- proportion: pair[1] / numDevices
+ proportion: pair[1] / numDevices_1
}); });
}
}
@@ -4661,7 +4845,7 @@ var tf;
// (which ignores control edges) and seeing that Z comes AFTER A.
//
// The property of being backwards is independent of whether the edge
- // is inbound or outbound. In the preceeding example, if we were building
+ // is inbound or outbound. In the preceding example, if we were building
// the subhierarchy for Z, we'd find bridge edge Z/Y=>A, walk to its
// topmost adjoining metaedge Z=>A and discover that it's backwards.
var backwards = false;
@@ -4752,7 +4936,7 @@ var tf;
// one edge in the bridgegraph from Z->A/C.
//
// At this point, we've added a container bridge node IN to house all
- // incoming bridge nodes. We'v alse added a bridge node Z' (with parent IN)
+ // incoming bridge nodes. We've also added a bridge node Z' (with parent IN)
// to A, and a bridge edge from Z'->C.
//
// +----------------------+
@@ -4860,7 +5044,7 @@ var tf;
});
};
return RenderGraphInfo;
- })();
+ }());
render.RenderGraphInfo = RenderGraphInfo;
/**
* A class for rendering annotation object which contains label
@@ -4899,7 +5083,7 @@ var tf;
this.points = [];
}
return Annotation;
- })();
+ }());
render.Annotation = Annotation;
;
(function (AnnotationType) {
@@ -4942,7 +5126,7 @@ var tf;
this.list.push(new Annotation(ellipsisNode, new RenderNodeInfo(ellipsisNode), null, AnnotationType.ELLIPSIS, annotation.isIn));
};
return AnnotationList;
- })();
+ }());
render.AnnotationList = AnnotationList;
/**
* Contains rendering information about a node in the hierarchical graph.
@@ -4981,7 +5165,7 @@ var tf;
return !this.isInExtract && !this.isOutExtract;
};
return RenderNodeInfo;
- })();
+ }());
render.RenderNodeInfo = RenderNodeInfo;
/**
* Contains rendering information about a Metaedge from the underlying
@@ -4995,7 +5179,7 @@ var tf;
this.weight = 1;
}
return RenderMetaedgeInfo;
- })();
+ }());
render.RenderMetaedgeInfo = RenderMetaedgeInfo;
function addInAnnotation(node, predecessor, predecessorRenderInfo, edge, type, params) {
var annotation = new Annotation(predecessor, predecessorRenderInfo, edge, type, true);
@@ -5034,7 +5218,7 @@ var tf;
this.isolatedOutExtract = [];
}
return RenderGroupNodeInfo;
- })(RenderNodeInfo);
+ }(RenderNodeInfo));
render.RenderGroupNodeInfo = RenderGroupNodeInfo;
function setGroupNodeDepth(renderInfo, depth) {
if (renderInfo.coreGraph) {
@@ -5146,7 +5330,7 @@ var tf;
}
return false;
}
- /** Move nodes that are speficied to be excluded out of the core graph. */
+ /** Move nodes that are specified to be excluded out of the core graph. */
function extractSpecifiedNodes(renderNode, params) {
var graph = renderNode.coreGraph;
_.each(graph.nodes(), function (n) {
@@ -5380,8 +5564,6 @@ 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.
==============================================================================*/
-/// <reference path="graph.ts" />
-/// <reference path="hierarchy.ts" />
var tf;
(function (tf) {
var graph;
@@ -5646,10 +5828,6 @@ 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.
==============================================================================*/
-/// <reference path="../graph.ts" />
-/// <reference path="edge.ts" />
-/// <reference path="node.ts" />
-/// <reference path="../layout.ts" />
var tf;
(function (tf) {
var graph;
@@ -5874,10 +6052,10 @@ var tf;
*
* @param container D3 selection of the parent.
* @param renderNode render node of a metanode or series node.
- * @param sceneBehavior Parent scene module.
+ * @param sceneElement <tf-graph-scene> polymer element.
* @param sceneClass class attribute of the scene (default="scene").
*/
- function buildGroup(container, renderNode, sceneBehavior, sceneClass) {
+ function buildGroup(container, renderNode, sceneElement, sceneClass) {
sceneClass = sceneClass || scene.Class.Scene.GROUP;
var isNewSceneGroup = selectChild(container, "g", sceneClass).empty();
var sceneGroup = selectOrCreateChild(container, "g", sceneClass);
@@ -5897,13 +6075,13 @@ var tf;
coreNodes.reverse();
}
// Create the layer of edges for this scene (paths).
- scene.edge.buildGroup(coreGroup, renderNode.coreGraph, sceneBehavior);
+ scene.edge.buildGroup(coreGroup, renderNode.coreGraph, sceneElement);
// Create the layer of nodes for this scene (ellipses, rects etc).
- scene.node.buildGroup(coreGroup, coreNodes, sceneBehavior);
+ scene.node.buildGroup(coreGroup, coreNodes, sceneElement);
// In-extract
if (renderNode.isolatedInExtract.length > 0) {
var inExtractGroup = selectOrCreateChild(sceneGroup, "g", scene.Class.Scene.INEXTRACT);
- scene.node.buildGroup(inExtractGroup, renderNode.isolatedInExtract, sceneBehavior);
+ scene.node.buildGroup(inExtractGroup, renderNode.isolatedInExtract, sceneElement);
}
else {
selectChild(sceneGroup, "g", scene.Class.Scene.INEXTRACT).remove();
@@ -5911,7 +6089,7 @@ var tf;
// Out-extract
if (renderNode.isolatedOutExtract.length > 0) {
var outExtractGroup = selectOrCreateChild(sceneGroup, "g", scene.Class.Scene.OUTEXTRACT);
- scene.node.buildGroup(outExtractGroup, renderNode.isolatedOutExtract, sceneBehavior);
+ scene.node.buildGroup(outExtractGroup, renderNode.isolatedOutExtract, sceneElement);
}
else {
selectChild(sceneGroup, "g", scene.Class.Scene.OUTEXTRACT).remove();
@@ -5958,9 +6136,9 @@ var tf;
}
;
/** Adds a click listener to a group that fires a graph-select event */
- function addGraphClickListener(graphGroup, sceneBehavior) {
+ function addGraphClickListener(graphGroup, sceneElement) {
d3.select(graphGroup).on("click", function () {
- sceneBehavior.fire("graph-select");
+ sceneElement.fire("graph-select");
});
}
scene.addGraphClickListener = addGraphClickListener;
@@ -6061,11 +6239,6 @@ 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.
==============================================================================*/
-/// <reference path="../graph.ts" />
-/// <reference path="../render.ts" />
-/// <reference path="scene.ts" />
-/// <reference path="edge.ts" />
-/// <reference path="contextmenu.ts" />
var tf;
(function (tf) {
var graph;
@@ -6092,10 +6265,10 @@ var tf;
* @param container selection of the container.
* @param annotationData node.{in|out}Annotations
* @param d node to build group for.
- * @param sceneBehavior polymer scene element.
+ * @param sceneElement <tf-graph-scene> polymer element.
* @return selection of appended objects
*/
- function buildGroup(container, annotationData, d, sceneBehavior) {
+ function buildGroup(container, annotationData, d, sceneElement) {
// Select all children and join with data.
var annotationGroups = container.selectAll(function () {
// using d3's selector function
@@ -6110,7 +6283,7 @@ var tf;
.each(function (a) {
var aGroup = d3.select(this);
// Add annotation to the index in the scene
- sceneBehavior.addAnnotationGroup(a, d, aGroup);
+ sceneElement.addAnnotationGroup(a, d, aGroup);
// Append annotation edge
var edgeType = scene.Class.Annotation.EDGE;
var metaedge = a.renderMetaedgeInfo && a.renderMetaedgeInfo.metaedge;
@@ -6121,10 +6294,10 @@ var tf;
if (metaedge && metaedge.numRefEdges) {
edgeType += " " + scene.Class.Edge.REF_LINE;
}
- scene.edge.appendEdge(aGroup, a, sceneBehavior, edgeType);
- if (a.annotationType !== tf.graph.render.AnnotationType.ELLIPSIS) {
+ scene.edge.appendEdge(aGroup, a, sceneElement, edgeType);
+ if (a.annotationType !== graph.render.AnnotationType.ELLIPSIS) {
addAnnotationLabelFromNode(aGroup, a);
- buildShape(aGroup, a, sceneBehavior);
+ buildShape(aGroup, a);
}
else {
addAnnotationLabel(aGroup, a.node.name, a, scene.Class.Annotation.ELLIPSIS);
@@ -6138,16 +6311,16 @@ var tf;
})
.each(function (a) {
var aGroup = d3.select(this);
- update(aGroup, d, a, sceneBehavior);
- if (a.annotationType !== tf.graph.render.AnnotationType.ELLIPSIS) {
- addInteraction(aGroup, d, a, sceneBehavior);
+ update(aGroup, d, a, sceneElement);
+ if (a.annotationType !== graph.render.AnnotationType.ELLIPSIS) {
+ addInteraction(aGroup, d, a, sceneElement);
}
});
annotationGroups.exit()
.each(function (a) {
var aGroup = d3.select(this);
// Remove annotation from the index in the scene
- sceneBehavior.removeAnnotationGroup(a, d, aGroup);
+ sceneElement.removeAnnotationGroup(a, d, aGroup);
})
.remove();
return annotationGroups;
@@ -6158,11 +6331,11 @@ var tf;
* Maps an annotation enum to a class name used in css rules.
*/
function annotationToClassName(annotationType) {
- return (tf.graph.render.AnnotationType[annotationType] || "")
+ return (graph.render.AnnotationType[annotationType] || "")
.toLowerCase() || null;
}
- function buildShape(aGroup, a, sceneBehavior) {
- if (a.annotationType === tf.graph.render.AnnotationType.SUMMARY) {
+ function buildShape(aGroup, a) {
+ if (a.annotationType === graph.render.AnnotationType.SUMMARY) {
var summary = scene.selectOrCreateChild(aGroup, "use");
summary.attr({
"class": "summary",
@@ -6195,16 +6368,16 @@ var tf;
.text(label)
.append("title").text(titleText);
}
- function addInteraction(selection, d, annotation, sceneBehavior) {
+ function addInteraction(selection, d, annotation, sceneElement) {
selection
.on("mouseover", function (a) {
- sceneBehavior.fire("annotation-highlight", {
+ sceneElement.fire("annotation-highlight", {
name: a.node.name,
hostName: d.node.name
});
})
.on("mouseout", function (a) {
- sceneBehavior.fire("annotation-unhighlight", {
+ sceneElement.fire("annotation-unhighlight", {
name: a.node.name,
hostName: d.node.name
});
@@ -6213,14 +6386,14 @@ var tf;
// Stop this event"s propagation so that it isn't also considered a
// graph-select.
d3.event.stopPropagation();
- sceneBehavior.fire("annotation-select", {
+ sceneElement.fire("annotation-select", {
name: a.node.name,
hostName: d.node.name
});
});
- if (annotation.annotationType !== tf.graph.render.AnnotationType.SUMMARY &&
- annotation.annotationType !== tf.graph.render.AnnotationType.CONSTANT) {
- selection.on("contextmenu", tf.graph.scene.contextmenu.getMenu(tf.graph.scene.node.getContextMenu(annotation.node, sceneBehavior)));
+ if (annotation.annotationType !== graph.render.AnnotationType.SUMMARY &&
+ annotation.annotationType !== graph.render.AnnotationType.CONSTANT) {
+ selection.on("contextmenu", scene.contextmenu.getMenu(scene.node.getContextMenu(annotation.node, sceneElement)));
}
}
;
@@ -6230,18 +6403,18 @@ var tf;
* @param aGroup selection of a "g.annotation" element.
* @param d Host node data.
* @param a annotation node data.
- * @param scene Polymer scene element.
+ * @param scene <tf-graph-scene> polymer element.
*/
- function update(aGroup, d, a, sceneBehavior) {
+ function update(aGroup, d, a, sceneElement) {
var cx = graph.layout.computeCXPositionOfNodeShape(d);
// Annotations that point to embedded nodes (constants,summary)
// don't have a render information attached so we don't stylize these.
// Also we don't stylize ellipsis annotations (the string "... and X more").
if (a.renderNodeInfo &&
- a.annotationType !== tf.graph.render.AnnotationType.ELLIPSIS) {
- scene.node.stylize(aGroup, a.renderNodeInfo, sceneBehavior, scene.Class.Annotation.NODE);
+ a.annotationType !== graph.render.AnnotationType.ELLIPSIS) {
+ scene.node.stylize(aGroup, a.renderNodeInfo, sceneElement, scene.Class.Annotation.NODE);
}
- if (a.annotationType === tf.graph.render.AnnotationType.SUMMARY) {
+ if (a.annotationType === graph.render.AnnotationType.SUMMARY) {
// Update the width of the annotation to give space for the image.
a.width += 10;
}
@@ -6251,7 +6424,7 @@ var tf;
y: d.y + a.dy
});
// Some annotations (such as summary) are represented using a 12x12 image tag.
- // Purposely ommited units (e.g. pixels) since the images are vector graphics.
+ // Purposely omitted units (e.g. pixels) since the images are vector graphics.
// If there is an image, we adjust the location of the image to be vertically
// centered with the node and horizontally centered between the arrow and the
// text label.
@@ -6292,9 +6465,6 @@ 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.
==============================================================================*/
-/// <reference path="../graph.ts" />
-/// <reference path="../render.ts" />
-/// <reference path="scene.ts" />
var tf;
(function (tf) {
var graph;
@@ -6303,8 +6473,10 @@ var tf;
(function (scene) {
var edge;
(function (edge) {
+ /** Delimiter between dimensions when showing sizes of tensors. */
+ var TENSOR_SHAPE_DELIM = "Ă—";
function getEdgeKey(edgeObj) {
- return edgeObj.v + tf.graph.EDGE_KEY_DELIM + edgeObj.w;
+ return edgeObj.v + graph_1.EDGE_KEY_DELIM + edgeObj.w;
}
edge.getEdgeKey = getEdgeKey;
/**
@@ -6323,12 +6495,12 @@ var tf;
*
* @param sceneGroup container
* @param graph
- * @param sceneBehavior Parent scene module.
+ * @param sceneElement <tf-graph-scene> polymer element.
* @return selection of the created nodeGroups
*/
- function buildGroup(sceneGroup, graph, sceneBehavior) {
+ function buildGroup(sceneGroup, graph, sceneElement) {
var edges = [];
- var edgeData = _.reduce(graph.edges(), function (edges, edgeObj) {
+ edges = _.reduce(graph.edges(), function (edges, edgeObj) {
var edgeLabel = graph.edge(edgeObj);
edges.push({
v: edgeObj.v,
@@ -6345,8 +6517,7 @@ var tf;
// See https://github.com/mbostock/d3/releases/tag/v2.0.0
// (It's not listed in the d3 wiki.)
return this.childNodes;
- })
- .data(edgeData, getEdgeKey);
+ }).data(edges, getEdgeKey);
// Make edges a group to support rendering multiple lines for metaedge
edgeGroups.enter()
.append("g")
@@ -6356,28 +6527,62 @@ var tf;
var edgeGroup = d3.select(this);
d.label.edgeGroup = edgeGroup;
// index node group for quick highlighting
- sceneBehavior._edgeGroupIndex[getEdgeKey(d)] = edgeGroup;
+ sceneElement._edgeGroupIndex[getEdgeKey(d)] = edgeGroup;
// If any edges are reference edges, add the reference edge class.
var extraEdgeClass = d.label.metaedge && d.label.metaedge.numRefEdges
? scene.Class.Edge.REF_LINE + " " + scene.Class.Edge.LINE
: undefined;
// Add line during enter because we're assuming that type of line
// normally does not change.
- appendEdge(edgeGroup, d, scene, extraEdgeClass);
+ appendEdge(edgeGroup, d, sceneElement, extraEdgeClass);
});
edgeGroups.each(position);
edgeGroups.each(function (d) {
- stylize(d3.select(this), d, sceneBehavior);
+ stylize(d3.select(this), d, sceneElement);
});
edgeGroups.exit()
.each(function (d) {
- delete sceneBehavior._edgeGroupIndex[getEdgeKey(d)];
+ delete sceneElement._edgeGroupIndex[getEdgeKey(d)];
})
.remove();
return edgeGroups;
}
edge.buildGroup = buildGroup;
;
+ function getShapeLabelFromNode(node, renderInfo) {
+ if (node.outputShapes == null || node.outputShapes.length === 0) {
+ return null;
+ }
+ // TODO(smilkov): Figure out exactly which output tensor this
+ // edge is from.
+ var shape = node.outputShapes[0];
+ if (shape == null) {
+ return null;
+ }
+ if (shape.length === 0) {
+ return "scalar";
+ }
+ return shape.map(function (size) {
+ return size === -1 ? "?" : size;
+ }).join(TENSOR_SHAPE_DELIM);
+ }
+ edge.getShapeLabelFromNode = getShapeLabelFromNode;
+ /**
+ * Creates the label for the given metaedge. If the metaedge consists
+ * of only 1 tensor, and it's shape is known, the label will contain that
+ * shape. Otherwise, the label will say the number of tensors in the metaedge.
+ */
+ function getLabelForEdge(metaedge, renderInfo) {
+ var isMultiEdge = metaedge.baseEdgeList.length > 1;
+ if (isMultiEdge) {
+ return metaedge.baseEdgeList.length + " tensors";
+ }
+ else {
+ var node_1 = renderInfo.getNodeByName(metaedge.baseEdgeList[0].v);
+ return getShapeLabelFromNode(node_1, renderInfo);
+ }
+ }
+ edge.getLabelForEdge = getLabelForEdge;
/**
* For a given d3 selection and data object, create a path to represent the
* edge described in d.label.
@@ -6386,13 +6591,43 @@ var tf;
* will sometimes be undefined, for example for some Annotation edges for which
* there is no underlying Metaedge in the hierarchical graph.
*/
- function appendEdge(edgeGroup, d, sceneBehavior, edgeClass) {
+ function appendEdge(edgeGroup, d, sceneElement, edgeClass) {
+ var size = 1;
+ if (d.label != null && d.label.metaedge != null) {
+ // There is an underlying Metaedge.
+ size = d.label.metaedge.totalSize;
+ }
edgeClass = edgeClass || scene.Class.Edge.LINE; // set default type
if (d.label && d.label.structural) {
edgeClass += " " + scene.Class.Edge.STRUCTURAL;
}
+ // Give the path a unique id, which will be used to link
+ // the textPath (edge label) to this path.
+ var pathId = "path_" + getEdgeKey(d);
+ var strokeWidth = sceneElement.renderHierarchy.edgeWidthScale(size);
edgeGroup.append("path")
- .attr("class", edgeClass);
+ .attr({
+ "id": pathId,
+ "class": edgeClass,
+ }).style({
+ "stroke-width": strokeWidth + "px"
+ });
+ if (d.label == null || d.label.metaedge == null) {
+ // There is no associated metaedge, thus no text.
+ // This happens for annotation edges.
+ return;
+ }
+ var labelForEdge = getLabelForEdge(d.label.metaedge, sceneElement.renderHierarchy);
+ if (labelForEdge == null) {
+ // We have no information to show on this edge.
+ return;
+ }
+ edgeGroup.append("text").append("textPath").attr({
+ "xlink:href": "#" + pathId,
+ "startOffset": "50%",
+ "text-anchor": "middle",
+ "dominant-baseline": "central"
+ }).text(labelForEdge);
}
edge.appendEdge = appendEdge;
;
@@ -6406,8 +6641,9 @@ var tf;
function getEdgePathInterpolator(d, i, a) {
var renderMetaedgeInfo = d.label;
var adjoiningMetaedge = renderMetaedgeInfo.adjoiningMetaedge;
+ var points = renderMetaedgeInfo.points;
if (!adjoiningMetaedge) {
- return d3.interpolate(a, edge.interpolate(renderMetaedgeInfo.points));
+ return d3.interpolate(a, edge.interpolate(points));
}
var renderPath = this;
// Get the adjoining path that matches the adjoining metaedge.
@@ -6424,7 +6660,6 @@ var tf;
.matrixTransform(renderPath.getCTM().inverse());
// Update the relevant point in the renderMetaedgeInfo's points list, then
// re-interpolate the path.
- var points = renderMetaedgeInfo.points;
var index = inbound ? 0 : points.length - 1;
points[index].x = adjoiningPoint.x;
points[index].y = adjoiningPoint.y;
@@ -6434,10 +6669,8 @@ var tf;
}
function position(d) {
d3.select(this).select("path." + scene.Class.Edge.LINE)
- .each(function (d) {
- var path = d3.select(this);
- path.transition().attrTween("d", getEdgePathInterpolator);
- });
+ .transition()
+ .attrTween("d", getEdgePathInterpolator);
}
;
/**
@@ -6472,10 +6705,6 @@ 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.
==============================================================================*/
-/// <reference path="../graph.ts" />
-/// <reference path="scene.ts" />
-/// <reference path="annotation.ts" />
-/// <reference path="contextmenu.ts" />
var tf;
(function (tf) {
var graph;
@@ -6525,10 +6754,10 @@ var tf;
*
* @param sceneGroup selection of the container
* @param nodeData array of render node information to map
- * @param sceneBehavior parent scene module
+ * @param sceneElement <tf-graph-scene> polymer element
* @return selection of the created nodeGroups
*/
- function buildGroup(sceneGroup, nodeData, sceneBehavior) {
+ function buildGroup(sceneGroup, nodeData, sceneElement) {
var container = scene.selectOrCreateChild(sceneGroup, "g", scene.Class.Node.CONTAINER);
// Select all children and join with data.
// (Note that all children of g.nodes are g.node)
@@ -6549,7 +6778,7 @@ var tf;
.each(function (d) {
var nodeGroup = d3.select(this);
// index node group for quick stylizing
- sceneBehavior.addNodeGroup(d.node.name, nodeGroup);
+ sceneElement.addNodeGroup(d.node.name, nodeGroup);
});
// UPDATE
nodeGroups
@@ -6558,46 +6787,46 @@ var tf;
})
.each(function (d) {
var nodeGroup = d3.select(this);
- // add g.in-annotations (always add -- to keep layer order consistent.)
+ // Add g.in-annotations (always add -- to keep layer order consistent.)
var inAnnotationBox = scene.selectOrCreateChild(nodeGroup, "g", scene.Class.Annotation.INBOX);
- scene.annotation.buildGroup(inAnnotationBox, d.inAnnotations, d, sceneBehavior);
- // add g.out-annotations (always add -- to keep layer order consistent.)
+ scene.annotation.buildGroup(inAnnotationBox, d.inAnnotations, d, sceneElement);
+ // Add g.out-annotations (always add -- to keep layer order consistent.)
var outAnnotationBox = scene.selectOrCreateChild(nodeGroup, "g", scene.Class.Annotation.OUTBOX);
- scene.annotation.buildGroup(outAnnotationBox, d.outAnnotations, d, sceneBehavior);
- // label
- var label = labelBuild(nodeGroup, d, sceneBehavior);
- // Do not add interaction to metanode labels as they live inside the
- // metanode shape which already has the same interactions.
- addInteraction(label, d, sceneBehavior, d.node.type === graph.NodeType.META);
- // build .shape below label
- var shape = buildShape(nodeGroup, d, scene.Class.Node.SHAPE, label.node());
+ scene.annotation.buildGroup(outAnnotationBox, d.outAnnotations, d, sceneElement);
+ // Build .shape first (background of the node).
+ var shape = buildShape(nodeGroup, d, scene.Class.Node.SHAPE);
if (d.node.isGroupNode) {
- addButton(shape, d, sceneBehavior);
+ addButton(shape, d, sceneElement);
}
- addInteraction(shape, d, sceneBehavior);
- // build subscene on the top
- subsceneBuild(nodeGroup, d, sceneBehavior);
- stylize(nodeGroup, d, sceneBehavior);
- position(nodeGroup, d, sceneBehavior);
+ addInteraction(shape, d, sceneElement);
+ // Build subscene on the top.
+ subsceneBuild(nodeGroup, d, sceneElement);
+ // Build label last. Should be on top of everything else.
+ var label = labelBuild(nodeGroup, d, sceneElement);
+ // Do not add interaction to metanode labels as they live inside the
+ // metanode shape which already has the same interactions.
+ addInteraction(label, d, sceneElement, d.node.type === graph.NodeType.META);
+ stylize(nodeGroup, d, sceneElement);
+ position(nodeGroup, d);
});
// EXIT
nodeGroups.exit()
.each(function (d) {
// remove all indices on remove
- sceneBehavior.removeNodeGroup(d.node.name);
+ sceneElement.removeNodeGroup(d.node.name);
var nodeGroup = d3.select(this);
if (d.inAnnotations.list.length > 0) {
nodeGroup.select("." + scene.Class.Annotation.INBOX)
.selectAll("." + scene.Class.Annotation.GROUP)
.each(function (a) {
- sceneBehavior.removeAnnotationGroup(a, d);
+ sceneElement.removeAnnotationGroup(a, d);
});
}
if (d.outAnnotations.list.length > 0) {
nodeGroup.select("." + scene.Class.Annotation.OUTBOX)
.selectAll("." + scene.Class.Annotation.GROUP)
.each(function (a) {
- sceneBehavior.removeAnnotationGroup(a, d);
+ sceneElement.removeAnnotationGroup(a, d);
});
}
})
@@ -6612,16 +6841,16 @@ var tf;
*
* @param nodeGroup selection of the container
* @param renderNodeInfo the render information for the node.
- * @param sceneBehavior parent scene module
+ * @param sceneElement <tf-graph-scene> polymer element.
* @return Selection of the subscene group, or null if node group does not have
* a subscene. Op nodes, bridge nodes and unexpanded group nodes will
* not have a subscene.
*/
- function subsceneBuild(nodeGroup, renderNodeInfo, sceneBehavior) {
+ function subsceneBuild(nodeGroup, renderNodeInfo, sceneElement) {
if (renderNodeInfo.node.isGroupNode) {
if (renderNodeInfo.expanded) {
// Recursively build the subscene.
- return scene.buildGroup(nodeGroup, renderNodeInfo, sceneBehavior, scene.Class.Subscene.GROUP);
+ return scene.buildGroup(nodeGroup, renderNodeInfo, sceneElement, scene.Class.Subscene.GROUP);
}
// Clean out existing subscene if the node is not expanded.
scene.selectChild(nodeGroup, "g", scene.Class.Subscene.GROUP).remove();
@@ -6644,9 +6873,9 @@ var tf;
*
* @param selection The group node selection.
* @param d Info about the node being rendered.
- * @param sceneBehavior parent scene module.
+ * @param sceneElement <tf-graph-scene> polymer element.
*/
- function addButton(selection, d, sceneBehavior) {
+ function addButton(selection, d, sceneElement) {
var group = scene.selectOrCreateChild(selection, "g", scene.Class.Node.BUTTON_CONTAINER);
scene.selectOrCreateChild(group, "circle", scene.Class.Node.BUTTON_CIRCLE);
scene.selectOrCreateChild(group, "path", scene.Class.Node.EXPAND_BUTTON).attr("d", "M0,-2.2 V2.2 M-2.2,0 H2.2");
@@ -6655,7 +6884,7 @@ var tf;
// Stop this event's propagation so that it isn't also considered a
// node-select.
d3.event.stopPropagation();
- sceneBehavior.fire("node-toggle-expand", { name: d.node.name });
+ sceneElement.fire("node-toggle-expand", { name: d.node.name });
});
scene.positionButton(group, d);
}
@@ -6668,39 +6897,39 @@ var tf;
* don't need interaction as their surrounding shape has interaction, and if
* given interaction would cause conflicts with the expand/collapse button.
*/
- function addInteraction(selection, d, sceneBehavior, disableInteraction) {
+ function addInteraction(selection, d, sceneElement, disableInteraction) {
if (disableInteraction) {
selection.attr("pointer-events", "none");
return;
}
- var contextMenuFunction = tf.graph.scene.contextmenu.getMenu(getContextMenu(d.node, sceneBehavior));
+ var contextMenuFunction = scene.contextmenu.getMenu(getContextMenu(d.node, sceneElement));
selection.on("dblclick", function (d) {
- sceneBehavior.fire("node-toggle-expand", { name: d.node.name });
+ sceneElement.fire("node-toggle-expand", { name: d.node.name });
})
.on("mouseover", function (d) {
// don't send mouseover over expanded group,
// otherwise it is causing too much glitches
- if (sceneBehavior.isNodeExpanded(d)) {
+ if (sceneElement.isNodeExpanded(d)) {
return;
}
- sceneBehavior.fire("node-highlight", { name: d.node.name });
+ sceneElement.fire("node-highlight", { name: d.node.name });
})
.on("mouseout", function (d) {
// don't send mouseover over expanded group,
// otherwise it is causing too much glitches
- if (sceneBehavior.isNodeExpanded(d)) {
+ if (sceneElement.isNodeExpanded(d)) {
return;
}
- sceneBehavior.fire("node-unhighlight", { name: d.node.name });
+ sceneElement.fire("node-unhighlight", { name: d.node.name });
})
.on("click", function (d) {
// Stop this event's propagation so that it isn't also considered
// a graph-select.
d3.event.stopPropagation();
- sceneBehavior.fire("node-select", { name: d.node.name });
+ sceneElement.fire("node-select", { name: d.node.name });
})
.on("contextmenu", function (d, i) {
- sceneBehavior.fire("node-select", { name: d.node.name });
+ sceneElement.fire("node-select", { name: d.node.name });
contextMenuFunction.call(d, i);
});
}
@@ -6708,37 +6937,101 @@ var tf;
/**
* Returns the d3 context menu specification for the provided node.
*/
- function getContextMenu(node, sceneBehavior) {
- return [{
+ function getContextMenu(node, sceneElement) {
+ var menu = [{
title: function (d) {
- return tf.graph.getIncludeNodeButtonString(node.include);
+ return graph.getIncludeNodeButtonString(node.include);
},
action: function (elm, d, i) {
- sceneBehavior.fire("node-toggle-extract", { name: node.name });
+ sceneElement.fire("node-toggle-extract", { name: node.name });
}
}];
+ if (canBeInSeries(node)) {
+ menu.push({
+ title: function (d) {
+ return getGroupSettingLabel(node);
+ },
+ action: function (elm, d, i) {
+ sceneElement.fire("node-toggle-seriesgroup", { name: getSeriesName(node) });
+ }
+ });
+ }
+ return menu;
}
node_1.getContextMenu = getContextMenu;
+ /** Returns if a node can be part of a grouped series */
+ function canBeInSeries(node) {
+ return getSeriesName(node) !== null;
+ }
+ node_1.canBeInSeries = canBeInSeries;
+ /**
+ * Returns the name of the possible grouped series containing this node.
+ * Returns null if the node cannot be part of a grouped series of nodes.
+ */
+ function getSeriesName(node) {
+ if (!node) {
+ return null;
+ }
+ if (node.type === graph.NodeType.SERIES) {
+ return node.name;
+ }
+ if (node.type === graph.NodeType.OP) {
+ var op = node;
+ return op.owningSeries;
+ }
+ return null;
+ }
+ node_1.getSeriesName = getSeriesName;
+ /**
+ * Returns the SeriesNode that represents the series that the provided node
+ * is contained in (or itself if the provided node is itself a SeriesNode).
+ * Returns null if the node is not rendered as part of a series.
+ */
+ function getContainingSeries(node) {
+ var s = null;
+ if (!node) {
+ return null;
+ }
+ else if (node.type === graph.NodeType.SERIES) {
+ s = node;
+ }
+ else if (node.parentNode && node.parentNode.type === graph.NodeType.SERIES) {
+ s = node.parentNode;
+ }
+ return s;
+ }
+ /**
+ * Returns the label for a button to toggle the group setting of the provided
+ * node.
+ */
+ function getGroupSettingLabel(node) {
+ return tf.graph.getGroupSeriesNodeButtonString(getContainingSeries(node) !== null ? tf.graph.SeriesGroupingType.GROUP :
+ tf.graph.SeriesGroupingType.UNGROUP);
+ }
+ node_1.getGroupSettingLabel = getGroupSettingLabel;
/**
* Append svg text for label and assign data.
* @param nodeGroup
* @param renderNodeInfo The render node information for the label.
- * @param sceneBehavior parent scene module.
+ * @param sceneElement <tf-graph-scene> polymer element.
*/
- function labelBuild(nodeGroup, renderNodeInfo, sceneBehavior) {
+ function labelBuild(nodeGroup, renderNodeInfo, sceneElement) {
var namePath = renderNodeInfo.node.name.split("/");
var text = namePath[namePath.length - 1];
// Truncate long labels for unexpanded Metanodes.
var useFontScale = renderNodeInfo.node.type === graph.NodeType.META &&
!renderNodeInfo.expanded;
var label = scene.selectOrCreateChild(nodeGroup, "text", scene.Class.Node.LABEL);
+ // Make sure the label is visually on top among its siblings.
+ var labelNode = label.node();
+ labelNode.parentNode.appendChild(labelNode);
label.attr("dy", ".35em")
.attr("text-anchor", "middle");
if (useFontScale) {
- if (text.length > sceneBehavior.maxMetanodeLabelLength) {
- text = text.substr(0, sceneBehavior.maxMetanodeLabelLength - 2) + "...";
+ if (text.length > sceneElement.maxMetanodeLabelLength) {
+ text = text.substr(0, sceneElement.maxMetanodeLabelLength - 2) + "...";
}
- var scale = getLabelFontScale(sceneBehavior);
+ var scale = getLabelFontScale(sceneElement);
label.attr("font-size", scale(text.length) + "px");
}
label.text(text);
@@ -6750,13 +7043,13 @@ var tf;
* initialized once by getLabelFontScale.
*/
var fontScale = null;
- function getLabelFontScale(sceneBehavior) {
+ function getLabelFontScale(sceneElement) {
if (!fontScale) {
fontScale = d3.scale.linear()
- .domain([sceneBehavior.maxMetanodeLabelLengthLargeFont,
- sceneBehavior.maxMetanodeLabelLength])
- .range([sceneBehavior.maxMetanodeLabelLengthFontSize,
- sceneBehavior.minMetanodeLabelLengthFontSize]).clamp(true);
+ .domain([sceneElement.maxMetanodeLabelLengthLargeFont,
+ sceneElement.maxMetanodeLabelLength])
+ .range([sceneElement.maxMetanodeLabelLengthFontSize,
+ sceneElement.minMetanodeLabelLengthFontSize]).clamp(true);
}
return fontScale;
}
@@ -6776,12 +7069,11 @@ var tf;
* @param nodeGroup
* @param d Render node information.
* @param nodeClass class for the element.
- * @param before Reference DOM node for insertion.
* @return Selection of the shape.
*/
- function buildShape(nodeGroup, d, nodeClass, before) {
+ function buildShape(nodeGroup, d, nodeClass) {
// Create a group to house the underlying visual elements.
- var shapeGroup = scene.selectOrCreateChild(nodeGroup, "g", nodeClass, before);
+ var shapeGroup = scene.selectOrCreateChild(nodeGroup, "g", nodeClass);
// TODO(jimbo): DOM structure should be templated in HTML somewhere, not JS.
switch (d.node.type) {
case graph.NodeType.OP:
@@ -6834,7 +7126,7 @@ var tf;
node_1.nodeClass = nodeClass;
;
/** Modify node and its subscene and its label's positional attributes */
- function position(nodeGroup, d, sceneBehavior) {
+ function position(nodeGroup, d) {
var shapeGroup = scene.selectChild(nodeGroup, "g", scene.Class.Node.SHAPE);
var cx = graph.layout.computeCXPositionOfNodeShape(d);
switch (d.node.type) {
@@ -6902,16 +7194,16 @@ var tf;
* option.
*/
function getFillForNode(templateIndex, colorBy, renderInfo, isExpanded) {
- var colorParams = tf.graph.render.MetanodeColors;
+ var colorParams = graph.render.MetanodeColors;
switch (colorBy) {
case ColorBy.STRUCTURE:
- if (renderInfo.node.type === tf.graph.NodeType.META) {
+ if (renderInfo.node.type === graph.NodeType.META) {
var tid = renderInfo.node.templateId;
return tid === null ?
colorParams.UNKNOWN :
colorParams.STRUCTURE_PALETTE(templateIndex(tid), isExpanded);
}
- else if (renderInfo.node.type === tf.graph.NodeType.SERIES) {
+ else if (renderInfo.node.type === graph.NodeType.SERIES) {
// If expanded, we're showing the background rect, which we want to
// appear gray. Otherwise we're showing a stack of ellipses which we
// want to show white.
@@ -6933,23 +7225,23 @@ var tf;
var id = renderInfo.node.name;
var escapedId = tf.escapeQuerySelector(id);
var gradientDefs = d3.select("svg#svg defs #linearGradients");
- var linearGradient = gradientDefs.select("linearGradient#" + escapedId);
+ var linearGradient_1 = gradientDefs.select("linearGradient#" + escapedId);
// If the linear gradient is not there yet, create it.
- if (linearGradient.size() === 0) {
- linearGradient = gradientDefs.append("linearGradient").attr("id", id);
+ if (linearGradient_1.size() === 0) {
+ linearGradient_1 = gradientDefs.append("linearGradient").attr("id", id);
// Re-create the stops of the linear gradient.
- linearGradient.selectAll("*").remove();
- var cumulativeProportion = 0;
+ linearGradient_1.selectAll("*").remove();
+ var cumulativeProportion_1 = 0;
// For each device, create a stop using the proportion of that device.
_.each(renderInfo.deviceColors, function (d) {
var color = d.color;
- linearGradient.append("stop")
- .attr("offset", cumulativeProportion)
+ linearGradient_1.append("stop")
+ .attr("offset", cumulativeProportion_1)
.attr("stop-color", color);
- linearGradient.append("stop")
- .attr("offset", cumulativeProportion + d.proportion)
+ linearGradient_1.append("stop")
+ .attr("offset", cumulativeProportion_1 + d.proportion)
.attr("stop-color", color);
- cumulativeProportion += d.proportion;
+ cumulativeProportion_1 += d.proportion;
});
}
return isExpanded ? colorParams.EXPANDED_COLOR : "url(#" + escapedId + ")";
@@ -6970,10 +7262,10 @@ var tf;
* Modify node style by toggling class and assign attributes (only for things
* that can't be done in css).
*/
- function stylize(nodeGroup, renderInfo, sceneBehavior, nodeClass) {
+ function stylize(nodeGroup, renderInfo, sceneElement, nodeClass) {
nodeClass = nodeClass || scene.Class.Node.SHAPE;
- var isHighlighted = sceneBehavior.isNodeHighlighted(renderInfo.node.name);
- var isSelected = sceneBehavior.isNodeSelected(renderInfo.node.name);
+ var isHighlighted = sceneElement.isNodeHighlighted(renderInfo.node.name);
+ var isSelected = sceneElement.isNodeSelected(renderInfo.node.name);
var isExtract = renderInfo.isInExtract || renderInfo.isOutExtract;
var isExpanded = renderInfo.expanded;
nodeGroup.classed("highlighted", isHighlighted);
@@ -6983,7 +7275,7 @@ var tf;
// Main node always exists here and it will be reached before subscene,
// so d3 selection is fine here.
var node = nodeGroup.select("." + nodeClass + " ." + scene.Class.Node.COLOR_TARGET);
- var fillColor = getFillForNode(sceneBehavior.templateIndex, ColorBy[sceneBehavior.colorBy.toUpperCase()], renderInfo, isExpanded);
+ var fillColor = getFillForNode(sceneElement.templateIndex, ColorBy[sceneElement.colorBy.toUpperCase()], renderInfo, isExpanded);
node.style("fill", fillColor);
// Choose outline to be darker version of node color if the node is a single
// color and is not selected.
@@ -6997,7 +7289,7 @@ var tf;
function getStrokeForFill(fill) {
// If node is colored by a gradient, then use a dark gray outline.
return fill.substring(0, 3) === "url" ?
- tf.graph.render.MetanodeColors.GRADIENT_OUTLINE :
+ graph.render.MetanodeColors.GRADIENT_OUTLINE :
d3.rgb(fill).darker().toString();
}
node_1.getStrokeForFill = getStrokeForFill;
@@ -7087,8 +7379,6 @@ 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.
==============================================================================*/
-/// <reference path="graph.ts" />
-/// <reference path="render.ts" />
var tf;
(function (tf) {
var graph;
@@ -8186,7 +8476,6 @@ var tf;
::content .edge > path.edgeline {
fill: none;
- marker-end: url("#arrowhead");
stroke: #bbb;
stroke-linecap: round;
stroke-width: 0.75;
@@ -8196,6 +8485,12 @@ var tf;
marker-start: url("#ref-arrowhead");
}
+/* Labels showing tensor shapes on edges */
+::content .edge > text {
+ font-size: 3.5px;
+ fill: #666;
+}
+
::content #arrowhead {
fill: #bbb;
}
@@ -8259,8 +8554,6 @@ 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.
==============================================================================*/
-/// <reference path="../../../../typings/tsd.d.ts" />
-/// <reference path="../common.ts" />
var tf;
(function (tf) {
var scene;
@@ -8449,7 +8742,8 @@ var tf;
downloadContext.clearRect(0, 0, _this.downloadCanvas.width, _this.downloadCanvas.height);
downloadContext.drawImage(image, 0, 0, _this.downloadCanvas.width, _this.downloadCanvas.height);
};
- image.src = "data:image/svg+xml;base64," + btoa(svgXml);
+ var blob = new Blob([svgXml], { type: "image/svg+xml;charset=utf-8" });
+ image.src = URL.createObjectURL(blob);
};
/**
* Handles changes in zooming/panning. Should be called from the main svg
@@ -8497,7 +8791,7 @@ var tf;
}
};
return Minimap;
- })();
+ }());
scene.Minimap = Minimap;
})(scene = tf.scene || (tf.scene = {}));
})(tf || (tf = {})); // close module tf.scene
@@ -9184,6 +9478,12 @@ Polymer({
notify: true,
observer: '_graphChanged'
},
+ basicGraph: Object,
+ hierarchyParams: Object,
+ progress: {
+ type: Object,
+ notify: true,
+ },
title: String,
selectedNode: {
type: String,
@@ -9219,7 +9519,7 @@ Polymer({
_allowGraphSelect: {
type: Boolean,
value: true
- }
+ },
},
observers: [
'_buildRenderHierarchy(graphHierarchy, _graphParams)'
@@ -9278,6 +9578,7 @@ Polymer({
'node-highlight': '_nodeHighlighted',
'node-unhighlight': '_nodeUnhighlighted',
'node-toggle-extract': '_nodeToggleExtract',
+ 'node-toggle-seriesgroup': '_nodeToggleSeriesGroup',
// Annotations
@@ -9327,6 +9628,10 @@ Polymer({
this.set('highlightedNode', null);
},
_nodeToggleExpand: function(event) {
+ // Immediately select the node that is about to be expanded.
+ this._nodeSelected(event);
+
+ // Compute the sub-hierarchy scene.
var nodeName = event.detail.name;
var renderNode = this.renderHierarchy.getRenderNodeByName(nodeName);
// Op nodes are not expandable.
@@ -9335,9 +9640,13 @@ Polymer({
}
this.renderHierarchy.buildSubhierarchy(nodeName);
renderNode.expanded = !renderNode.expanded;
- this.querySelector('#scene').setNodeExpanded(renderNode);
- // Also select the expanded node.
- this._nodeSelected(event);
+
+ // Expand the node with some delay so that the user can immediately see
+ // the visual effect of selecting that node, before the expansion is
+ // done.
+ this.async(function() {
+ this.querySelector('#scene').setNodeExpanded(renderNode);
+ }, 75);
},
_nodeToggleExtract: function(event) {
// Toggle the include setting of the specified node appropriately.
@@ -9356,6 +9665,25 @@ Polymer({
// Rebuild the render hierarchy.
this._buildRenderHierarchy(this.graphHierarchy, this._graphParams);
},
+ _nodeToggleSeriesGroup: function(event) {
+ // Toggle the group setting of the specified node appropriately.
+ var nodeName = event.detail.name;
+ tf.graph.toggleNodeSeriesGroup(this.hierarchyParams.seriesMap, nodeName);
+
+ // Rebuild the render hierarchy with the updated series grouping map.
+ this.set('progress', {
+ value: 0,
+ msg: ''
+ });
+ var tracker = tf.getTracker(this);
+ var hierarchyTracker = tf.getSubtaskTracker(tracker, 100,
+ 'Namespace hierarchy');
+ tf.graph.hierarchy.build(this.basicGraph, this.hierarchyParams, hierarchyTracker)
+ .then(function(graphHierarchy) {
+ this.set('graphHierarchy', graphHierarchy);
+ this._buildRenderHierarchy(this.graphHierarchy, this._graphParams);
+ }.bind(this));
+ },
not: function(x) {
return !x;
}
@@ -9429,7 +9757,7 @@ Polymer({
/**
* String indicating the type of coloring to use for this node, used
- * only for deterimining the fill.
+ * only for determining the fill.
*/
colorBy: {
type: Object,
@@ -9437,7 +9765,7 @@ Polymer({
},
/**
- * Function used by structural coloring algorithim to determine which
+ * Function used by structural coloring algorithm to determine which
* color to use based on the template ID of the node. Optional.
*/
templateIndex: {
@@ -9600,6 +9928,7 @@ Polymer({
font-size: 11pt;
font-weight: 400;
position: relative;
+ display: inline-block;
}
#list-item:hover {
@@ -9611,7 +9940,6 @@ Polymer({
}
#list-item span {
- display: block;
margin-left: 40px;
}
@@ -9619,6 +9947,13 @@ Polymer({
color: #999;
}
+ #list-item span.edge-label {
+ float: right;
+ font-size: 10px;
+ margin-left: 3px;
+ margin-right: 5px;
+ }
+
.node-icon {
position: absolute;
top: 1px;
@@ -9629,6 +9964,7 @@ Polymer({
<div id="list-item" on-mouseover="_nodeListener" on-mouseout="_nodeListener" on-click="_nodeListener">
<tf-graph-icon class="node-icon" height="12" color-by="[[colorBy]]" color-by-params="[[colorByParams]]" node="[[itemNode]]" render-info="[[itemRenderInfo]]" template-index="[[templateIndex]]"></tf-graph-icon>
<span title$="[[name]]">[[name]]</span>
+ <span class="edge-label">[[edgeLabel]]</span>
</div>
</template>
@@ -9648,6 +9984,8 @@ Polymer({
* @type {tf.graph.Node}
*/
itemNode: Object,
+ /** The edge label associated with this item. */
+ edgeLabel: String,
/**
* The render node information for the item node. Used by the graph
* icon in determining fill color.
@@ -9660,7 +9998,7 @@ Polymer({
},
colorBy: String,
colorByParams: Object,
- templateIndex: Function,
+ templateIndex: Function
},
_itemTypeChanged: function() {
@@ -9679,7 +10017,6 @@ Polymer({
type: this.itemType
});
}
-
});
})();
</script>
@@ -9793,7 +10130,7 @@ Polymer({
<div>
<paper-icon-button icon="{{_getToggleIcon(_expanded)}}" on-click="_toggleExpanded" class="toggle-button">
</paper-icon-button>
- <div class="node-name">[[_getNodeName(nodeName)]]</div>
+ <div class="node-name" id="nodetitle"></div>
</div>
<div secondary="">
<tf-graph-icon class="node-icon" node="[[_node]]" render-info="[[_getRenderInfo(nodeName, renderHierarchy)]]" color-by="[[colorBy]]" template-index="[[_templateIndex]]"></tf-graph-icon>
@@ -9840,7 +10177,7 @@ Polymer({
(<span>[[_totalPredecessors]]</span>)
<iron-list class="sub-list" id="inputsList" items="[[_predecessors.regular]]">
<template>
- <tf-node-list-item class="non-control-list-item" card-node="[[_node]]" item-node="[[_getNode(item, graphHierarchy)]]" item-render-info="[[_getRenderInfo(item, renderHierarchy)]]" name="[[item]]" item-type="predecessors" color-by="[[colorBy]]" template-index="[[_templateIndex]]">
+ <tf-node-list-item class="non-control-list-item" card-node="[[_node]]" item-node="[[_getNode(item, graphHierarchy)]]" edge-label="[[_getPredEdgeLabel(item)]]" item-render-info="[[_getRenderInfo(item, renderHierarchy)]]" name="[[item]]" item-type="predecessors" color-by="[[colorBy]]" template-index="[[_templateIndex]]">
</tf-node-list-item>
</template>
</iron-list>
@@ -9870,7 +10207,7 @@ Polymer({
(<span>[[_totalSuccessors]]</span>)
<iron-list class="sub-list" id="outputsList" items="[[_successors.regular]]">
<template>
- <tf-node-list-item class="non-control-list-item" card-node="[[_node]]" item-node="[[_getNode(item, graphHierarchy)]]" item-render-info="[[_getRenderInfo(item, renderHierarchy)]]" name="[[item]]" item-type="successor" color-by="[[colorBy]]" template-index="[[_templateIndex]]">
+ <tf-node-list-item class="non-control-list-item" card-node="[[_node]]" item-node="[[_getNode(item, graphHierarchy)]]" edge-label="[[_getSuccEdgeLabel(item)]]" item-render-info="[[_getRenderInfo(item, renderHierarchy)]]" name="[[item]]" item-type="successor" color-by="[[colorBy]]" template-index="[[_templateIndex]]">
</tf-node-list-item>
</template>
</iron-list>
@@ -9899,6 +10236,13 @@ Polymer({
<span>[[_auxButtonText]]</span>
</paper-button>
</div>
+ <template is="dom-if" if="{{_isInSeries(_node)}}">
+ <div class="toggle-include-group">
+ <paper-button raised="" class="toggle-include" on-click="_toggleGroup">
+ <span>[[_groupButtonText]]</span>
+ </paper-button>
+ </div>
+ </template>
</div>
</template>
</iron-collapse>
@@ -9969,7 +10313,8 @@ Polymer({
type: Boolean,
value: false
},
- _auxButtonText: String
+ _auxButtonText: String,
+ _groupButtonText: String
},
expandNode: function() {
this.fire('_node.expand', this.node);
@@ -9980,20 +10325,60 @@ Polymer({
_getNode: function(nodeName, graphHierarchy) {
return graphHierarchy.node(nodeName);
},
- _getNodeName: function(nodeName) {
- // Insert a zero-width whitespace character before each slash so that
+ _getPrintableHTMLNodeName: function(nodeName) {
+ // Insert an optional line break before each slash so that
// long node names wrap cleanly at path boundaries.
- return (nodeName || '').replace(/\//g, '\u200B/');
+ return (nodeName || '').replace(/\//g, '<wbr>/');
+ },
+ _getPredEdgeLabel: function(sourceName) {
+ return this._getEdgeLabel(sourceName, this.nodeName);
+ },
+ _getSuccEdgeLabel: function(destName) {
+ return this._getEdgeLabel(this.nodeName, destName);
+ },
+ _getEdgeLabel: function(sourceName, destName) {
+ if (!this._node) {
+ // The user clicked outside, thus no node is selected and
+ // the info card should be hidden.
+ return;
+ }
+ var parent = this._node.parentNode;
+ var sourceNode = this.graphHierarchy.node(sourceName);
+ if (!sourceNode.isGroupNode) {
+ // Show the tensor shape directly.
+ return tf.graph.scene.edge.getShapeLabelFromNode(sourceNode);
+ }
+ sourceName = this.renderHierarchy.getNearestVisibleAncestor(sourceName);
+ destName = this.renderHierarchy.getNearestVisibleAncestor(destName);
+ var metaedge = parent.metagraph.edge(sourceName, destName) ||
+ parent.bridgegraph.edge(sourceName, destName);
+ return tf.graph.scene.edge.getLabelForEdge(metaedge,
+ this.renderHierarchy);
},
_getRenderInfo: function(nodeName, renderHierarchy) {
return this.renderHierarchy.getOrCreateRenderNodeByName(nodeName);
},
_getAttributes: function(node) {
this.async(this._resizeList.bind(this, "#attributesList"));
- return node && node.attr ? node.attr.map(function(entry) {
- return {key: entry.key, value: JSON.stringify(entry.value)};
- }) : [];
-
+ if (!node || !node.attr) {
+ return [];
+ }
+ var attrs = [];
+ _.each(node.attr, function(entry) {
+ // Unpack the "too large" attributes into separate attributes
+ // in the info card, with values "too large to show".
+ if (entry.key === tf.graph.LARGE_ATTRS_KEY) {
+ attrs = attrs.concat(entry.value.list.s.map(function(key) {
+ return {key: key, value: "Too large to show..."};
+ }));
+ } else {
+ attrs.push({
+ key: entry.key,
+ value: JSON.stringify(entry.value)
+ });
+ }
+ });
+ return attrs;
},
_getDevice: function(node) {
return node ? node.device : null;
@@ -10030,6 +10415,14 @@ Polymer({
_resetState: function() {
this._openedControlPred = false;
this._openedControlSucc = false;
+
+ this.set("_groupButtonText",
+ tf.graph.scene.node.getGroupSettingLabel(this._node));
+
+ if (this._node) {
+ Polymer.dom(this.$.nodetitle).innerHTML =
+ this._getPrintableHTMLNodeName(this._node.name);
+ }
},
_resizeList: function(selector) {
var list = document.querySelector(selector);
@@ -10046,6 +10439,14 @@ Polymer({
_nodeIncludeStateChanged: function(include, oldInclude) {
this.set("_auxButtonText",
tf.graph.getIncludeNodeButtonString(include));
+ },
+ _toggleGroup: function() {
+ var graphElem = document.querySelector("#graph");
+ var seriesName = tf.graph.scene.node.getSeriesName(this._node);
+ graphElem.fire("node-toggle-seriesgroup", { name: seriesName });
+ },
+ _isInSeries: function(node) {
+ return tf.graph.scene.node.canBeInSeries(node);
}
});
})();
@@ -10222,7 +10623,7 @@ paper-progress {
</template>
<div class$="[[_getContainerClass(progress)]]">
<div id="main">
- <tf-graph id="graph" graph-hierarchy="[[graphHierarchy]]" render-hierarchy="{{_renderHierarchy}}" selected-node="{{_selectedNode}}" highlighted-node="{{_highlightedNode}}" color-by="[[colorBy]]" color-by-params="{{colorByParams}}" graph-name="[[graphName]]" progress="[[progress]]"></tf-graph>
+ <tf-graph id="graph" graph-hierarchy="{{graphHierarchy}}" basic-graph="[[graph]]" hierarchy-params="[[hierarchyParams]]" render-hierarchy="{{_renderHierarchy}}" selected-node="{{_selectedNode}}" highlighted-node="{{_highlightedNode}}" color-by="[[colorBy]]" color-by-params="{{colorByParams}}" graph-name="[[graphName]]" progress="{{progress}}"></tf-graph>
</div>
<div id="info">
<tf-graph-info id="graph-info" title="selected" graph-hierarchy="[[graphHierarchy]]" render-hierarchy="[[_renderHierarchy]]" graph="[[graph]]" selected-node="{{_selectedNode}}" selected-node-include="{{_selectedNodeInclude}}" highlighted-node="{{_highlightedNode}}" color-by="[[colorBy]]" color-by-params="[[colorByParams]]"></tf-graph-info>
@@ -10806,10 +11207,10 @@ function convertToHumanReadable(value, units, unitIndex) {
<tf-dashboard-layout>
<div class="sidebar">
<tf-graph-controls id="controls" color-by-params="[[_colorByParams]]" has-stats="[[_hasStats]]" color-by="{{_colorBy}}" ,="" datasets="[[_datasets]]" selected-dataset="{{_selectedDataset}}" selected-file="{{_selectedFile}}"></tf-graph-controls>
- <tf-graph-loader id="loader" datasets="[[_datasets]]" ,="" selected-dataset="[[_selectedDataset]]" selected-file="[[_selectedFile]]" out-graph-hierarchy="{{_graphHierarchy}}" out-graph="{{_graph}}" out-graph-name="{{_graphName}}" has-stats="{{_hasStats}}" progress="{{_progress}}"></tf-graph-loader>
+ <tf-graph-loader id="loader" datasets="[[_datasets]]" ,="" selected-dataset="[[_selectedDataset]]" selected-file="[[_selectedFile]]" out-graph-hierarchy="{{_graphHierarchy}}" out-graph="{{_graph}}" out-graph-name="{{_graphName}}" has-stats="{{_hasStats}}" progress="{{_progress}}" out-hierarchy-params="{{_hierarchyParams}}"></tf-graph-loader>
</div>
<div class="center">
- <tf-graph-board id="graphboard" graph-hierarchy="[[_graphHierarchy]]" graph="[[_graph]]" has-stats="[[_hasStats]]" graph-name="[[_graphName]]" progress="[[_progress]]" color-by="[[_colorBy]]" color-by-params="{{_colorByParams}}">
+ <tf-graph-board id="graphboard" graph-hierarchy="[[_graphHierarchy]]" graph="[[_graph]]" has-stats="[[_hasStats]]" graph-name="[[_graphName]]" progress="[[_progress]]" color-by="[[_colorBy]]" color-by-params="{{_colorByParams}}" hierarchy-params="[[_hierarchyParams]]">
</tf-graph-board>
</div>
</tf-dashboard-layout>
@@ -10849,7 +11250,8 @@ Polymer({
return _.map(runsWithGraph, function(runName) {
return {
name: runName,
- path: graphUrlGen(runName)
+ path: graphUrlGen(runName, tf.graph.LIMIT_ATTR_SIZE,
+ tf.graph.LARGE_ATTRS_KEY)
};
});
},
@@ -10865,11 +11267,11 @@ Polymer({
<paper-toolbar id="toolbar">
<div id="toolbar-content">
<div class="toolbar-title">TensorBoard</div>
- <paper-tabs selected="0" noink="" class="tabs" id="tabs">
- <paper-tab data-mode="events" on-click="changeMode">Events</paper-tab>
- <paper-tab data-mode="images" on-click="changeMode">Images</paper-tab>
- <paper-tab data-mode="graphs" on-click="changeMode">Graph</paper-tab>
- <paper-tab data-mode="histograms" on-click="changeMode">Histograms</paper-tab>
+ <paper-tabs selected="{{modeIndex}}" noink="" class="tabs" id="tabs">
+ <paper-tab data-mode="events">Events</paper-tab>
+ <paper-tab data-mode="images">Images</paper-tab>
+ <paper-tab data-mode="graphs">Graph</paper-tab>
+ <paper-tab data-mode="histograms">Histograms</paper-tab>
</paper-tabs>
</div>
</paper-toolbar>
@@ -10944,14 +11346,24 @@ Polymer({
type: Object,
value: TF.Urls.productionRouter(),
},
+ // Which tab is selected (events, graph, images etc).
mode: {
type: String,
- value: "events",
+ computed: '_getModeFromIndex(modeIndex)'
},
+ // If true, tab switching in TensorBoard will not update
+ // location hash. Hash update interferes with selenium tests.
+ noHash: {
+ type: Boolean,
+ value: false
+ }
},
- changeMode: function(ev) {
- var mode = ev.target.parentElement.getAttribute('data-mode');
- this._changeMode(mode, true);
+ _getModeFromIndex: function(modeIndex) {
+ var mode = this.tabs[modeIndex];
+ if (!this.noHash) {
+ window.location.hash = mode;
+ }
+ return mode;
},
eventDashboard: function(mode) {
return mode === "events";
@@ -10965,36 +11377,26 @@ Polymer({
histogramDashboard: function(mode) {
return mode === "histograms";
},
- loadPreviousMode: function() {
- this._changeMode(this._getMode(), false);
- },
ready: function() {
- this._changeMode(this._getMode(), true);
-
- var self = this;
- window.addEventListener('hashchange', function(){
- self.loadPreviousMode();
+ this.tabs = [].slice.call(this.querySelectorAll('paper-tab')).map(function(a) {
+ return a.dataset.mode;
});
+ this._getModeFromHash();
+ window.addEventListener('hashchange', function() {
+ this._getModeFromHash();
+ }.bind(this));
},
- _changeMode: function(mode, isNewState) {
- this.mode = mode;
-
- // Change the selected tab
- this.$.tabs.selected = this._tabs().indexOf(mode);
-
- if (isNewState){
- window.location.hash = mode;
- }
- },
- _getMode: function() {
+ _getModeFromHash: function() {
// Return the mode as it is stored in the hash.
- // If no mode can be found, default to the first tab.
- var hash = window.location.hash;
- return hash.length > 0 ? hash.slice(1, hash.length) : this._tabs()[0];
- },
- _tabs: function() {
- var elts = Array.prototype.slice.call(this.querySelectorAll('paper-tab'));
- return elts.map(function(elt){ return elt.getAttribute('data-mode')});
+ var tabName = window.location.hash.trim().slice(1);
+ var modeIndex = this.tabs.indexOf(tabName);
+ if (modeIndex == -1 && this.modeIndex == null) {
+ // Selecting the first tab as default.
+ this.set('modeIndex', 0);
+ }
+ if (modeIndex != -1 && modeIndex != this.modeIndex) {
+ this.set('modeIndex', modeIndex);
+ }
},
});
</script>