提交 aa62fad6 authored 作者: Christof Angermueller's avatar Christof Angermueller

Add node profiling colors

上级 726cce89
差异被折叠。
This source diff could not be displayed because it is too large. You can view the blob instead.
digraph G {
graph [bb="0,0,923,584"];
node [label="\N"];
"Shape_i{1}" [fillcolor=cyan,
height=0.5,
pos="763,478",
profile="[9.5367431640625e-07, None, 0.5673758865248227]",
shape=ellipse,
style=filled,
type=colored,
width=1.4763];
MakeVector [height=0.5,
pos="602,390",
profile="[1.9073486328125e-06, None, 1.1347517730496455]",
shape=ellipse,
width=1.5402];
"Shape_i{1}" -> MakeVector [label="1 TensorType(int64, scalar)",
lp="775,434",
pos="e,629.45,405.66 735.69,462.41 708.97,448.14 668.11,426.32 638.6,410.55"];
"TensorType(float64, matrix)" [fillcolor=limegreen,
height=0.5,
pos="640,566",
profile="[9.989738464355469e-05, None, 59.43262411347518]",
shape=box,
style=filled,
width=2.4444];
"TensorType(float64, matrix)" -> "Shape_i{1}" [label="TensorType(float64, matrix)",
lp="843,522",
pos="e,764.26,496.07 728.22,549.11 737.93,544.3 746.87,538.07 754,530 759.76,523.49 762.45,514.62 763.57,506.1"];
Dot22 [height=0.5,
pos="242,478",
profile="[9.989738464355469e-05, None, 59.43262411347518]",
shape=ellipse,
width=0.92774];
"TensorType(float64, matrix)" -> Dot22 [label="1 TensorType(float64, matrix)",
lp="665,522",
pos="e,273.58,484.55 610.32,547.87 600.62,542.23 589.83,535.89 580,530 568.36,523.03 566.88,518.27 554,514 467.6,485.38 440.34,507.08 \
350,496 328.02,493.3 303.64,489.53 283.62,486.23"];
"Shape_i{0}" [fillcolor=cyan,
height=0.5,
pos="412,478",
profile="[0.0, None, 0.0]",
shape=ellipse,
style=filled,
type=colored,
width=1.4763];
"Shape_i{0}" -> MakeVector [label="0 TensorType(int64, scalar)",
lp="587,434",
pos="e,565.36,403.6 437.91,462.25 457.2,451.55 484.35,437.07 509,426 523.98,419.28 540.67,412.72 555.73,407.13"];
"name=X TensorType(float64, matrix)" [fillcolor=limegreen,
height=0.5,
pos="342,566",
profile="[9.989738464355469e-05, None, 59.43262411347518]",
shape=box,
style=filled,
width=3.1667];
"name=X TensorType(float64, matrix)" -> "Shape_i{0}" [label="TensorType(float64, matrix)",
lp="470,522",
pos="e,402.12,495.7 361.08,547.9 366.78,542.42 372.87,536.17 378,530 384.67,521.98 391.21,512.63 396.75,504.15"];
"name=X TensorType(float64, matrix)" -> Dot22 [label="0 TensorType(float64, matrix)",
lp="289,522",
pos="e,221.22,492.32 240.1,547.93 223.33,543.11 209.58,537.17 204,530 196.09,519.83 203.28,508.34 213.46,498.84"];
"Elemwise{ScalarSigmoid}[(0, 0)]" [fillcolor="#FFAABB",
height=0.5,
pos="242,390",
profile="[1.0967254638671875e-05, None, 6.524822695035461]",
shape=ellipse,
style=filled,
type=colored,
width=3.7297];
Dot22 -> "Elemwise{ScalarSigmoid}[(0, 0)]" [color=red,
label="TensorType(float64, matrix)",
lp="322,434",
pos="e,242,408.08 242,459.6 242,447.75 242,431.82 242,418.29"];
"Elemwise{Cast{float64}}" [fillcolor="#FFAABB",
height=0.5,
pos="602,302",
profile="[2.86102294921875e-06, None, 1.702127659574468]",
shape=ellipse,
style=filled,
type=colored,
width=2.9207];
MakeVector -> "Elemwise{Cast{float64}}" [label="TensorType(int64, vector)",
lp="676,346",
pos="e,602,320.08 602,371.6 602,359.75 602,343.82 602,330.29"];
"TensorType(float64, matrix) id=6" [fillcolor=dodgerblue,
height=0.5,
pos="254,302",
profile="[1.0967254638671875e-05, None, 6.524822695035461]",
shape=box,
style=filled,
width=2.8403];
"Elemwise{ScalarSigmoid}[(0, 0)]" -> "TensorType(float64, matrix) id=6" [label="TensorType(float64, matrix)",
lp="330,346",
pos="e,251.62,320.08 244.43,371.6 246.08,359.75 248.3,343.82 250.19,330.29"];
"Sum{acc_dtype=float64}" [height=0.5,
pos="103,248",
profile="[1.9073486328125e-06, None, 1.1347517730496455]",
shape=ellipse,
width=2.8658];
"Elemwise{ScalarSigmoid}[(0, 0)]" -> "Sum{acc_dtype=float64}" [label="TensorType(float64, matrix)",
lp="163,346",
pos="e,92.15,266.28 144.12,377.63 116.5,372.3 91.588,364.68 83,354 65.118,331.75 75.943,298.34 87.435,275.2"];
"Subtensor{int64}" [fillcolor="#FFAAFF",
height=0.5,
pos="670,194",
profile="[0.0, None, 0.0]",
shape=ellipse,
style=filled,
type=colored,
width=2.0659];
"Elemwise{Cast{float64}}" -> "Subtensor{int64}" [color=dodgerblue,
label="0 TensorType(float64, vector)",
lp="748.5,248",
pos="e,667.73,212.08 629.37,284.55 636.24,279.34 643.05,273.07 648,266 657.08,253.02 662.51,236.17 665.7,222.14"];
"Subtensor{int64} id=8" [fillcolor="#FFAAFF",
height=0.5,
pos="462,194",
profile="[2.1457672119140625e-06, None, 1.2765957446808511]",
shape=ellipse,
style=filled,
type=colored,
width=2.5916];
"Elemwise{Cast{float64}}" -> "Subtensor{int64} id=8" [color=dodgerblue,
label="0 TensorType(float64, vector)",
lp="559.5,248",
pos="e,460.37,212.13 516.4,291.46 500.83,286.11 486.04,278.06 475,266 464.31,254.32 461,236.88 460.4,222.21"];
"Elemwise{Composite{((i0 / i1) / i2)}}[(0, 0)]" [fillcolor="#FFAABB",
height=0.5,
pos="462,106",
profile="[0.0, None, 0.0]",
shape=ellipse,
style=filled,
type=colored,
width=4.8998];
"Sum{acc_dtype=float64}" -> "Elemwise{Composite{((i0 / i1) / i2)}}[(0, 0)]" [color=red,
label="0 TensorType(float64, scalar)",
lp="275.5,194",
pos="e,366.69,121.17 119.53,230.18 136.35,214 163.86,190 192,176 243.47,150.38 305.34,133.68 356.86,123.14"];
"Subtensor{int64}" -> "Elemwise{Composite{((i0 / i1) / i2)}}[(0, 0)]" [label="2 TensorType(float64, scalar)",
lp="731.5,150",
pos="e,578.08,119.56 661.08,175.7 654.34,164.37 644.02,150.18 631,142 617.89,133.76 603.18,127.42 588.06,122.55"];
"val=1 int64" [fillcolor=limegreen,
height=0.5,
pos="862,302",
profile="[0.0, None, 0.0]",
shape=box,
style=filled,
width=1.1181];
"val=1 int64" -> "Subtensor{int64}" [label="1 int64",
lp="877,248",
pos="e,736.58,202.24 860.64,283.73 858.41,267.46 852.53,243.61 837,230 823.25,217.96 783.96,209.39 746.94,203.75"];
"Subtensor{int64} id=8" -> "Elemwise{Composite{((i0 / i1) / i2)}}[(0, 0)]" [label="1 TensorType(float64, scalar)",
lp="545.5,150",
pos="e,462,124.08 462,175.6 462,163.75 462,147.82 462,134.29"];
"val=0 int64" [fillcolor=limegreen,
height=0.5,
pos="415,302",
profile="[2.1457672119140625e-06, None, 1.2765957446808511]",
shape=box,
style=filled,
width=1.1181];
"val=0 int64" -> "Subtensor{int64} id=8" [label="1 int64",
lp="436,248",
pos="e,432.27,211.35 411.23,283.95 408.81,268.91 407.5,246.84 416,230 418.2,225.64 421.23,221.67 424.69,218.1"];
"TensorType(float64, scalar) id=13" [fillcolor=dodgerblue,
height=0.5,
pos="462,18",
profile="[0.0, None, 0.0]",
shape=box,
style=filled,
width=2.8889];
"Elemwise{Composite{((i0 / i1) / i2)}}[(0, 0)]" -> "TensorType(float64, scalar) id=13" [label="TensorType(float64, scalar)",
lp="540,62",
pos="e,462,36.084 462,87.597 462,75.746 462,59.817 462,46.292"];
}
digraph G {
graph [bb="0,0,923,584"];
node [label="\N"];
"Shape_i{1}" [fillcolor=cyan,
height=0.5,
pos="763,478",
shape=ellipse,
style=filled,
type=colored,
width=1.4763];
MakeVector [height=0.5,
pos="602,390",
shape=ellipse,
width=1.5402];
"Shape_i{1}" -> MakeVector [label="1 TensorType(int64, scalar)",
lp="775,434",
pos="e,629.45,405.66 735.69,462.41 708.97,448.14 668.11,426.32 638.6,410.55"];
"TensorType(float64, matrix)" [fillcolor=limegreen,
height=0.5,
pos="640,566",
shape=box,
style=filled,
width=2.4444];
"TensorType(float64, matrix)" -> "Shape_i{1}" [label="TensorType(float64, matrix)",
lp="843,522",
pos="e,764.26,496.07 728.22,549.11 737.93,544.3 746.87,538.07 754,530 759.76,523.49 762.45,514.62 763.57,506.1"];
Dot22 [height=0.5,
pos="242,478",
shape=ellipse,
width=0.92774];
"TensorType(float64, matrix)" -> Dot22 [label="1 TensorType(float64, matrix)",
lp="665,522",
pos="e,273.58,484.55 610.32,547.87 600.62,542.23 589.83,535.89 580,530 568.36,523.03 566.88,518.27 554,514 467.6,485.38 440.34,507.08 \
350,496 328.02,493.3 303.64,489.53 283.62,486.23"];
"Shape_i{0}" [fillcolor=cyan,
height=0.5,
pos="412,478",
shape=ellipse,
style=filled,
type=colored,
width=1.4763];
"Shape_i{0}" -> MakeVector [label="0 TensorType(int64, scalar)",
lp="587,434",
pos="e,565.36,403.6 437.91,462.25 457.2,451.55 484.35,437.07 509,426 523.98,419.28 540.67,412.72 555.73,407.13"];
"name=X TensorType(float64, matrix)" [fillcolor=limegreen,
height=0.5,
pos="342,566",
shape=box,
style=filled,
width=3.1667];
"name=X TensorType(float64, matrix)" -> "Shape_i{0}" [label="TensorType(float64, matrix)",
lp="470,522",
pos="e,402.12,495.7 361.08,547.9 366.78,542.42 372.87,536.17 378,530 384.67,521.98 391.21,512.63 396.75,504.15"];
"name=X TensorType(float64, matrix)" -> Dot22 [label="0 TensorType(float64, matrix)",
lp="289,522",
pos="e,221.22,492.32 240.1,547.93 223.33,543.11 209.58,537.17 204,530 196.09,519.83 203.28,508.34 213.46,498.84"];
"Elemwise{ScalarSigmoid}[(0, 0)]" [fillcolor="#FFAABB",
height=0.5,
pos="242,390",
shape=ellipse,
style=filled,
type=colored,
width=3.7297];
Dot22 -> "Elemwise{ScalarSigmoid}[(0, 0)]" [color=red,
label="TensorType(float64, matrix)",
lp="322,434",
pos="e,242,408.08 242,459.6 242,447.75 242,431.82 242,418.29"];
"Elemwise{Cast{float64}}" [fillcolor="#FFAABB",
height=0.5,
pos="602,302",
shape=ellipse,
style=filled,
type=colored,
width=2.9207];
MakeVector -> "Elemwise{Cast{float64}}" [label="TensorType(int64, vector)",
lp="676,346",
pos="e,602,320.08 602,371.6 602,359.75 602,343.82 602,330.29"];
"TensorType(float64, matrix) id=6" [fillcolor=dodgerblue,
height=0.5,
pos="254,302",
shape=box,
style=filled,
width=2.8403];
"Elemwise{ScalarSigmoid}[(0, 0)]" -> "TensorType(float64, matrix) id=6" [label="TensorType(float64, matrix)",
lp="330,346",
pos="e,251.62,320.08 244.43,371.6 246.08,359.75 248.3,343.82 250.19,330.29"];
"Sum{acc_dtype=float64}" [height=0.5,
pos="103,248",
shape=ellipse,
width=2.8658];
"Elemwise{ScalarSigmoid}[(0, 0)]" -> "Sum{acc_dtype=float64}" [label="TensorType(float64, matrix)",
lp="163,346",
pos="e,92.15,266.28 144.12,377.63 116.5,372.3 91.588,364.68 83,354 65.118,331.75 75.943,298.34 87.435,275.2"];
"Subtensor{int64}" [fillcolor="#FFAAFF",
height=0.5,
pos="670,194",
shape=ellipse,
style=filled,
type=colored,
width=2.0659];
"Elemwise{Cast{float64}}" -> "Subtensor{int64}" [color=dodgerblue,
label="0 TensorType(float64, vector)",
lp="748.5,248",
pos="e,667.73,212.08 629.37,284.55 636.24,279.34 643.05,273.07 648,266 657.08,253.02 662.51,236.17 665.7,222.14"];
"Subtensor{int64} id=8" [fillcolor="#FFAAFF",
height=0.5,
pos="462,194",
shape=ellipse,
style=filled,
type=colored,
width=2.5916];
"Elemwise{Cast{float64}}" -> "Subtensor{int64} id=8" [color=dodgerblue,
label="0 TensorType(float64, vector)",
lp="559.5,248",
pos="e,460.37,212.13 516.4,291.46 500.83,286.11 486.04,278.06 475,266 464.31,254.32 461,236.88 460.4,222.21"];
"Elemwise{Composite{((i0 / i1) / i2)}}[(0, 0)]" [fillcolor="#FFAABB",
height=0.5,
pos="462,106",
shape=ellipse,
style=filled,
type=colored,
width=4.8998];
"Sum{acc_dtype=float64}" -> "Elemwise{Composite{((i0 / i1) / i2)}}[(0, 0)]" [color=red,
label="0 TensorType(float64, scalar)",
lp="275.5,194",
pos="e,366.69,121.17 119.53,230.18 136.35,214 163.86,190 192,176 243.47,150.38 305.34,133.68 356.86,123.14"];
"Subtensor{int64}" -> "Elemwise{Composite{((i0 / i1) / i2)}}[(0, 0)]" [label="2 TensorType(float64, scalar)",
lp="731.5,150",
pos="e,578.08,119.56 661.08,175.7 654.34,164.37 644.02,150.18 631,142 617.89,133.76 603.18,127.42 588.06,122.55"];
"val=1 int64" [fillcolor=limegreen,
height=0.5,
pos="862,302",
shape=box,
style=filled,
width=1.1181];
"val=1 int64" -> "Subtensor{int64}" [label="1 int64",
lp="877,248",
pos="e,736.58,202.24 860.64,283.73 858.41,267.46 852.53,243.61 837,230 823.25,217.96 783.96,209.39 746.94,203.75"];
"Subtensor{int64} id=8" -> "Elemwise{Composite{((i0 / i1) / i2)}}[(0, 0)]" [label="1 TensorType(float64, scalar)",
lp="545.5,150",
pos="e,462,124.08 462,175.6 462,163.75 462,147.82 462,134.29"];
"val=0 int64" [fillcolor=limegreen,
height=0.5,
pos="415,302",
shape=box,
style=filled,
width=1.1181];
"val=0 int64" -> "Subtensor{int64} id=8" [label="1 int64",
lp="436,248",
pos="e,432.27,211.35 411.23,283.95 408.81,268.91 407.5,246.84 416,230 418.2,225.64 421.23,221.67 424.69,218.1"];
"TensorType(float64, scalar) id=13" [fillcolor=dodgerblue,
height=0.5,
pos="462,18",
shape=box,
style=filled,
width=2.8889];
"Elemwise{Composite{((i0 / i1) / i2)}}[(0, 0)]" -> "TensorType(float64, scalar) id=13" [label="TensorType(float64, scalar)",
lp="540,62",
pos="e,462,36.084 462,87.597 462,75.746 462,59.817 462,46.292"];
}
......@@ -157,7 +157,7 @@ class GraphFormatter(object):
apply_shape = 'ellipse'
var_shape = 'box'
for node_idx, node in enumerate(topo):
astr = self.apply_name(node, fct, topo, mode, profile)
astr, aprof = self.apply_name(node, fct, topo, mode, profile)
use_color = None
for opName, color in self.colorCodes.items():
......@@ -165,12 +165,12 @@ class GraphFormatter(object):
use_color = color
if use_color is None:
nw_node = pd.Node(astr, shape=apply_shape)
nw_node = pd.Node(astr, shape=apply_shape, profile=aprof)
elif self.high_contrast:
nw_node = pd.Node(astr, style='filled', fillcolor=use_color,
shape=apply_shape, type='colored')
shape=apply_shape, type='colored', profile=aprof)
else:
nw_node = pd.Node(astr, color=use_color, shape=apply_shape)
nw_node = pd.Node(astr, color=use_color, shape=apply_shape, profile=aprof)
g.add_node(nw_node)
if self.cond_highlight:
if node in middle:
......@@ -180,6 +180,10 @@ class GraphFormatter(object):
elif node in right:
c2.add_node(nw_node)
def make_node(*args, **kwargs):
t = {k:v for k,v in kwargs.items() if v is not None}
return pd.Node(*args, **t)
for id, var in enumerate(node.inputs):
varstr = self.var_name(var)
label = str(var.type)
......@@ -196,19 +200,19 @@ class GraphFormatter(object):
param['color'] = 'red'
if var.owner is None:
if self.high_contrast:
g.add_node(pd.Node(varstr,
g.add_node(make_node(varstr,
style='filled',
fillcolor=self.node_colors['input'],
shape=var_shape))
shape=var_shape, profile=aprof))
else:
g.add_node(pd.Node(varstr, color=self.node_colors['input'],
shape=var_shape))
g.add_node(make_node(varstr, color=self.node_colors['input'],
shape=var_shape, profile=aprof))
g.add_edge(pd.Edge(varstr, astr, label=label, **param))
elif var.name or not self.compact:
g.add_edge(pd.Edge(varstr, astr, label=label, **param))
else:
# no name, so we don't make a var ellipse
name = self.apply_name(var.owner, fct, topo, mode, profile)
name, prof = self.apply_name(var.owner, fct, topo, mode, profile)
g.add_edge(pd.Edge(name, astr,
label=label, **param))
......@@ -223,21 +227,21 @@ class GraphFormatter(object):
if out:
g.add_edge(pd.Edge(astr, varstr, label=label))
if self.high_contrast:
g.add_node(pd.Node(varstr, style='filled',
g.add_node(make_node(varstr, style='filled',
fillcolor=self.node_colors['output'],
shape=var_shape))
shape=var_shape, profile=aprof))
else:
g.add_node(pd.Node(varstr, color=self.node_colors['output'],
shape=var_shape))
g.add_node(make_node(varstr, color=self.node_colors['output'],
shape=var_shape, profile=aprof))
elif len(var.clients) == 0:
g.add_edge(pd.Edge(astr, varstr, label=label))
if self.high_contrast:
g.add_node(pd.Node(varstr, style='filled',
g.add_node(make_node(varstr, style='filled',
fillcolor=self.node_colors['unused'],
shape=var_shape))
shape=var_shape, profile=aprof))
else:
g.add_node(pd.Node(varstr, color=self.node_colors['unused'],
shape=var_shape))
g.add_node(make_node(varstr, color=self.node_colors['unused'],
shape=var_shape, profile=aprof))
elif var.name or not self.compact:
g.add_edge(pd.Edge(astr, varstr, label=label))
......@@ -296,12 +300,11 @@ class GraphFormatter(object):
return varstr
def apply_name(self, node, fct, topo, mode=None, profile=None):
if node in self.apply_name_cache:
return self.apply_name_cache[node]
prof_str = ''
prof = None
if mode:
time = mode.profile_stats[fct].apply_time.get(node, 0)
# second, % total time in profiler, %fct time in profiler
......@@ -313,7 +316,7 @@ class GraphFormatter(object):
pf = 0
else:
pf = time * 100 / mode.profile_stats[fct].fct_call_time
prof_str = ' (%.3fs,%.3f%%,%.3f%%)' % (time, pt, pf)
prof = [time, pt, pf]
elif profile:
time = profile.apply_time.get(node, 0)
# second, %fct time in profiler
......@@ -321,9 +324,9 @@ class GraphFormatter(object):
pf = 0
else:
pf = time * 100 / profile.fct_call_time
prof_str = ' (%.3fs,%.3f%%)' % (time, pf)
prof = [time, None, pf]
applystr = str(node.op).replace(':', '_')
applystr += prof_str
if (applystr in self.all_strings) or self.with_ids:
idx = ' id=' + str(topo.index(node))
if len(applystr) + len(idx) > self.max_label_size:
......@@ -340,7 +343,11 @@ class GraphFormatter(object):
applystr = (applystr[:self.max_label_size - 3 - len(suffix)] +
'...' +
suffix)
if prof is not None:
prof = str(prof)
else:
prof = ''
self.all_strings.add(applystr)
self.apply_name_cache[node] = applystr
return applystr
self.apply_name_cache[node] = (applystr, prof)
return (applystr, prof)
<!DOCTYPE html>
<html>
<head>
......@@ -58,7 +59,7 @@
stroke: dodgerblue;
}
.tooltip {
.edgeTooltip {
position: absolute;
text-align: center;
vertical-align: middle;
......@@ -70,9 +71,22 @@
border-radius: 8px;
pointer-events: none;
}
.nodeTooltip {
position: absolute;
text-align: left;
vertical-align: middle;
min-width: 10px;
min-height: 10px;
padding: 5px;
background: lightsteelblue;
border: 1px solid black;
border-radius: 8px;
pointer-events: none;
}
</style>
<div>
<div id='menu'>
<input name="resetNodes"
type="button"
value="Reset nodes"
......@@ -85,7 +99,9 @@
<script type="text/javascript">
var path='%% DOT_FILE %%';
var isProfiled = false;
var colorProfile = false;
// Global attributes
var pad = 10;
d3.select('body').select('svg').remove();
......@@ -95,7 +111,11 @@
var pane = svg.append('g');
var edgeDiv = d3.select('body').append('div')
.attr('class', 'tooltip')
.attr('class', 'edgeTooltip')
.style('opacity', 0.0);
var nodeDiv = d3.select('body').append('div')
.attr('class', 'nodeTooltip')
.style('opacity', 0.0);
// Definition head of edges
......@@ -113,6 +133,12 @@
.append("path")
.attr("d", "M0,0 L4,2 L0,4 Z")
.attr('fill', function(d) { return d.color;});
function toggleColors() {
colorProfile = !colorProfile;
updateNodes();
updateGraph();
}
function textSize(text, attr) {
var t = svg.append('text').text(text);
......@@ -128,8 +154,99 @@
function exists(x) {
return typeof(x) != 'undefined';
}
function replaceAll(str, find, replace) {
return str.replace(new RegExp(find, 'g'), replace);
}
function parseProfile(profile) {
if (typeof(profile) == 'undefined') {
return;
}
profile = profile.replace('[', '');
profile = profile.replace(']', '');
profile = replaceAll(profile, ' ', '');
profile = profile.split(',');
if (profile.length < 2) {
return [];
}
profile = profile.map(function(x) { return parseFloat(x); });
return profile;
}
function profileColor(per) {
var colors = ["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"];
var s = d3.scale.linear()
.domain([0, 100])
.range([0, colors.length - 1]);
return colors[Math.round(s(per))];
}
function fillColor(d) {
if (colorProfile && typeof(d.value.profile) != 'undefined') {
return profileColor(d.value.profile[2]);
} else {
return typeof(d.value.fillcolor) == 'undefined' ? 'white' : d.value.fillcolor;
}
}
function formatTime(sec) {
var s;
if (sec < 0.1) {
s = (sec * 1000).toFixed(1) + 'ms';
} else {
s = sec.toFixed(1) + 's';
}
return s;
}
function nodeDetails(node) {
var s = '<b>' + node.value.label + '</b>';
var p = node.value.profile;
if (!isNaN(p[0])) {
s += '<br>Total time: ' + formatTime(p[0]);
}
if (!isNaN(p[1])) {
s += '<br>Total time: ' + p[1].toFixed(1) + '%';
}
if (!isNaN(p[2])) {
s += '<br>Profile time: ' + p[2].toFixed(1) + '%';
}
return s;
}
function updateNode(d, node) {
var shape;
if (d.value.shape == 'ellipse') {
node.selectAll('ellipse').remove();
shape = node.append('ellipse')
.attr('class', 'nodeEllipse')
.attr('cx', d.value.cx)
.attr('cy', d.value.cy)
.attr('rx', d.value.width * 0.6)
.attr('ry', d.value.height * 0.6);
} else {
node.selectAll('rect').remove();
shape = node.append('rect')
.attr('class', 'nodeRect')
.attr('width', d.value.width)
.attr('height', d.value.height);
}
shape.attr('fill', fillColor(d));
node.selectAll('text').remove();
var text = node.append('text')
.attr('class', 'nodeText')
.attr('x', pad)
.attr('dy', function(d) {return d.value.height - pad - 5;})
.text(function(d) {return d.value.label;});
}
function updateNodes() {
nodes.each(function(d) {var node = d3.select(this); updateNode(d, node);});
}
var dotGraph;
var graph = {};
......@@ -146,7 +263,7 @@
var posMax = [0, 0];
for (var nodeId in dotGraph._nodes) {
var node = dotGraph._nodes[nodeId];
node.value.label = node.id;
node.value.label = node.id;
node.value.pos = node.value.pos.split(',').map(function(d) {return parseInt(d);});
node.value.width = parseInt(node.value.width);
node.value.height = parseInt(node.value.height);
......@@ -173,12 +290,24 @@
node.value.height = size.height + 2 * pad;
node.value.cx = node.value.width / 2;
node.value.cy = node.value.height / 2;
node.value.profile = parseProfile(node.value.profile);
if (typeof(node.value.profile) != 'undefined') {
isProfiled = true;
}
node.fixed = true;
nodes.push(node);
dotGraph._nodes[nodeId] = node;
}
if (isProfiled) {
d3.select('body').select('#menu').append('input')
.attr('name', 'tColors')
.attr('type', 'button')
.attr('value', 'Toggle profile colors')
.attr('onclick', "toggleColors()");
}
// Parse edges
for (edgeId in dotGraph._edges) {
var edge = dotGraph._edges[edgeId];
......@@ -241,11 +370,9 @@
});
// Add nodes
nodes = pane.append('g').attr('id', 'nodes').selectAll('g').data(graph['nodes']).enter().append('g');
function fillColor(f) {
return typeof(f) == 'undefined' ? 'white' : f;
}
function setNodeSize(node) {
var size = textSize(node.value.label, {'class': 'nodeText'});
node.value.width = size.width + 2 * pad;
......@@ -254,44 +381,25 @@
node.value.cy = node.value.height / 2;
}
function updateNode(d, node) {
var shape;
if (d.value.shape == 'ellipse') {
node.selectAll('ellipse').remove();
shape = node.append('ellipse')
.attr('class', 'nodeEllipse')
.attr('cx', d.value.cx)
.attr('cy', d.value.cy)
.attr('rx', d.value.width * 0.6)
.attr('ry', d.value.height * 0.6);
} else {
node.selectAll('rect').remove();
shape = node.append('rect')
.attr('class', 'nodeRect')
.attr('width', d.value.width)
.attr('height', d.value.height);
}
shape.attr('fill', fillColor(d.value.fillcolor));
node.selectAll('text').remove();
var text = node.append('text')
.attr('class', 'nodeText')
.attr('x', pad)
.attr('dy', function(d) {return d.value.height - pad - 5;})
.text(function(d) {return d.value.label;})
.on('dblclick', releaseNode);
updateNodes();
function hideNodeDiv() {
nodeDiv.transition()
.duration(200)
.style('opacity', 0);
}
nodes.each(function(d) {var node = d3.select(this); updateNode(d, node);});
// TODO: activate again without interfering with click event
//nodes.on('dblclick', releaseNode);
nodes.on('click', function(d) {
var editNode = false;
nodes.on('dblclick', function(d) {
var pos = this.getBBox();
var node = d3.select(this);
if (d3.event.defaultPrevented) return;
editNode = true;
hideNodeDiv();
var form = node.append('foreignObject')
.attr('x', pos.x)
.attr('y', pos.y)
......@@ -308,6 +416,7 @@
setNodeSize(d);
updateNode(d, node);
form.remove(); // TODO: check this
editNode = false;
})
.on('keypress', function() {
if (!d3.event) {
......@@ -325,12 +434,17 @@
d.value.label = input.node().value;
setNodeSize(d);
updateNode(d, node);
form.remove(); // TODO: check thi
form.remove(); // TODO: check this
editNode = false;
}
});
});
nodes.on('mouseover', function(node) {
if (editNode || typeof(node.value.profile) == 'undefined') {
return;
}
edges.each(function (d, i) {
var edge = d3.select(this);
if (d.source == node || d.target == node) {
......@@ -339,8 +453,16 @@
.style('opacity', 1.0);
}
});
nodeDiv.transition()
.duration(200)
.style('opacity', .9);
nodeDiv
.html(nodeDetails(node))
.style('left', (d3.event.pageX) + 30 + 'px')
.style('top', (d3.event.pageY - 28) + 'px');
});
nodes.on('mouseout', function(node) {
edges.each(function (d, i) {
var edge = d3.select(this);
......@@ -350,6 +472,11 @@
.style('opacity', 0.4);
}
});
hideNodeDiv();
});
nodes.on('contextmenu', function(d) {
releaseNode(d);
});
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论