4
4
try :
5
5
import dash
6
6
import dash_cytoscape as cyto
7
- from dash import html , Output , Input
7
+ from dash import Input , Output , html
8
8
except ImportError :
9
9
raise ImportError ("Please install the 'dash' and 'dash-cytoscape' packages to use the visualizer." )
10
10
11
+ import json
11
12
import os
12
13
import sys
13
- import json
14
14
15
15
16
16
def main ():
@@ -32,32 +32,28 @@ def main():
32
32
33
33
# Create nodes for observable registers.
34
34
for register in range (graph ["observable_registers" ]):
35
- elements .append ({
36
- "data" : {
37
- "id" : f"obs_register_{ register } " ,
38
- "label" : f"Observable register { register } " ,
39
- "info" : "This is an observable register. It's an output of a workflow."
40
- },
41
- "classes" : "register"
42
- })
35
+ elements .append (
36
+ {
37
+ "data" : {
38
+ "id" : f"obs_register_{ register } " ,
39
+ "label" : f"Observable register { register } " ,
40
+ "info" : "This is an observable register. It's an output of a workflow." ,
41
+ },
42
+ "classes" : "register" ,
43
+ }
44
+ )
43
45
ins [register ] = [f"obs_register_{ register } " ]
44
46
rendered_registers .add (register )
45
47
46
-
47
48
script_i = 0
48
49
execution_i = 0
49
50
# First pass to create nodes and mark input registers.
50
51
for task in graph ["tasks" ]:
51
52
if task ["type" ] == "script" :
52
53
id = f"script_{ script_i } "
53
- elements .append ({
54
- "data" : {
55
- "id" : id ,
56
- "label" : task .get ("name" , f"Script { script_i } " ),
57
- "info" : task
58
- },
59
- "classes" : "script"
60
- })
54
+ elements .append (
55
+ {"data" : {"id" : id , "label" : task .get ("name" , f"Script { script_i } " ), "info" : task }, "classes" : "script" }
56
+ )
61
57
if task ["reactive" ]:
62
58
elements [- 1 ]["classes" ] += " reactive"
63
59
script_i += 1
@@ -67,14 +63,12 @@ def main():
67
63
ins [register ].append (id )
68
64
elif task ["type" ] == "execution" :
69
65
id = f"execution_{ execution_i } "
70
- elements .append ({
71
- "data" : {
72
- "id" : id ,
73
- "label" : task .get ("name" , f"Execution { execution_i } " ),
74
- "info" : task
75
- },
76
- "classes" : "execution"
77
- })
66
+ elements .append (
67
+ {
68
+ "data" : {"id" : id , "label" : task .get ("name" , f"Execution { execution_i } " ), "info" : task },
69
+ "classes" : "execution" ,
70
+ }
71
+ )
78
72
if task ["exclusive" ]:
79
73
elements [- 1 ]["classes" ] += " exclusive"
80
74
@@ -99,31 +93,37 @@ def main():
99
93
100
94
for register in registers :
101
95
if register not in ins :
102
- elements .append ({
103
- "data" : {
104
- "id" : f"register_{ register } " ,
105
- "label" : f"Register { register } " ,
106
- "info" : f"This is a register. It's an intermediate value in a workflow."
107
- },
108
- "classes" : "register"
109
- })
96
+ elements .append (
97
+ {
98
+ "data" : {
99
+ "id" : f"register_{ register } " ,
100
+ "label" : f"Register { register } " ,
101
+ "info" : f"This is a register. It's an intermediate value in a workflow." ,
102
+ },
103
+ "classes" : "register" ,
104
+ }
105
+ )
110
106
ins [register ] = [f"register_{ register } " ]
111
107
rendered_registers .add (register )
112
108
for id in ins [register ]:
113
109
if task ["type" ] == "script" :
114
- elements .append ({
115
- "data" : {
116
- "source" : f"script_{ script_i } " ,
117
- "target" : id ,
110
+ elements .append (
111
+ {
112
+ "data" : {
113
+ "source" : f"script_{ script_i } " ,
114
+ "target" : id ,
115
+ }
118
116
}
119
- } )
117
+ )
120
118
elif task ["type" ] == "execution" :
121
- elements .append ({
122
- "data" : {
123
- "source" : f"execution_{ execution_i } " ,
124
- "target" : id ,
119
+ elements .append (
120
+ {
121
+ "data" : {
122
+ "source" : f"execution_{ execution_i } " ,
123
+ "target" : id ,
124
+ }
125
125
}
126
- } )
126
+ )
127
127
if register not in rendered_registers :
128
128
elements [- 1 ]["data" ]["label" ] = f"via register { register } "
129
129
@@ -133,70 +133,99 @@ def main():
133
133
execution_i += 1
134
134
135
135
app = dash .Dash (__name__ )
136
- app .layout = html .Div ([
137
- html .Div ([
138
- cyto .Cytoscape (
139
- id = 'cytoscape' ,
140
- layout = {"name" : "breadthfirst" , "directed" : True },
141
- style = {'width' : '100%' , 'height' : '100vh' },
142
- elements = elements ,
143
- stylesheet = [
144
- {"selector" : "node" , "style" : {
145
- "label" : "data(label)" ,
146
- "text-valign" : "center" ,
147
- "text-margin-y" : "-20px" ,
148
- }},
149
- {"selector" : "edge" , "style" : {
150
- "curve-style" : "bezier" , # Makes edges curved for better readability
151
- "target-arrow-shape" : "triangle" , # Adds an arrowhead to indicate direction
152
- "arrow-scale" : 1.5 , # Makes the arrow larger
153
- "line-color" : "#0074D9" , # Edge color
154
- "target-arrow-color" : "#0074D9" , # Arrow color
155
- "width" : 2 , # Line thickness
156
- "content" : "data(label)" , # Show edge label on hover
157
- "font-size" : "12px" ,
158
- "color" : "#ff4136" ,
159
- "text-background-opacity" : 1 ,
160
- "text-background-color" : "white" ,
161
- "text-background-shape" : "roundrectangle" ,
162
- "text-border-opacity" : 1 ,
163
- "text-border-width" : 1 ,
164
- "text-border-color" : "#ff4136" ,
165
- }},
166
- {"selector" : ".register" , "style" : {
167
- "shape" : "rectangle" ,
168
- }},
169
- {"selector" : ".script" , "style" : {
170
- "shape" : "roundrectangle" ,
171
- }},
172
- {"selector" : ".execution" , "style" : {
173
- "shape" : "ellipse" ,
174
- }},
175
- {"selector" : ".reactive" , "style" : {
176
- "background-color" : "#ff851b" ,
177
- }},
178
- {"selector" : ".exclusive" , "style" : {
179
- "background-color" : "#ff4136" ,
180
- }},
136
+ app .layout = html .Div (
137
+ [
138
+ html .Div (
139
+ [
140
+ cyto .Cytoscape (
141
+ id = "cytoscape" ,
142
+ layout = {"name" : "breadthfirst" , "directed" : True },
143
+ style = {"width" : "100%" , "height" : "100vh" },
144
+ elements = elements ,
145
+ stylesheet = [
146
+ {
147
+ "selector" : "node" ,
148
+ "style" : {
149
+ "label" : "data(label)" ,
150
+ "text-valign" : "center" ,
151
+ "text-margin-y" : "-20px" ,
152
+ },
153
+ },
154
+ {
155
+ "selector" : "edge" ,
156
+ "style" : {
157
+ "curve-style" : "bezier" , # Makes edges curved for better readability
158
+ "target-arrow-shape" : "triangle" , # Adds an arrowhead to indicate direction
159
+ "arrow-scale" : 1.5 , # Makes the arrow larger
160
+ "line-color" : "#0074D9" , # Edge color
161
+ "target-arrow-color" : "#0074D9" , # Arrow color
162
+ "width" : 2 , # Line thickness
163
+ "content" : "data(label)" , # Show edge label on hover
164
+ "font-size" : "12px" ,
165
+ "color" : "#ff4136" ,
166
+ "text-background-opacity" : 1 ,
167
+ "text-background-color" : "white" ,
168
+ "text-background-shape" : "roundrectangle" ,
169
+ "text-border-opacity" : 1 ,
170
+ "text-border-width" : 1 ,
171
+ "text-border-color" : "#ff4136" ,
172
+ },
173
+ },
174
+ {
175
+ "selector" : ".register" ,
176
+ "style" : {
177
+ "shape" : "rectangle" ,
178
+ },
179
+ },
180
+ {
181
+ "selector" : ".script" ,
182
+ "style" : {
183
+ "shape" : "roundrectangle" ,
184
+ },
185
+ },
186
+ {
187
+ "selector" : ".execution" ,
188
+ "style" : {
189
+ "shape" : "ellipse" ,
190
+ },
191
+ },
192
+ {
193
+ "selector" : ".reactive" ,
194
+ "style" : {
195
+ "background-color" : "#ff851b" ,
196
+ },
197
+ },
198
+ {
199
+ "selector" : ".exclusive" ,
200
+ "style" : {
201
+ "background-color" : "#ff4136" ,
202
+ },
203
+ },
204
+ ],
205
+ ),
181
206
],
207
+ style = {"flex" : "3" , "height" : "100vh" },
182
208
),
183
- ], style = {"flex" : "3" , "height" : "100vh" }),
184
-
185
- html .Div ([
186
- html .Pre (id = 'node-data' , style = {
187
- "padding" : "10px" ,
188
- "white-space" : "pre" ,
189
- "overflow" : "auto" ,
190
- "max-height" : "95vh" ,
191
- "max-width" : "100%"
192
- })
193
- ], style = {"flex" : "1" , "height" : "100vh" , "background-color" : "#f7f7f7" })
194
- ], style = {"display" : "flex" , "flex-direction" : "row" , "height" : "100vh" })
195
-
196
- @app .callback (
197
- Output ('node-data' , 'children' ),
198
- Input ('cytoscape' , 'tapNodeData' )
209
+ html .Div (
210
+ [
211
+ html .Pre (
212
+ id = "node-data" ,
213
+ style = {
214
+ "padding" : "10px" ,
215
+ "white-space" : "pre" ,
216
+ "overflow" : "auto" ,
217
+ "max-height" : "95vh" ,
218
+ "max-width" : "100%" ,
219
+ },
220
+ )
221
+ ],
222
+ style = {"flex" : "1" , "height" : "100vh" , "background-color" : "#f7f7f7" },
223
+ ),
224
+ ],
225
+ style = {"display" : "flex" , "flex-direction" : "row" , "height" : "100vh" },
199
226
)
227
+
228
+ @app .callback (Output ("node-data" , "children" ), Input ("cytoscape" , "tapNodeData" ))
200
229
def display_task_info (data ):
201
230
if data is None :
202
231
return "Click on a node to see its info."
0 commit comments