diff options
author | Dan Mané <danmane@google.com> | 2016-06-30 18:30:17 -0800 |
---|---|---|
committer | TensorFlower Gardener <gardener@tensorflow.org> | 2016-06-30 19:32:57 -0700 |
commit | ccd57f57d879c95d77125c6b04781fdf952365da (patch) | |
tree | 8be3d9eade6347e1da78ce11f0293dd855e2f65a | |
parent | 1bcc32c99ca1fe8d08d02a27d9570233fdb92472 (diff) |
Autogenerated Change: Release TensorBoard at TAG: 21
Change: 126371321
-rw-r--r-- | WORKSPACE | 2 | ||||
-rw-r--r-- | tensorflow/tensorboard/TAG | 2 | ||||
-rw-r--r-- | tensorflow/tensorboard/dist/tf-tensorboard.html | 464 |
3 files changed, 454 insertions, 14 deletions
@@ -70,7 +70,7 @@ new_git_repository( name = "iron_a11y_keys_behavior", build_file = "bower.BUILD", remote = "https://github.com/polymerelements/iron-a11y-keys-behavior.git", - tag = "v1.1.5", + tag = "v1.1.6", ) new_git_repository( diff --git a/tensorflow/tensorboard/TAG b/tensorflow/tensorboard/TAG index aabe6ec390..2bd5a0a98a 100644 --- a/tensorflow/tensorboard/TAG +++ b/tensorflow/tensorboard/TAG @@ -1 +1 @@ -21 +22 diff --git a/tensorflow/tensorboard/dist/tf-tensorboard.html b/tensorflow/tensorboard/dist/tf-tensorboard.html index 77e224dd20..1c0297dbdb 100644 --- a/tensorflow/tensorboard/dist/tf-tensorboard.html +++ b/tensorflow/tensorboard/dist/tf-tensorboard.html @@ -3963,6 +3963,7 @@ var tf; } return OpNodeImpl; }()); + graph_1.OpNodeImpl = OpNodeImpl; ; function createMetanode(name, opt) { if (opt === void 0) { opt = {}; } @@ -4171,6 +4172,7 @@ var tf; }; return MetanodeImpl; }()); + graph_1.MetanodeImpl = MetanodeImpl; ; function createMetaedge(v, w) { return new MetaedgeImpl(v, w); @@ -4527,6 +4529,7 @@ var tf; var parts = name.split(graph_1.NAMESPACE_DELIM); return name + graph_1.NAMESPACE_DELIM + '(' + parts[parts.length - 1] + ')'; } + graph_1.getStrictName = getStrictName; /** * For each op node (embedding or non-embedding), rename it if there is a * non-embedding node under its namespace. For example, assume node name 'A'. @@ -6494,6 +6497,7 @@ var tf; this.index[hierarchy.root.name] = this.root; this.buildSubhierarchy(hierarchy.root.name); this.root.expanded = true; + this.traceInputs = false; } RenderGraphInfo.prototype.computeScales = function () { this.deviceColorMap = d3.scale.ordinal() @@ -8788,10 +8792,333 @@ var tf; d3.rgb(fill).darker().toString(); } node_1.getStrokeForFill = getStrokeForFill; + /** + * Finds selected node and highlights all nodes which are providing direct + * or indirect input to the node and all edges connecting these nodes + * together and to the selected node. + * + * @param renderGraphInfo Information on the rendered state of the graph. + */ + function traceInputs(renderGraphInfo) { + // Reset all styling. + d3.selectAll('.input-highlight').classed('input-highlight', false); + d3.selectAll('.non-input').classed('non-input', false); + d3.selectAll('.input-parent').classed('input-parent', false); + d3.selectAll('.input-child').classed('input-child', false); + d3.selectAll('.input-edge-highlight').classed('input-edge-highlight', false); + d3.selectAll('.non-input-edge-highlight') + .classed('non-input-edge-highlight', false); + d3.selectAll('.input-highlight-selected') + .classed('input-highlight-selected', false); + // Extract currently selected node. Return if input tracing disabled or no + // node is selected. + var selectedNodeSelectorString = 'g.node.selected,g.op.selected'; + var node = d3.select(selectedNodeSelectorString); + var currentNode = undefined; + if (renderGraphInfo && renderGraphInfo.traceInputs && node && node[0] && + node[0][0]) { + currentNode = node[0][0]; + } + else { + return; + } + var nodeName = currentNode.getAttribute('data-name'); + var opNodes = _getAllContainedOpNodes(nodeName, renderGraphInfo); + var allTracedNodes = {}; + _.each(opNodes, function (nodeInstance) { + allTracedNodes = + traceAllInputsOfOpNode(renderGraphInfo, nodeInstance, allTracedNodes); + }); + d3.selectAll(selectedNodeSelectorString).classed({ + // Remove the input-highlight from the selected node. + 'input-highlight': false, + // Add input-highlight-selected class to selected node, which allows + // treating the selected not as a special case of an input node. + 'input-highlight-selected': true + }); + // Highlight all parent nodes of each OpNode as input parent to allow + // specific highlighting. + var highlightedNodes = Object.keys(allTracedNodes); + var visibleNodes = _findVisibleParentsFromOpNodes(renderGraphInfo, highlightedNodes); + _markParentsOfNodes(visibleNodes); + // Attach class to all non-input nodes and edges for styling. + d3.selectAll('g.node:not(.selected):not(.input-highlight)' + + ':not(.input-parent):not(.input-children)') + .classed('non-input', true) + .each(function (d) { + // Mark all nodes with the specified name as non-inputs. This + // results in Annotation nodes which are attached to inputs to be + // tagged as well. + var nodeName = d.node.name; + d3.selectAll("[data-name=\"" + nodeName + "\"]").classed('non-input', true); + }); + d3.selectAll('g.edge:not(.input-edge-highlight)') + .classed('non-input-edge-highlight', true); + } + node_1.traceInputs = traceInputs; + /** + * Recursively find all op nodes contained by the node identified by the + * provided name. + * @param nodeName The meta or op node of which the OpNode instances are + * required. + * @param renderGraphInfo The rendered graph information object. + * @returns {Array} An array of OpNodeImpl instances. + */ + function _getAllContainedOpNodes(nodeName, renderGraphInfo) { + var opNodes = []; + // Get current node. + var node = renderGraphInfo.getNodeByName(nodeName); + // If node is already OpNode then return the node plus its input embeddings. + if (node instanceof tf.graph.OpNodeImpl) { + return [node].concat(node.inEmbeddings); + } + // Otherwise, make recursive call for each node contained by the GroupNode. + var childNodeNames = node.metagraph.nodes(); + _.each(childNodeNames, function (childNodeName) { + opNodes = + opNodes.concat(_getAllContainedOpNodes(childNodeName, renderGraphInfo)); + }); + return opNodes; + } + node_1._getAllContainedOpNodes = _getAllContainedOpNodes; + function traceAllInputsOfOpNode(renderGraphInfo, startNode, allTracedNodes) { + // To prevent infinite loops due to cyclical relationships and improving + // performance by tracing OpNode which is input to 2+ nodes only once. + if (allTracedNodes[startNode.name]) { + return allTracedNodes; + } + else { + allTracedNodes[startNode.name] = true; + } + // Extract the inputs. + var inputs = startNode.inputs; + // Get visible parent. + var currentVisibleParent = getVisibleParent(renderGraphInfo, startNode); + // Mark as input node. + d3.select(".node[data-name=\"" + currentVisibleParent.name + "\"]") + .classed('input-highlight', true); + // Find the visible parent of each input. + var visibleInputs = {}; + _.each(inputs, function (nodeInstance) { + var resolvedNode = renderGraphInfo.getNodeByName(nodeInstance.name); + if (resolvedNode === undefined) { + // Node could not be found in rendered Hierarchy, which happens when + // tracing inputs of a SummaryNode. + return; + } + // Ensure node is resolved to OpNode if name collision with Metanode exists. + if (resolvedNode instanceof graph.MetanodeImpl) { + var resolvedNodeName = tf.graph.getStrictName(resolvedNode.name); + resolvedNode = renderGraphInfo.getNodeByName(resolvedNodeName); + } + var visibleParent = getVisibleParent(renderGraphInfo, resolvedNode); + // Append OpNode to visible parent entry. + var visibleInputsEntry = visibleInputs[visibleParent.name]; + if (visibleInputsEntry) { + visibleInputsEntry.opNodes.push(resolvedNode); + } + else { + visibleInputs[visibleParent.name] = { + visibleParent: visibleParent, + opNodes: [resolvedNode] + }; + } + }); + // Find all parents of the start node. + var startNodeParents = {}; + var indexedStartNodeParents = [currentVisibleParent]; + startNodeParents[currentVisibleParent.name] = { + traced: false, + index: 0, + connectionEndpoints: [] + }; + var currentNode = currentVisibleParent; + for (var index = 1; currentNode.name !== tf.graph.ROOT_NAME; index++) { + currentNode = currentNode.parentNode; + startNodeParents[currentNode.name] = { + traced: false, + index: index, + connectionEndpoints: [] + }; + indexedStartNodeParents[index] = currentNode; + } + // Find first mutual parent of each input node and highlight connection. + _.forOwn(visibleInputs, function (visibleParentInfo, key) { + var nodeInstance = visibleParentInfo.visibleParent; + // Make recursive call for each input-OpNode contained by the visible + // parent. + _.each(visibleParentInfo.opNodes, function (opNode) { + allTracedNodes = + traceAllInputsOfOpNode(renderGraphInfo, opNode, allTracedNodes); + }); + if (nodeInstance.name !== currentVisibleParent.name) { + _createVisibleTrace(nodeInstance, startNodeParents, indexedStartNodeParents); + } + }); + return allTracedNodes; + } + node_1.traceAllInputsOfOpNode = traceAllInputsOfOpNode; + /** + * Colors the edges to connect the passed node to the start node. This is + * done by: + * + * a) Finding the first (visible) common parent in the rendered + * hierarchy. + * NB: There are 2 types of connections: + * 1) Direct connections between node A + * and B, marked below as II, + * 2) Connections from any node A to its parent, A'. Marked below as I and III. + * For type 2 connection you need to know the inner-nested node, the + * direct parent, and the ultimate destination of the connection. + * + * A_parent B_parent + * +--------+ +---------+ + * | | | | + * | +--+ I| II |III+--+ | + * | |A +----------\x3e+B | | + * | +--+ | | +--+ | + * | | | | + * +--------+ +---------+ + * + * + * b) Highlighting the direct connection between the parents of A and B, + * called A_parent and B_parent, s.t. A_parent and B_parent are children of the + * mutual parent of A and B found in a), marked above as II. + * + * c) Highlighting the connection from A to A_parent and B to B_parent + * (through all layers of parents between A and A_parent and B and B_parent, + * respectively). Marked above as I and III. + * + * @param nodeInstance The instance of the node to use as destination node, B. + * @param startNodeParents Map of startNodeParent names to information objects + * about the parent. + * @param indexedStartNodeParents An array of all parents of the start node. + * This is required to find the child of the mutual parent which is a parent + * of the start node. + * @private + */ + function _createVisibleTrace(nodeInstance, startNodeParents, indexedStartNodeParents) { + var currentNode = nodeInstance; + var previousNode = nodeInstance; + // Ascend through parents until a mutual parent is found with the start + // node. + var destinationParentPairs = []; + while (!startNodeParents[currentNode.name]) { + if (previousNode.name !== currentNode.name) { + destinationParentPairs.push([previousNode, currentNode]); + } + previousNode = currentNode; + currentNode = currentNode.parentNode; + } + // Connection between nodes is drawn between the parents of each + // respective node, both of which share the mutual parent. + var startNodeIndex = startNodeParents[currentNode.name].index; + var startNodeName = indexedStartNodeParents[Math.max(startNodeIndex - 1, 0)].name; + var startNodeTopParentName = startNodeName; + var targetNodeTopParentName = previousNode.name; + var endNodeName = previousNode.name; + d3.selectAll("[data-edge=\"" + endNodeName + "--" + startNodeName + "\"]") + .classed('input-edge-highlight', true); + // Trace up the parents of the input. + _.each(destinationParentPairs, function (value) { + var inner = value[0]; + var outer = value[1]; + var edgeSelector = ("[data-edge=\"" + inner.name + "--" + startNodeTopParentName) + + ("~~" + outer.name + "~~OUT\"]"); + d3.selectAll(edgeSelector).classed('input-edge-highlight', true); + }); + // Trace up the parents of the start node. + for (var index = 1; index < startNodeIndex; index++) { + var inner = indexedStartNodeParents[index - 1]; + var outer = indexedStartNodeParents[index]; + var edgeSelector = ("[data-edge=\"" + targetNodeTopParentName + "~~" + outer.name) + + ("~~IN--" + inner.name + "\"]"); + d3.selectAll(edgeSelector).classed('input-edge-highlight', true); + } + } + /** + * Creates map { [name: string] -> Node } of all visible / rendered parents + * of the nodes identified by the node names passed in. + * + * @param renderGraphInfo The information on the rendered graph. + * @param nodeNames String array of node names. + * @returns {[nodeName: string]: Node} + * @private + */ + function _findVisibleParentsFromOpNodes(renderGraphInfo, nodeNames) { + var visibleParents = {}; + _.each(nodeNames, function (nodeName) { + var currentNode = renderGraphInfo.getNodeByName(nodeName); + var visibleParent = getVisibleParent(renderGraphInfo, currentNode); + visibleParents[visibleParent.name] = visibleParent; + }); + return visibleParents; + } + /** + * Traverse through the parents of all nodes in the list and mark each + * encountered node as input-parent. + * @param visibleNodes Map of input nodes, have to be visible/rendered when + * called. + * @private + */ + function _markParentsOfNodes(visibleNodes) { + _.forOwn(visibleNodes, function (nodeInstance) { + // Mark all parents of the node as input-parents. + var currentNode = nodeInstance; + while (currentNode.name !== tf.graph.ROOT_NAME) { + var renderedElement = d3.select(".node[data-name=\"" + currentNode.name + "\"]"); + // Only mark the element as a parent node to an input if it is not + // marked as input node itself. + if (renderedElement[0][0] && + !renderedElement.classed('input-highlight') && + !renderedElement.classed('selected') && + // OpNode only parent if start node is embedded node, in which case + // the OpNode should be faded as well. + !renderedElement.classed('op')) { + renderedElement.classed('input-parent', true); + } + currentNode = currentNode.parentNode; + } + }); + } + /** + * Find the parent of the passed in op node which is expanded. This is done + * by going through all parents until the parent's parent is expanded, thus + * finding the the first unexpanded parent which is rendered on the screen. + * @param renderGraphInfo The graph info object used to gain access to the + * render info of the parents. + * @param currentNode The node whose parent is to be found. + * @returns Node + */ + function getVisibleParent(renderGraphInfo, currentNode) { + var found = false; + var currentParent = currentNode; + while (!found) { + // Get parent element, to extract name. + currentNode = currentParent; + currentParent = currentNode.parentNode; + if (currentParent === undefined) { + found = true; + } + else { + var renderNode = renderGraphInfo.getRenderNodeByName(currentParent.name); + // Found if node is rendered on the screen (renderNode truthy), and + // the parent is either expanded (i.e. it is a metanode or seriesnode) + // or the parent is an OpNode in which case currentNode is an embedded + // node which has another OpNode as parent. + if (renderNode && + (renderNode.expanded || currentParent instanceof graph.OpNodeImpl)) { + found = true; + } + } + } // Close while loop. + return currentNode; + } + node_1.getVisibleParent = getVisibleParent; })(node = scene.node || (scene.node = {})); })(scene = graph.scene || (graph.scene = {})); })(graph = tf.graph || (tf.graph = {})); -})(tf || (tf = {})); // close module +})(tf || (tf = {})); // Close module. </script> <script>/* Copyright 2015 The TensorFlow Authors. All Rights Reserved. @@ -10137,6 +10464,7 @@ Polymer({ ::content .faded rect, ::content .faded ellipse, ::content .faded path, +::content .faded use, ::content #rectHatch line, ::content #ellipseHatch line { color: #e0d4b3 !important; @@ -10153,7 +10481,8 @@ Polymer({ fill: url("#rectHatch") !important; } -::content .faded ellipse { +::content .faded ellipse, +::content .faded use { fill: url("#ellipseHatch") !important; } @@ -10161,6 +10490,81 @@ Polymer({ opacity: 0; } +/* Rules used for input-tracing. */ +::content .input-highlight > * > rect, +::content .input-highlight > * > ellipse, +::content .input-highlight > * > use +{ + fill: white; + stroke: #ff9800 !important; +} + +/* - Faded non-input styling */ +::content .non-input > * > rect, +::content .non-input > * > ellipse, +::content .non-input > * > use, +/* For Const nodes. */ +::content .non-input > * > .constant:not([class*="input-highlight"]) > + .annotation-node > ellipse, +/* For styling of annotation nodes of non-input nodes. */ +::content .non-input > g > .annotation > .annotation-node > rect { + stroke: #e0d4b3 !important; + stroke-width: inherit; + stroke-dasharray: inherit; +} + + +::content .non-input path { + visibility: hidden; +} + +::content .non-input > .nodeshape > rect, +::content .non-input > .annotation-node > rect, +/* For styling of annotation nodes of non-input nodes. */ +::content .non-input > g > .annotation > .annotation-node > rect +{ + fill: url("#rectHatch") !important; +} + +::content .non-input ellipse, +::content .non-input use { + fill: url("#ellipseHatch") !important; +} + +::content .non-input > text { + opacity: 0; +} + +::content .non-input .annotation > .annotation-edge { + marker-end: url("#annotation-arrowhead-faded"); +} + +::content .non-input .annotation > .annotation-edge.refline { + marker-start: url("#ref-annotation-arrowhead-faded"); +} + +/* Input edges. */ +::content .input-edge-highlight > text { + fill: black !important; +} +::content .input-edge-highlight > path, +::content .input-highlight > .in-annotations > .annotation > .annotation-edge, +::content .input-highlight-selected > .in-annotations > .annotation > +.annotation-edge { + stroke: #999 !important; +} + +/* Non-input edges. */ +::content .non-input-edge-highlight, +::content .non-input > g > .annotation > path, +/* Annotation styles (label and edges respectively). */ +::content .non-input > g > +.annotation:not(.input-highlight):not(.input-highlight-selected) > +.annotation-label +/*.annotation-edge*/ +{ + visibility: hidden; +} /* --- Op Node --- */ @@ -10689,6 +11093,7 @@ Polymer({ tf.graph.util.time('tf-graph-scene (build scene):', function() { tf.graph.scene.buildGroup(d3.select(this.$.root), renderHierarchy.root, this); tf.graph.scene.addGraphClickListener(this.$.svg, this); + tf.graph.scene.node.traceInputs(renderHierarchy); }.bind(this)); // Update the minimap again when the graph is done animating. setTimeout(function() { @@ -10853,6 +11258,13 @@ Polymer({ }, this); }, + /** + * Handles new node selection. 1) Updates the selected-state of each node, + * 2) triggers input tracing. + * @param selectedNode {string} The name of the newly selected node. + * @param oldSelectedNode {string} The name of the previously selected node. + * @private + */ _selectedNodeChanged: function(selectedNode, oldSelectedNode) { if (selectedNode === oldSelectedNode) { return; @@ -10865,9 +11277,13 @@ Polymer({ this._updateNodeState(oldSelectedNode); } + tf.graph.scene.node.traceInputs(this.renderHierarchy); + if (!selectedNode) { return; } + + // Update the minimap to reflect the highlighted (selected) node. this.minimap.update(); var node = this.renderHierarchy.hierarchy.node(selectedNode); @@ -12296,10 +12712,10 @@ paper-progress { </template> <div class$="[[_getContainerClass(progress)]]"> <div id="main"> - <tf-graph id="graph" graph-hierarchy="{{graphHierarchy}}" basic-graph="[[graph]]" hierarchy-params="[[hierarchyParams]]" render-hierarchy="{{_renderHierarchy}}" devices-for-stats="[[devicesForStats]]" stats="[[stats]]" selected-node="{{_selectedNode}}" highlighted-node="{{_highlightedNode}}" color-by="[[colorBy]]" color-by-params="{{colorByParams}}" progress="{{progress}}"></tf-graph> + <tf-graph id="graph" graph-hierarchy="{{graphHierarchy}}" basic-graph="[[graph]]" hierarchy-params="[[hierarchyParams]]" render-hierarchy="{{renderHierarchy}}" devices-for-stats="[[devicesForStats]]" stats="[[stats]]" selected-node="{{_selectedNode}}" highlighted-node="{{_highlightedNode}}" color-by="[[colorBy]]" color-by-params="{{colorByParams}}" 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> + <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> </div> <div class="context-menu"></div> </div> @@ -12324,14 +12740,17 @@ Polymer({ colorBy: String, colorByParams: { type: Object, - notify: true, + notify: true + }, + renderHierarchy: { + type: Object, + notify: true }, // Private API: Data routing between child components. _selectedNode: String, // The enum value of the include property of the selected node. _selectedNodeInclude: Number, - _highlightedNode: String, - _renderHierarchy: Object, + _highlightedNode: String }, listeners: { 'node-toggle-extract': '_nodeToggleExtract' @@ -12618,6 +13037,14 @@ span.counter { </div> </div> <div class="control-holder"> + <div class="title"> + Trace inputs + </div> + <paper-toggle-button id="trace-inputs"> + + </paper-toggle-button> + </div> + <div class="control-holder"> <div class="title">Color</div> <paper-radio-group selected="{{colorBy}}"> <paper-radio-button name="structure">Structure</paper-radio-button> @@ -12846,6 +13273,10 @@ Polymer({ type: Array, observer: '_datasetsChanged' }, + renderHierarchy: { + type: Object, + notify: true, + }, metadataTags: { type: Array, computed: '_getMetadataTags(selectedDataset, datasets)' @@ -12870,6 +13301,14 @@ Polymer({ computed: '_getCurrentGradientParams(colorByParams, colorBy)' } }, + listeners: { + 'trace-inputs.change': '_traceInputToggleChanged' + }, + _traceInputToggleChanged: function(event) { + // Flip the state of the trace inputs flag. + this.renderHierarchy.traceInputs = event.target.active; + tf.graph.scene.node.traceInputs(this.renderHierarchy); + }, _statsNotNull: function(stats) { return stats != null; }, @@ -12988,6 +13427,7 @@ Polymer({ if (this.datasets) { this.set('selectedMetadataTag', -1); this.set('colorBy', 'structure'); + this.$['trace-inputs'].active = false; // Set trace input to off-state. this._setDownloadFilename(this.datasets[newDataset].path); } }, @@ -13019,12 +13459,11 @@ Polymer({ <template is="dom-if" if="[[!_datasetsEmpty(_datasets)]]"> <tf-dashboard-layout> <div class="sidebar"> - <tf-graph-controls id="controls" devices-for-stats="{{_devicesForStats}}" color-by-params="[[_colorByParams]]" stats="[[_stats]]" color-by="{{_colorBy}}" ,="" datasets="[[_datasets]]" selected-dataset="{{_selectedDataset}}" selected-file="{{_selectedFile}}" selected-metadata-tag="{{_selectedMetadataTag}}"></tf-graph-controls> - <tf-graph-loader id="loader" datasets="[[_datasets]]" ,="" selected-dataset="[[_selectedDataset]]" selected-metadata-tag="[[_selectedMetadataTag]]" selected-file="[[_selectedFile]]" out-graph-hierarchy="{{_graphHierarchy}}" out-graph="{{_graph}}" out-stats="{{_stats}}" progress="{{_progress}}" out-hierarchy-params="{{_hierarchyParams}}"></tf-graph-loader> + <tf-graph-controls id="controls" devices-for-stats="{{_devicesForStats}}" color-by-params="[[_colorByParams]]" stats="[[_stats]]" color-by="{{_colorBy}}" datasets="[[_datasets]]" render-hierarchy="[[_renderHierarchy]]" selected-dataset="{{_selectedDataset}}" selected-file="{{_selectedFile}}" selected-metadata-tag="{{_selectedMetadataTag}}"></tf-graph-controls> + <tf-graph-loader id="loader" datasets="[[_datasets]]" selected-dataset="[[_selectedDataset]]" selected-metadata-tag="[[_selectedMetadataTag]]" selected-file="[[_selectedFile]]" out-graph-hierarchy="{{_graphHierarchy}}" out-graph="{{_graph}}" out-stats="{{_stats}}" progress="{{_progress}}" out-hierarchy-params="{{_hierarchyParams}}"></tf-graph-loader> </div> <div class="center"> - <tf-graph-board id="graphboard" devices-for-stats="[[_devicesForStats]]" graph-hierarchy="[[_graphHierarchy]]" graph="[[_graph]]" stats="[[_stats]]" progress="[[_progress]]" color-by="[[_colorBy]]" color-by-params="{{_colorByParams}}" hierarchy-params="[[_hierarchyParams]]"> - </tf-graph-board> + <tf-graph-board id="graphboard" devices-for-stats="[[_devicesForStats]]" color-by="[[_colorBy]]" color-by-params="{{_colorByParams}}" graph-hierarchy="[[_graphHierarchy]]" graph="[[_graph]]" hierarchy-params="[[_hierarchyParams]]" progress="[[_progress]]" render-hierarchy="{{_renderHierarchy}}" stats="[[_stats]]"></tf-graph-board> </div> </tf-dashboard-layout> </template> @@ -13049,8 +13488,9 @@ Polymer({ is: 'tf-graph-dashboard', properties: { _datasets: Object, + _renderHierarchy: Object, backend: {type: Object, observer: 'reload'}, - runs: Array, + runs: Array }, reload: function() { Promise.all([this.backend.graphRuns(), this.backend.runMetadataRuns()]) |