aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/tensorboard/components/tf-graph/tf-graph-controls.html
diff options
context:
space:
mode:
Diffstat (limited to 'tensorflow/tensorboard/components/tf-graph/tf-graph-controls.html')
-rw-r--r--tensorflow/tensorboard/components/tf-graph/tf-graph-controls.html487
1 files changed, 487 insertions, 0 deletions
diff --git a/tensorflow/tensorboard/components/tf-graph/tf-graph-controls.html b/tensorflow/tensorboard/components/tf-graph/tf-graph-controls.html
new file mode 100644
index 0000000000..4a6901e911
--- /dev/null
+++ b/tensorflow/tensorboard/components/tf-graph/tf-graph-controls.html
@@ -0,0 +1,487 @@
+<link rel="import" href="../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../bower_components/paper-menu/paper-menu.html">
+<link rel="import" href="../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
+
+<dom-module id="tf-graph-controls">
+<template>
+<style>
+:host {
+ font-size: 12px;
+ color: gray;
+ --paper-font-subhead: {
+ font-size: 14px;
+ color: gray;
+ };
+ --paper-dropdown-menu-icon: {
+ width: 15px;
+ height: 15px;
+ };
+ --paper-dropdown-menu-button: {
+ padding: 0;
+ };
+ --paper-dropdown-menu-input: {
+ padding: 0;
+ };
+ --paper-item-min-height: 30px;
+}
+
+paper-button[raised].keyboard-focus {
+ font-weight: normal;
+}
+
+.run-dropdown {
+ --paper-input-container: {
+ padding: 9px 0 0 25px;
+ };
+}
+
+.color-dropdown {
+ --paper-input-container: {
+ padding: 9px 0 0 13px;
+ };
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+table td {
+ padding: 0;
+ margin: 0;
+}
+
+.allcontrols {
+ padding: 10px;
+}
+
+.legend-holder {
+ position: absolute;
+ bottom: 0;
+ padding-bottom: 10px;
+}
+
+#fit {
+ color: var(--paper-orange-500);
+}
+
+paper-radio-button {
+ padding: 5px;
+}
+svg.icon {
+ width: 60px;
+ height: 18px;
+}
+.icon ellipse {
+ rx: 10px;
+ ry: 5px;
+ stroke: #CCC;
+ stroke-width: 1px;
+ fill: #FFFFFF;
+ cy: 10px;
+}
+.icon rect {
+ height: 14px;
+ width: 35px;
+ rx: 5px;
+ ry: 5px;
+ stroke: #CCC;
+ stroke-width: 2px;
+ fill: #D9D9D9;
+}
+.domainValues {
+ width: 165px;
+}
+.domainStart {
+ float: left;
+}
+.domainEnd {
+ float: right;
+}
+.colorBox {
+ width: 20px;
+}
+
+.image-icon {
+ width: 24px;
+ height: 24px;
+}
+
+.gray {
+ color: #666;
+}
+
+.title {
+ font-size: 16px;
+ margin: 8px 5px 8px 0;
+ color: black;
+}
+.title small {
+ font-weight: normal;
+}
+.deviceList {
+ max-height: 100px;
+ overflow-y: auto;
+}
+
+#file {
+ padding: 8px 0;
+}
+
+.color-text {
+ padding: 0 0 0 55px;
+}
+
+.fit-button-text {
+ text-transform: none;
+ padding: 8px 18px 0 18px;
+ font-size: 14px
+}
+
+.upload-button {
+ width: 165px;
+ height: 25px;
+ text-transform: none;
+ margin-top: 4px;
+}
+
+.fit-button {
+ padding: 2px;
+ width: 30px;
+ height: 30px;
+}
+
+.hidden-input {
+ height: 0px;
+ width: 0px;
+ overflow:hidden;
+}
+
+.allcontrols .control-holder {
+ display: flex;
+ clear: both;
+}
+</style>
+<div class="allcontrols">
+ <div class="control-holder">
+ <paper-icon-button id="fit" icon="aspect-ratio" class="fit-button" on-click="fit" alt="Fit to screen">
+ </paper-icon-button>
+ <paper-button class="fit-button-text" on-click="fit">Fit to screen
+ </paper-button>
+ </div>
+ <div class="control-holder">
+ <div class="title">Run</div>
+ <paper-dropdown-menu no-label-float no-animations noink class="run-dropdown">
+ <paper-menu id="select" class="dropdown-content" selected="{{selectedDataset}}">
+ <template is="dom-repeat" items="[[datasets]]">
+ <paper-item>[[item.name]]</paper-item>
+ </template>
+ </paper-menu>
+ </paper-dropdown-menu>
+ </div>
+ <div class="control-holder">
+ <div class="title">Upload</div>
+ <paper-button raised class="text-button upload-button"
+ on-click="_getFile">Choose File</paper-button>
+ <div class="hidden-input">
+ <input type="file" id="file" name="file" on-change="_updateFileInput" />
+ </div>
+ </div>
+ <div class="control-holder">
+ <div class="title">Color</div>
+ <paper-dropdown-menu no-label-float no-animations noink class="color-dropdown">
+ <paper-menu class="dropdown-content" selected="{{_colorByIndex}}">
+ <paper-item>Structure</paper-item>
+ <paper-item>Device</paper-item>
+ <template is="dom-if" if="[[hasStats]]">
+ <paper-item>Compute time</paper-item>
+ <paper-item>Memory</paper-item>
+ </template>
+ </paper-menu>
+ </paper-dropdown-menu>
+ </div>
+ <div>
+ <template is="dom-if" if="[[_isGradientColoring(colorBy)]]">
+ <svg width="160" height="20" style="margin: 0 5px" class="color-text">
+ <defs>
+ <linearGradient id="linearGradient" x1="0%" y1="0%" x2="100%" y2="0%">
+ <stop class="start" offset="0%"
+ stop-color$="[[_currentGradientParams.startColor]]"/>
+ <stop class="end" offset="100%"
+ stop-color$="[[_currentGradientParams.endColor]]"/>
+ </linearGradient>
+ </defs>
+ <rect x="0" y="0" width="160" height="20" fill="url(#linearGradient)"
+ stroke="black" />
+ </svg>
+ <div class="domainValues color-text">
+ <div class="domainStart">[[_currentGradientParams.minValue]]</div>
+ <div class="domainEnd">[[_currentGradientParams.maxValue]]</div>
+ </div>
+ </template>
+ <template is="dom-if" if="[[_equals(colorBy, 'structure')]]">
+ <div class="color-text">
+ color: same substructure<br/>
+ gray: unique substructure
+ </div>
+ </template>
+ <template is="dom-if" if="[[_equals(colorBy, 'device')]]">
+ <div class="color-text">
+ <div class="deviceList">
+ <table>
+ <template is="dom-repeat" items="[[colorByParams.device]]">
+ <tr>
+ <td style$="[[_getBackgroundColor(item.color)]]">
+ <div class="colorBox"></div>
+ </td>
+ <td>
+ <div>[[item.device]]</div>
+ </td>
+ </tr>
+ </template>
+ </table>
+ </div>
+ <br/>
+ gray: unknown device
+ </div>
+ </template>
+ </div>
+ <div class="legend-holder">
+ <table>
+ <tr>
+ <td><div class="title">Graph</div></td>
+ <td>(* = expandable)</td>
+ </tr>
+ <tr>
+ <td>
+ <svg class="icon">
+ <rect transform="translate(3, 1)" height="14" width="35"
+ rx="5" ry="5"/>
+ </svg>
+ </td>
+ <td>Namespace<span class="gray">*</span></td>
+ </tr>
+ <tr>
+ <td>
+ <svg class="icon" preserveAspectRatio="xMinYMid meet"
+ viewBox="0 0 10 10">
+ <use xlink:href="#op-node-stamp" fill="white" stroke="#ccc" x="9.5"
+ y="6" />
+ </svg>
+ </td>
+ <td>OpNode</td>
+ </tr>
+ <tr>
+ <td>
+ <svg class="icon" height="15px" preserveAspectRatio="xMinYMid meet"
+ viewBox="0 0 12 12">
+ <use xlink:href="#op-series-horizontal-stamp" fill="white"
+ stroke="#ccc" x="2" y="2"/>
+ </svg>
+ </td>
+ <td>Unconnected series<span class="gray">*</span></td>
+ </tr>
+ <tr>
+ <td>
+ <svg class="icon" height="15px"
+ preserveAspectRatio="xMinYMid meet" viewBox="0 0 15 15">
+ <use xlink:href="#op-series-vertical-stamp"
+ fill="white" stroke="#ccc" x="2" y="2"/>
+ </svg>
+ </td>
+ <td>Connected series<span class="gray">*</span></td>
+ </tr>
+ <tr>
+ <td>
+ <svg class="icon">
+ <circle fill="white" stroke="#848484" cx="10" cy="10" r="5"/>
+ </svg>
+ </td>
+ <td>Constant</td>
+ </tr>
+ <tr>
+ <td>
+ <svg class="image-icon">
+ <image id="summary-icon" width="24" height="24" x="0" y="0"
+ class="image-icon"/>
+ </svg>
+ </td>
+ <td>Summary</td>
+ </tr>
+ <tr>
+ <td>
+ <svg class="icon" height="15px"
+ preserveAspectRatio="xMinYMid meet" viewBox="0 0 15 15">
+ <defs>
+ <marker id="arrowhead-legend" fill="#bbb" markerWidth="10"
+ markerHeight="10" refX="9" refY="5" orient="auto">
+ <path d="M 0,0 L 10,5 L 0,10 C 3,7 3,3 0,0"/>
+ </marker>
+ <marker id="ref-arrowhead-legend" fill="#bbb" markerWidth="10"
+ markerHeight="10" refX="1" refY="5" orient="auto">
+ <path d="M 10,0 L 0,5 L 10,10 C 7,7 7,3 10,0"/>
+ </marker>
+ </defs>
+ <path marker-end="url(#arrowhead-legend)" stroke="#bbb"
+ d="M2 9 l 23 0" stroke-linecap="round" />
+ </svg>
+ </td>
+ <td>Dataflow edge</td>
+ </tr>
+ <tr>
+ <td>
+ <svg class="icon" height="15px"
+ preserveAspectRatio="xMinYMid meet" viewBox="0 0 15 15">
+ <path marker-end="url(#arrowhead-legend)" stroke="#bbb"
+ d="M2 9 l 23 0" stroke-linecap="round" stroke-dasharray="2, 2" />
+ </svg>
+ </td>
+ <td>Control dependency edge</td>
+ </tr>
+ <tr>
+ <td>
+ <svg class="icon" height="15px"
+ preserveAspectRatio="xMinYMid meet" viewBox="0 0 15 15">
+ <path marker-start="url(#ref-arrowhead-legend)"
+ marker-end="url(#arrowhead-legend)" stroke="#bbb" d="M2 9 l 23 0"
+ stroke-linecap="round" />
+ </svg>
+ </td>
+ <td>Reference edge</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</template>
+<script>
+(function() { // Private scope.
+Polymer({
+ is: 'tf-graph-controls',
+ ready: function() {
+ // Set the url to download the summary icon.
+ d3.select(this.$['summary-icon'])
+ .attr('xlink:href', this.resolveUrl('../../lib/svg/summary-icon.svg'));
+ },
+ properties: {
+ // Public API.
+ hasStats: {
+ type: Boolean
+ },
+ colorBy: {
+ type: String,
+ notify: true,
+ computed: '_getColorBy(_colorByIndex)'
+ },
+ colorByParams: Object,
+ datasets: {
+ type: Array,
+ observer: '_datasetsChanged'
+ },
+ selectedDataset: {
+ type: Number,
+ notify: true,
+ value: 0,
+ },
+ selectedFile: {
+ type: Object,
+ notify: true
+ },
+ // Private API.
+ _colorByIndex: {
+ type: Number,
+ value: 0 // Defaults to 'structure'.
+ },
+ _currentGradientParams: {
+ type: Object,
+ computed: '_getCurrentGradientParams(colorByParams, colorBy)'
+ }
+ },
+ _getColorBy: function(colorByIndex) {
+ return ["structure", "device", "compute_time", "memory"][colorByIndex];
+ },
+ _getBackgroundColor: function(color) {
+ return 'background-color:' + color;
+ },
+ fit: function() {
+ document.querySelector('#scene').fit();
+ },
+ _isGradientColoring: function(colorBy) {
+ return ["compute_time", "memory"].indexOf(colorBy) !== -1;
+ },
+ _equals: function(a, b) {
+ return a === b;
+ },
+ _getCurrentGradientParams: function(colorByParams, colorBy) {
+ if (!this._isGradientColoring(colorBy)) {
+ return;
+ }
+ var params = colorByParams[colorBy];
+ var minValue = params.minValue;
+ var maxValue = params.maxValue;
+ if (colorBy === 'memory') {
+ minValue = convertToHumanReadable(minValue, MEMORY_UNITS);
+ maxValue = convertToHumanReadable(maxValue, MEMORY_UNITS);
+ } else if (colorBy === 'compute_time') {
+ minValue = convertToHumanReadable(minValue, TIME_UNITS);
+ maxValue = convertToHumanReadable(maxValue, TIME_UNITS);
+ }
+ return {
+ minValue: minValue,
+ maxValue: maxValue,
+ startColor: params.startColor,
+ endColor: params.endColor
+ };
+ },
+ _updateFileInput: function(e) {
+ this.set('selectedFile', e);
+ },
+ _datasetsChanged: function(newDatasets, oldDatasets) {
+ if (oldDatasets != null || this.selected == null) {
+ // Select the first dataset by default.
+ this.set('selectedDataset', 0);
+ }
+ },
+ _getFile: function() {
+ this.$.file.click();
+ }
+});
+
+// Private methods.
+var MEMORY_UNITS = [
+ // Atomic unit.
+ {symbol: 'B'},
+ // numUnits specifies how many previous units this unit contains.
+ {symbol: 'KB', numUnits: 1024},
+ {symbol: 'MB', numUnits: 1024},
+ {symbol: 'GB', numUnits: 1024},
+ {symbol: 'TB', numUnits: 1024},
+ {symbol: 'PB', numUnits: 1024}
+];
+var TIME_UNITS = [
+ // Atomic unit. Finest granularity in TensorFlow stat collection.
+ {symbol: 'µs'},
+ // numUnits specifies how many previous units this unit contains.
+ {symbol: 'ms', numUnits: 1000},
+ {symbol: 's', numUnits: 1000},
+ {symbol: 'min', numUnits: 60},
+ {symbol: 'hr', numUnits: 60},
+ {symbol: 'days', numUnits: 24}
+];
+
+/**
+ * Returns the human readable version of the unit.
+ * (e.g. 1.35 GB, 23 MB, 34 ms, 6.53 min etc).
+ */
+function convertToHumanReadable(value, units, unitIndex) {
+ unitIndex = unitIndex == null ? 0 : unitIndex;
+ if (unitIndex + 1 < units.length && value >= units[unitIndex + 1].numUnits) {
+ return convertToHumanReadable(value / units[unitIndex + 1].numUnits,
+ units, unitIndex + 1);
+ }
+ // toPrecision() has the tendency to return a number in scientific
+ // notation and (number - 0) brings it back to normal notation.
+ return (value.toPrecision(3) - 0) + ' ' + units[unitIndex].symbol;
+}
+})(); // Closing private scope.
+</script>
+</dom-module>