diff options
3 files changed, 74 insertions, 48 deletions
diff --git a/tensorflow/tensorboard/components/tf_graph/tf-graph-scene.html b/tensorflow/tensorboard/components/tf_graph/tf-graph-scene.html index 480104519b..c837e6c684 100644 --- a/tensorflow/tensorboard/components/tf_graph/tf-graph-scene.html +++ b/tensorflow/tensorboard/components/tf_graph/tf-graph-scene.html @@ -479,6 +479,15 @@ limitations under the License. display: none; } +::content .health-pill { + filter: url(#health-pill-shadow); +} + +::content .health-pill rect { + rx: 3; + ry: 3; +} + .titleContainer { position: relative; top: 20px; @@ -581,6 +590,18 @@ limitations under the License. <pattern id="ellipseHatch" patternTransform="rotate(45 0 0)" width="2" height="2" patternUnits="userSpaceOnUse"> <line x1="0" y1="0" x2="0" y2="2" style="stroke-width: 1"/> </pattern> + + <!-- A shadow for health pills. --> + <filter id="health-pill-shadow" x="-40%" y="-40%" width="180%" height="180%"> + <feGaussianBlur in="SourceAlpha" stdDeviation="0.8"/> + <feOffset dx="0" dy="0" result="offsetblur"/> + <feFlood flood-color="#000000"/> + <feComposite in2="offsetblur" operator="in"/> + <feMerge> + <feMergeNode/> + <feMergeNode in="SourceGraphic"/> + </feMerge> + </filter> </defs> <!-- Make a large rectangle that fills the svg space so that zoom events get captured on safari --> @@ -895,7 +916,8 @@ Polymer({ return this._edgeGroupIndex[e]; }, _updateHealthPills: function(nodeNamesToHealthPills, healthPillStepIndex) { - tf.graph.scene.addHealthPills(this.$.svg, nodeNamesToHealthPills, healthPillStepIndex); + tf.graph.scene.addHealthPills( + this.$.svg, nodeNamesToHealthPills, healthPillStepIndex); }, /** * Update node and annotation node of the given name. diff --git a/tensorflow/tensorboard/components/tf_graph/tf-graph.html b/tensorflow/tensorboard/components/tf_graph/tf-graph.html index 7e4fe9e6e7..8792f475c4 100644 --- a/tensorflow/tensorboard/components/tf_graph/tf-graph.html +++ b/tensorflow/tensorboard/components/tf_graph/tf-graph.html @@ -61,7 +61,7 @@ paper-button { <tf-graph-scene id="scene" class="auto" render-hierarchy="[[renderHierarchy]]" highlighted-node="[[_getVisible(highlightedNode)]]" - selected-node="[[selectedNode]]" + selected-node="{{selectedNode}}" color-by="[[colorBy]]" progress="[[progress]]" node-names-to-health-pills="[[nodeNamesToHealthPills]]" diff --git a/tensorflow/tensorboard/components/tf_graph_common/lib/scene/scene.ts b/tensorflow/tensorboard/components/tf_graph_common/lib/scene/scene.ts index 182936dcf2..2b5e6c8b29 100644 --- a/tensorflow/tensorboard/components/tf_graph_common/lib/scene/scene.ts +++ b/tensorflow/tensorboard/components/tf_graph_common/lib/scene/scene.ts @@ -103,23 +103,23 @@ module tf.graph.scene { label: 'NaN', }, { - background_color: '#FFFF00', + background_color: '#FF8D00', label: '- ∞', }, { - background_color: '#A8A8A8', + background_color: '#EAEAEA', label: '-', }, { - background_color: '#D8DBE2', + background_color: '#A5A5A5', label: '0', }, { - background_color: '#424242', + background_color: '#262626', label: '+', }, { - background_color: '#FFA500', + background_color: '#003ED4', label: '+ ∞', }, ]; @@ -512,9 +512,7 @@ function _addHealthPill( nodeGroupElement: SVGElement, healthPill: HealthPill, nodeInfo: render.RenderGroupNodeInfo) { // Check if text already exists at location. - d3.select(nodeGroupElement.parentNode) - .selectAll('.health-pill-group') - .remove(); + d3.select(nodeGroupElement.parentNode).selectAll('.health-pill').remove(); if (!nodeInfo || !healthPill) { return; @@ -525,6 +523,7 @@ function _addHealthPill( // For now, we only visualize the 6 values that summarize counts of tensor // elements of various categories: -Inf, negative, 0, positive, Inf, and NaN. let lastHealthPillOverview = lastHealthPillData.slice(2, 8); + let totalCount = lastHealthPillData[1]; let healthPillWidth = 60; let healthPillHeight = 10; @@ -534,66 +533,71 @@ function _addHealthPill( healthPillHeight /= 2; } - let healthPillSvg = document.createElementNS(svgNamespace, 'svg'); - healthPillSvg.classList.add('health-pill-group'); - healthPillSvg.setAttribute('width', String(healthPillWidth)); - healthPillSvg.setAttribute('height', String(healthPillHeight)); - - let svgDefs = document.createElementNS(svgNamespace, 'defs'); - healthPillSvg.appendChild(svgDefs); - let clipPath = document.createElementNS(svgNamespace, 'clipPath'); - clipPath.setAttribute('id', 'health-pill-clip-path'); - svgDefs.appendChild(clipPath); - let clipRect = document.createElementNS(svgNamespace, 'rect'); - clipRect.setAttribute('height', String(healthPillHeight)); - clipRect.setAttribute('width', String(healthPillWidth)); - clipRect.setAttribute('rx', '2'); - clipRect.setAttribute('ry', '2'); - clipPath.appendChild(clipRect); - - let rectGroup = document.createElementNS(svgNamespace, 'g'); - rectGroup.setAttribute('clip-path', 'url(#health-pill-clip-path)'); - healthPillSvg.appendChild(rectGroup); - let totalCount = lastHealthPillData[1]; - // Create 1 rectangle for each category. - let totalCountSoFar = 0; - let totalWidthDividedByTotalCount = healthPillWidth / totalCount; + let healthPillGroup = document.createElementNS(svgNamespace, 'g'); + healthPillGroup.classList.add('health-pill'); + + // Define the gradient for the health pill. + let healthPillDefs = document.createElementNS(svgNamespace, 'defs'); + healthPillGroup.appendChild(healthPillDefs); + let healthPillGradient = + document.createElementNS(svgNamespace, 'linearGradient'); + const healthPillGradientId = 'health-pill-gradient'; + healthPillGradient.setAttribute('id', healthPillGradientId); let titleOnHoverTextEntries = []; + let cumulativeCount = 0; + let previousOffset = '0%'; for (let i = 0; i < lastHealthPillOverview.length; i++) { if (!lastHealthPillOverview[i]) { - // Do not render empty rectangles. + // Exclude empty categories. continue; } - let rect = document.createElementNS(svgNamespace, 'rect'); - rect.setAttribute('height', String(healthPillHeight)); - let rectWidth = totalWidthDividedByTotalCount * lastHealthPillOverview[i]; - rect.setAttribute('width', String(rectWidth)); - let rectX = totalWidthDividedByTotalCount * totalCountSoFar; - rect.setAttribute('x', String(rectX)); - rect.setAttribute('fill', healthPillEntries[i].background_color); - totalCountSoFar += lastHealthPillOverview[i]; - rectGroup.appendChild(rect); + cumulativeCount += lastHealthPillOverview[i]; + + // Create a color interval using 2 stop elements. + let stopElement0 = document.createElementNS(svgNamespace, 'stop'); + stopElement0.setAttribute('offset', previousOffset); + stopElement0.setAttribute( + 'stop-color', healthPillEntries[i].background_color); + healthPillGradient.appendChild(stopElement0); + + let stopElement1 = document.createElementNS(svgNamespace, 'stop'); + let percent = (cumulativeCount * 100 / totalCount) + '%'; + stopElement1.setAttribute('offset', percent); + stopElement1.setAttribute( + 'stop-color', healthPillEntries[i].background_color); + healthPillGradient.appendChild(stopElement1); + previousOffset = percent; // Include this number in the title that appears on hover. titleOnHoverTextEntries.push( healthPillEntries[i].label + ': ' + lastHealthPillOverview[i]); } + healthPillDefs.appendChild(healthPillGradient); + + // Create the rectangle for the health pill. + let rect = document.createElementNS(svgNamespace, 'rect'); + rect.setAttribute('fill', 'url(#' + healthPillGradientId + ')'); + rect.setAttribute('width', String(healthPillWidth)); + rect.setAttribute('height', String(healthPillHeight)); + healthPillGroup.appendChild(rect); // Show a title with specific counts on hover. let titleSvg = document.createElementNS(svgNamespace, 'title'); titleSvg.textContent = titleOnHoverTextEntries.join(', '); - healthPillSvg.appendChild(titleSvg); + healthPillGroup.appendChild(titleSvg); // Center this health pill just right above the node for the op. let healthPillX = nodeInfo.x - healthPillWidth / 2; - healthPillSvg.setAttribute('x', String(healthPillX)); let healthPillY = nodeInfo.y - healthPillHeight - nodeInfo.height / 2 - 2; if (nodeInfo.labelOffset < 0) { // The label is positioned above the node. Do not occlude the label. healthPillY += nodeInfo.labelOffset; } - healthPillSvg.setAttribute('y', String(healthPillY)); - Polymer.dom(nodeGroupElement.parentNode).appendChild(healthPillSvg); + + healthPillGroup.setAttribute( + 'transform', 'translate(' + healthPillX + ', ' + healthPillY + ')'); + + Polymer.dom(nodeGroupElement.parentNode).appendChild(healthPillGroup); } /** |