提交 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): ...@@ -157,7 +157,7 @@ class GraphFormatter(object):
apply_shape = 'ellipse' apply_shape = 'ellipse'
var_shape = 'box' var_shape = 'box'
for node_idx, node in enumerate(topo): 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 use_color = None
for opName, color in self.colorCodes.items(): for opName, color in self.colorCodes.items():
...@@ -165,12 +165,12 @@ class GraphFormatter(object): ...@@ -165,12 +165,12 @@ class GraphFormatter(object):
use_color = color use_color = color
if use_color is None: 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: elif self.high_contrast:
nw_node = pd.Node(astr, style='filled', fillcolor=use_color, nw_node = pd.Node(astr, style='filled', fillcolor=use_color,
shape=apply_shape, type='colored') shape=apply_shape, type='colored', profile=aprof)
else: 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) g.add_node(nw_node)
if self.cond_highlight: if self.cond_highlight:
if node in middle: if node in middle:
...@@ -180,6 +180,10 @@ class GraphFormatter(object): ...@@ -180,6 +180,10 @@ class GraphFormatter(object):
elif node in right: elif node in right:
c2.add_node(nw_node) 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): for id, var in enumerate(node.inputs):
varstr = self.var_name(var) varstr = self.var_name(var)
label = str(var.type) label = str(var.type)
...@@ -196,19 +200,19 @@ class GraphFormatter(object): ...@@ -196,19 +200,19 @@ class GraphFormatter(object):
param['color'] = 'red' param['color'] = 'red'
if var.owner is None: if var.owner is None:
if self.high_contrast: if self.high_contrast:
g.add_node(pd.Node(varstr, g.add_node(make_node(varstr,
style='filled', style='filled',
fillcolor=self.node_colors['input'], fillcolor=self.node_colors['input'],
shape=var_shape)) shape=var_shape, profile=aprof))
else: else:
g.add_node(pd.Node(varstr, color=self.node_colors['input'], g.add_node(make_node(varstr, color=self.node_colors['input'],
shape=var_shape)) shape=var_shape, profile=aprof))
g.add_edge(pd.Edge(varstr, astr, label=label, **param)) g.add_edge(pd.Edge(varstr, astr, label=label, **param))
elif var.name or not self.compact: elif var.name or not self.compact:
g.add_edge(pd.Edge(varstr, astr, label=label, **param)) g.add_edge(pd.Edge(varstr, astr, label=label, **param))
else: else:
# no name, so we don't make a var ellipse # 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, g.add_edge(pd.Edge(name, astr,
label=label, **param)) label=label, **param))
...@@ -223,21 +227,21 @@ class GraphFormatter(object): ...@@ -223,21 +227,21 @@ class GraphFormatter(object):
if out: if out:
g.add_edge(pd.Edge(astr, varstr, label=label)) g.add_edge(pd.Edge(astr, varstr, label=label))
if self.high_contrast: 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'], fillcolor=self.node_colors['output'],
shape=var_shape)) shape=var_shape, profile=aprof))
else: else:
g.add_node(pd.Node(varstr, color=self.node_colors['output'], g.add_node(make_node(varstr, color=self.node_colors['output'],
shape=var_shape)) shape=var_shape, profile=aprof))
elif len(var.clients) == 0: elif len(var.clients) == 0:
g.add_edge(pd.Edge(astr, varstr, label=label)) g.add_edge(pd.Edge(astr, varstr, label=label))
if self.high_contrast: 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'], fillcolor=self.node_colors['unused'],
shape=var_shape)) shape=var_shape, profile=aprof))
else: else:
g.add_node(pd.Node(varstr, color=self.node_colors['unused'], g.add_node(make_node(varstr, color=self.node_colors['unused'],
shape=var_shape)) shape=var_shape, profile=aprof))
elif var.name or not self.compact: elif var.name or not self.compact:
g.add_edge(pd.Edge(astr, varstr, label=label)) g.add_edge(pd.Edge(astr, varstr, label=label))
...@@ -296,12 +300,11 @@ class GraphFormatter(object): ...@@ -296,12 +300,11 @@ class GraphFormatter(object):
return varstr return varstr
def apply_name(self, node, fct, topo, mode=None, profile=None): def apply_name(self, node, fct, topo, mode=None, profile=None):
if node in self.apply_name_cache: if node in self.apply_name_cache:
return self.apply_name_cache[node] return self.apply_name_cache[node]
prof_str = '' prof = None
if mode: if mode:
time = mode.profile_stats[fct].apply_time.get(node, 0) time = mode.profile_stats[fct].apply_time.get(node, 0)
# second, % total time in profiler, %fct time in profiler # second, % total time in profiler, %fct time in profiler
...@@ -313,7 +316,7 @@ class GraphFormatter(object): ...@@ -313,7 +316,7 @@ class GraphFormatter(object):
pf = 0 pf = 0
else: else:
pf = time * 100 / mode.profile_stats[fct].fct_call_time pf = time * 100 / mode.profile_stats[fct].fct_call_time
prof_str = ' (%.3fs,%.3f%%,%.3f%%)' % (time, pt, pf) prof = [time, pt, pf]
elif profile: elif profile:
time = profile.apply_time.get(node, 0) time = profile.apply_time.get(node, 0)
# second, %fct time in profiler # second, %fct time in profiler
...@@ -321,9 +324,9 @@ class GraphFormatter(object): ...@@ -321,9 +324,9 @@ class GraphFormatter(object):
pf = 0 pf = 0
else: else:
pf = time * 100 / profile.fct_call_time pf = time * 100 / profile.fct_call_time
prof_str = ' (%.3fs,%.3f%%)' % (time, pf) prof = [time, None, pf]
applystr = str(node.op).replace(':', '_') applystr = str(node.op).replace(':', '_')
applystr += prof_str
if (applystr in self.all_strings) or self.with_ids: if (applystr in self.all_strings) or self.with_ids:
idx = ' id=' + str(topo.index(node)) idx = ' id=' + str(topo.index(node))
if len(applystr) + len(idx) > self.max_label_size: if len(applystr) + len(idx) > self.max_label_size:
...@@ -340,7 +343,11 @@ class GraphFormatter(object): ...@@ -340,7 +343,11 @@ class GraphFormatter(object):
applystr = (applystr[:self.max_label_size - 3 - len(suffix)] + applystr = (applystr[:self.max_label_size - 3 - len(suffix)] +
'...' + '...' +
suffix) suffix)
if prof is not None:
prof = str(prof)
else:
prof = ''
self.all_strings.add(applystr) self.all_strings.add(applystr)
self.apply_name_cache[node] = applystr self.apply_name_cache[node] = (applystr, prof)
return applystr return (applystr, prof)
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
...@@ -58,7 +59,7 @@ ...@@ -58,7 +59,7 @@
stroke: dodgerblue; stroke: dodgerblue;
} }
.tooltip { .edgeTooltip {
position: absolute; position: absolute;
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
...@@ -70,9 +71,22 @@ ...@@ -70,9 +71,22 @@
border-radius: 8px; border-radius: 8px;
pointer-events: none; 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> </style>
<div> <div id='menu'>
<input name="resetNodes" <input name="resetNodes"
type="button" type="button"
value="Reset nodes" value="Reset nodes"
...@@ -85,6 +99,8 @@ ...@@ -85,6 +99,8 @@
<script type="text/javascript"> <script type="text/javascript">
var path='%% DOT_FILE %%'; var path='%% DOT_FILE %%';
var isProfiled = false;
var colorProfile = false;
// Global attributes // Global attributes
var pad = 10; var pad = 10;
...@@ -95,7 +111,11 @@ ...@@ -95,7 +111,11 @@
var pane = svg.append('g'); var pane = svg.append('g');
var edgeDiv = d3.select('body').append('div') 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); .style('opacity', 0.0);
// Definition head of edges // Definition head of edges
...@@ -114,6 +134,12 @@ ...@@ -114,6 +134,12 @@
.attr("d", "M0,0 L4,2 L0,4 Z") .attr("d", "M0,0 L4,2 L0,4 Z")
.attr('fill', function(d) { return d.color;}); .attr('fill', function(d) { return d.color;});
function toggleColors() {
colorProfile = !colorProfile;
updateNodes();
updateGraph();
}
function textSize(text, attr) { function textSize(text, attr) {
var t = svg.append('text').text(text); var t = svg.append('text').text(text);
if (typeof(attr) != 'undefined') { if (typeof(attr) != 'undefined') {
...@@ -130,6 +156,97 @@ ...@@ -130,6 +156,97 @@
return typeof(x) != 'undefined'; 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 dotGraph;
var graph = {}; var graph = {};
...@@ -173,12 +290,24 @@ ...@@ -173,12 +290,24 @@
node.value.height = size.height + 2 * pad; node.value.height = size.height + 2 * pad;
node.value.cx = node.value.width / 2; node.value.cx = node.value.width / 2;
node.value.cy = node.value.height / 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; node.fixed = true;
nodes.push(node); nodes.push(node);
dotGraph._nodes[nodeId] = 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 // Parse edges
for (edgeId in dotGraph._edges) { for (edgeId in dotGraph._edges) {
var edge = dotGraph._edges[edgeId]; var edge = dotGraph._edges[edgeId];
...@@ -241,10 +370,8 @@ ...@@ -241,10 +370,8 @@
}); });
// Add nodes // Add nodes
nodes = pane.append('g').attr('id', 'nodes').selectAll('g').data(graph['nodes']).enter().append('g'); 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) { function setNodeSize(node) {
var size = textSize(node.value.label, {'class': 'nodeText'}); var size = textSize(node.value.label, {'class': 'nodeText'});
...@@ -254,44 +381,25 @@ ...@@ -254,44 +381,25 @@
node.value.cy = node.value.height / 2; node.value.cy = node.value.height / 2;
} }
function updateNode(d, node) { updateNodes();
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(); function hideNodeDiv() {
var text = node.append('text') nodeDiv.transition()
.attr('class', 'nodeText') .duration(200)
.attr('x', pad) .style('opacity', 0);
.attr('dy', function(d) {return d.value.height - pad - 5;})
.text(function(d) {return d.value.label;})
.on('dblclick', releaseNode);
} }
nodes.each(function(d) {var node = d3.select(this); updateNode(d, node);});
// TODO: activate again without interfering with click event var editNode = false;
//nodes.on('dblclick', releaseNode);
nodes.on('click', function(d) { nodes.on('dblclick', function(d) {
var pos = this.getBBox(); var pos = this.getBBox();
var node = d3.select(this); var node = d3.select(this);
if (d3.event.defaultPrevented) return; if (d3.event.defaultPrevented) return;
editNode = true;
hideNodeDiv();
var form = node.append('foreignObject') var form = node.append('foreignObject')
.attr('x', pos.x) .attr('x', pos.x)
.attr('y', pos.y) .attr('y', pos.y)
...@@ -308,6 +416,7 @@ ...@@ -308,6 +416,7 @@
setNodeSize(d); setNodeSize(d);
updateNode(d, node); updateNode(d, node);
form.remove(); // TODO: check this form.remove(); // TODO: check this
editNode = false;
}) })
.on('keypress', function() { .on('keypress', function() {
if (!d3.event) { if (!d3.event) {
...@@ -325,12 +434,17 @@ ...@@ -325,12 +434,17 @@
d.value.label = input.node().value; d.value.label = input.node().value;
setNodeSize(d); setNodeSize(d);
updateNode(d, node); updateNode(d, node);
form.remove(); // TODO: check thi form.remove(); // TODO: check this
editNode = false;
} }
}); });
}); });
nodes.on('mouseover', function(node) { nodes.on('mouseover', function(node) {
if (editNode || typeof(node.value.profile) == 'undefined') {
return;
}
edges.each(function (d, i) { edges.each(function (d, i) {
var edge = d3.select(this); var edge = d3.select(this);
if (d.source == node || d.target == node) { if (d.source == node || d.target == node) {
...@@ -339,8 +453,16 @@ ...@@ -339,8 +453,16 @@
.style('opacity', 1.0); .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) { nodes.on('mouseout', function(node) {
edges.each(function (d, i) { edges.each(function (d, i) {
var edge = d3.select(this); var edge = d3.select(this);
...@@ -350,6 +472,11 @@ ...@@ -350,6 +472,11 @@
.style('opacity', 0.4); .style('opacity', 0.4);
} }
}); });
hideNodeDiv();
});
nodes.on('contextmenu', function(d) {
releaseNode(d);
}); });
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论