Add arrowheads to dataflow edges.

Make reference edges orange.
Remove animations from tooltips in the graph documentation.

Previously, arrowheads were only added to reference edges (because we assumed users knew about the convention that arrowless edges flow upwards). That decision nicely reduces clutter. However, recently, some internal and external folks have expressed confusion, and so I want to try adding arrowheads to all data flow edges. And make the reference edges starkly different.

See #10428

PiperOrigin-RevId: 158195388
This commit is contained in:
A. Unique TensorFlower 2017-06-06 14:59:27 -07:00 committed by TensorFlower Gardener
parent b495155396
commit 65ce8c723d
4 changed files with 101 additions and 50 deletions

View File

@ -276,6 +276,12 @@ limitations under the License.
display: none;
}
/* Reference Edge */
::content .edge > path.edgeline.referenceedge {
stroke: #FFB74D;
opacity: 1;
}
/* --- Series Nodes --- */
/* Hide the rect for a series' annotation. */
@ -436,10 +442,14 @@ limitations under the License.
fill: #666;
}
::content .ref-arrowhead {
::content .dataflow-arrowhead {
fill: #bbb;
}
::content .reference-arrowhead {
fill: #FFB74D;
}
::content .edge .control-dep {
stroke-dasharray: 2, 2;
}
@ -516,23 +526,42 @@ limitations under the License.
<svg id="svg">
<defs>
<!-- Arrow heads for edge paths of different predefined sizes. -->
<path id="ref-arrowhead-path" d="M 10,0 L 0,5 L 10,10 C 7,7 7,3 10,0"/>
<marker class="ref-arrowhead" id="ref-arrowhead-small" viewBox="0 0 10 10" markerWidth="10" markerHeight="10"
refX="8" refY="5" orient="auto" markerUnits="userSpaceOnUse">
<use xlink:href="#ref-arrowhead-path" />
<!-- Arrow heads for reference edge paths of different predefined sizes per color. -->
<path id="reference-arrowhead-path" d="M 0,0 L 10,5 L 0,10 C 3,7 3,3 0,0"/>
<marker class="reference-arrowhead" id="reference-arrowhead-small" viewBox="0 0 10 10" markerWidth="5" markerHeight="5"
refX="2" refY="5" orient="auto-start-reverse" markerUnits="userSpaceOnUse">
<use xlink:href="#reference-arrowhead-path" />
</marker>
<marker class="ref-arrowhead" id="ref-arrowhead-medium" viewBox="0 0 10 10" markerWidth="13" markerHeight="13"
refX="8" refY="5" orient="auto" markerUnits="userSpaceOnUse">
<use xlink:href="#ref-arrowhead-path" />
<marker class="reference-arrowhead" id="reference-arrowhead-medium" viewBox="0 0 10 10" markerWidth="13" markerHeight="13"
refX="2" refY="5" orient="auto-start-reverse" markerUnits="userSpaceOnUse">
<use xlink:href="#reference-arrowhead-path" />
</marker>
<marker class="ref-arrowhead" id="ref-arrowhead-large" viewBox="0 0 10 10" markerWidth="16" markerHeight="16"
refX="8" refY="5" orient="auto" markerUnits="userSpaceOnUse">
<use xlink:href="#ref-arrowhead-path" />
<marker class="reference-arrowhead" id="reference-arrowhead-large" viewBox="0 0 10 10" markerWidth="16" markerHeight="16"
refX="2" refY="5" orient="auto-start-reverse" markerUnits="userSpaceOnUse">
<use xlink:href="#reference-arrowhead-path" />
</marker>
<marker class="ref-arrowhead" id="ref-arrowhead-xlarge" viewBox="0 0 10 10" markerWidth="20" markerHeight="20"
refX="8" refY="5" orient="auto" markerUnits="userSpaceOnUse">
<use xlink:href="#ref-arrowhead-path" />
<marker class="reference-arrowhead" id="reference-arrowhead-xlarge" viewBox="0 0 10 10" markerWidth="20" markerHeight="20"
refX="2" refY="5" orient="auto-start-reverse" markerUnits="userSpaceOnUse">
<use xlink:href="#reference-arrowhead-path" />
</marker>
<!-- Arrow heads for dataflow edge paths of different predefined sizes per color. -->
<path id="dataflow-arrowhead-path" d="M 0,0 L 10,5 L 0,10 C 3,7 3,3 0,0"/>
<marker class="dataflow-arrowhead" id="dataflow-arrowhead-small" viewBox="0 0 10 10" markerWidth="5" markerHeight="5"
refX="2" refY="5" orient="auto-start-reverse" markerUnits="userSpaceOnUse">
<use xlink:href="#dataflow-arrowhead-path" />
</marker>
<marker class="dataflow-arrowhead" id="dataflow-arrowhead-medium" viewBox="0 0 10 10" markerWidth="13" markerHeight="13"
refX="2" refY="5" orient="auto-start-reverse" markerUnits="userSpaceOnUse">
<use xlink:href="#dataflow-arrowhead-path" />
</marker>
<marker class="dataflow-arrowhead" id="dataflow-arrowhead-large" viewBox="0 0 10 10" markerWidth="16" markerHeight="16"
refX="2" refY="5" orient="auto-start-reverse" markerUnits="userSpaceOnUse">
<use xlink:href="#dataflow-arrowhead-path" />
</marker>
<marker class="dataflow-arrowhead" id="dataflow-arrowhead-xlarge" viewBox="0 0 10 10" markerWidth="20" markerHeight="20"
refX="2" refY="5" orient="auto-start-reverse" markerUnits="userSpaceOnUse">
<use xlink:href="#dataflow-arrowhead-path" />
</marker>
<!-- Arrow head for annotation edge paths. -->

View File

@ -176,23 +176,28 @@ function adjustPathPointsForMarker(points: render.Point[],
let refX = +marker.attr('refX');
let pathNode = <SVGPathElement> path.node();
if (isStart) {
let fractionStickingOut = refX / viewBoxWidth;
let length = markerWidth * fractionStickingOut;
let point = pathNode.getPointAtLength(length);
// The edge flows downwards. Do not make the edge go the whole way, lest we
// clobber the arrowhead.
const fractionStickingOut = 1 - refX / viewBoxWidth;
const length = markerWidth * fractionStickingOut;
const point = pathNode.getPointAtLength(length);
// Figure out how many segments of the path we need to remove in order
// to shorten the path.
let segIndex = pathNode.getPathSegAtLength(length);
const segIndex = pathNode.getPathSegAtLength(length);
// Update the very first segment.
points[segIndex - 1] = {x: point.x, y: point.y};
// Ignore every point before segIndex - 1.
return points.slice(segIndex - 1);
} else {
let fractionStickingOut = 1 - refX / viewBoxWidth;
let length = pathNode.getTotalLength() - markerWidth * fractionStickingOut;
let point = pathNode.getPointAtLength(length);
// The edge flows upwards. Do not make the edge go the whole way, lest we
// clobber the arrowhead.
const fractionStickingOut = 1 - refX / viewBoxWidth;
const length =
pathNode.getTotalLength() - markerWidth * fractionStickingOut;
const point = pathNode.getPointAtLength(length);
// Figure out how many segments of the path we need to remove in order
// to shorten the path.
let segIndex = pathNode.getPathSegAtLength(length);
const segIndex = pathNode.getPathSegAtLength(length);
// Update the very last segment.
points[segIndex] = {x: point.x, y: point.y};
// Ignore every point after segIndex.
@ -221,6 +226,9 @@ export function appendEdge(edgeGroup, d: EdgeData,
if (d.label && d.label.structural) {
edgeClass += ' ' + Class.Edge.STRUCTURAL;
}
if (d.label && d.label.metaedge && d.label.metaedge.numRefEdges) {
edgeClass += ' ' + Class.Edge.REFERENCE_EDGE;
}
// Give the path a unique id, which will be used to link
// the textPath (edge label) to this path.
let pathId = 'path_' + getEdgeKey(d);
@ -232,10 +240,18 @@ export function appendEdge(edgeGroup, d: EdgeData,
.style('stroke-width', strokeWidth + 'px');
// Check if there is a reference edge and add an arrowhead of the right size.
if (d.label && d.label.metaedge && d.label.metaedge.numRefEdges) {
let markerId = `ref-arrowhead-${arrowheadMap(strokeWidth)}`;
path.style('marker-start', `url(#${markerId})`);
d.label.startMarkerId = markerId;
if (d.label && d.label.metaedge) {
if (d.label.metaedge.numRefEdges) {
// We have a reference edge.
const markerId = `reference-arrowhead-${arrowheadMap(strokeWidth)}`;
path.style('marker-start', `url(#${markerId})`);
d.label.startMarkerId = markerId;
} else {
// We have a dataflow edge.
const markerId = `dataflow-arrowhead-${arrowheadMap(strokeWidth)}`;
path.style('marker-end', `url(#${markerId})`);
d.label.endMarkerId = markerId;
}
}
if (d.label == null || d.label.metaedge == null) {

View File

@ -42,6 +42,7 @@ module tf.graph.scene {
CONTAINER: 'edges',
GROUP: 'edge',
LINE: 'edgeline',
REFERENCE_EDGE: 'referenceedge',
REF_LINE: 'refline',
STRUCTURAL: 'structural'
},

View File

@ -345,7 +345,7 @@ table.tf-graph-controls td.input-element-table-data {
disabled="[[!_xlaClustersProvided(renderHierarchy)]]">
XLA Cluster
</paper-radio-button>
<paper-tooltip for="xla-cluster-radio-button" position="right">
<paper-tooltip animation-delay="0" for="xla-cluster-radio-button" position="right">
Coloring by XLA cluster is only enabled if at least 1 op specifies an XLA cluster.
</paper-tooltip>
@ -354,7 +354,7 @@ table.tf-graph-controls td.input-element-table-data {
disabled="[[!stats]]">
Compute time
</paper-radio-button>
<paper-tooltip for="compute-time-radio-button" position="right">
<paper-tooltip animation-delay="0" for="compute-time-radio-button" position="right">
Coloring by compute time is only enabled if the RunMetadata proto is passed to the
FileWriter when a specific session is run.
</paper-tooltip>
@ -364,7 +364,7 @@ table.tf-graph-controls td.input-element-table-data {
disabled="[[!stats]]">
Memory
</paper-radio-button>
<paper-tooltip for="memory-radio-button" position="right">
<paper-tooltip animation-delay="0" for="memory-radio-button" position="right">
Coloring by memory is only enabled if the RunMetadata proto is passed to the
FileWriter when a specific session is run.
</paper-tooltip>
@ -512,7 +512,7 @@ table.tf-graph-controls td.input-element-table-data {
Namespace<span class="gray">*</span>
<div class="legend-clarifier">
<span>?</span>
<paper-tooltip position="right">
<paper-tooltip animation-delay="0" position="right">
Encapsulates a set of nodes. Namespace is hierarchical and based on scope.
</paper-tooltip>
</div>
@ -530,7 +530,7 @@ table.tf-graph-controls td.input-element-table-data {
OpNode
<div class="legend-clarifier">
<span>?</span>
<paper-tooltip position="right">
<paper-tooltip animation-delay="0" position="right">
Node that performs an operation. These nodes cannot expand.
</paper-tooltip>
</div>
@ -548,7 +548,7 @@ table.tf-graph-controls td.input-element-table-data {
Unconnected series<span class="gray">*</span>
<div class="legend-clarifier">
<span>?</span>
<paper-tooltip position="right">
<paper-tooltip animation-delay="0" position="right">
Sequence of numbered nodes that are not connected to each other.
</paper-tooltip>
</div>
@ -566,7 +566,7 @@ table.tf-graph-controls td.input-element-table-data {
Connected series<span class="gray">*</span>
<div class="legend-clarifier">
<span>?</span>
<paper-tooltip position="right">
<paper-tooltip animation-delay="0" position="right">
Sequence of numbered nodes that are connected to each other.
</paper-tooltip>
</div>
@ -582,7 +582,7 @@ table.tf-graph-controls td.input-element-table-data {
Constant
<div class="legend-clarifier">
<span>?</span>
<paper-tooltip position="right">
<paper-tooltip animation-delay="0" position="right">
Node that outputs a constant value.
</paper-tooltip>
</div>
@ -598,7 +598,7 @@ table.tf-graph-controls td.input-element-table-data {
Summary
<div class="legend-clarifier">
<span>?</span>
<paper-tooltip position="right">
<paper-tooltip animation-delay="0" position="right">
Node that collects data for visualization within TensorBoard.
</paper-tooltip>
</div>
@ -609,20 +609,21 @@ table.tf-graph-controls td.input-element-table-data {
<svg class="icon" height="15px"
preserveAspectRatio="xMinYMid meet" viewBox="0 0 15 15">
<defs>
<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 id="dataflow-arrowhead-legend" fill="#bbb" markerWidth="10"
markerHeight="10" refX="9" refY="5" orient="auto-start-reverse">
<path d="M 0,0 L 10,5 L 0,10 C 3,7 3,3 0,0"/>
</marker>
</defs>
<path stroke="#bbb"
d="M2 9 l 23 0" stroke-linecap="round" />
<path marker-end="url(#dataflow-arrowhead-legend)"
stroke="#bbb" d="M2 9 l 29 0"
stroke-linecap="round" />
</svg>
</td>
<td>
Dataflow edge
<div class="legend-clarifier">
<span>?</span>
<paper-tooltip position="right">
<paper-tooltip animation-delay="0" position="right">
Edge showing the data flow between operations. Edges flow upwards unless arrowheads specify otherwise.
</paper-tooltip>
</div>
@ -633,14 +634,14 @@ table.tf-graph-controls td.input-element-table-data {
<svg class="icon" height="15px"
preserveAspectRatio="xMinYMid meet" viewBox="0 0 15 15">
<path stroke="#bbb"
d="M2 9 l 23 0" stroke-linecap="round" stroke-dasharray="2, 2" />
d="M2 9 l 29 0" stroke-linecap="round" stroke-dasharray="2, 2" />
</svg>
</td>
<td>
Control dependency edge
<div class="legend-clarifier">
<span>?</span>
<paper-tooltip position="right">
<paper-tooltip animation-delay="0" position="right">
Edge showing the control dependency between operations.
</paper-tooltip>
</div>
@ -650,18 +651,22 @@ table.tf-graph-controls td.input-element-table-data {
<td>
<svg class="icon" height="15px"
preserveAspectRatio="xMinYMid meet" viewBox="0 0 15 15">
<path
marker-start="url(#ref-arrowhead-legend)"
marker-end="url(#ref-arrowhead-legend)"
stroke="#bbb" d="M2 9 l 23 0"
stroke-linecap="round" />
<defs>
<marker id="reference-arrowhead-legend" fill="#FFB74D" markerWidth="10"
markerHeight="10" refX="9" refY="5" orient="auto-start-reverse">
<path d="M 0,0 L 10,5 L 0,10 C 3,7 3,3 0,0"/>
</marker>
</defs>
<path marker-end="url(#reference-arrowhead-legend)"
stroke="#FFB74D" d="M2 9 l 29 0"
stroke-linecap="round" />
</svg>
</td>
<td>
Reference edge
<div class="legend-clarifier">
<span>?</span>
<paper-tooltip position="right">
<paper-tooltip animation-delay="0" position="right">
Edge showing that the outgoing operation node can mutate the incoming tensor.
</paper-tooltip>
</div>