@@ -97,12 +97,12 @@ def __str__(self):
97
97
98
98
Format:
99
99
{
100
- 'source_arn': 'string', 'destination_arn': 'string',
100
+ 'source_arn': 'string', 'destination_arn': 'string',
101
101
'association_type': 'string'
102
102
}
103
-
103
+
104
104
"""
105
- return ( str (self .__dict__ ) )
105
+ return str (self .__dict__ )
106
106
107
107
108
108
class Vertex :
@@ -147,13 +147,13 @@ def __str__(self):
147
147
148
148
Format:
149
149
{
150
- 'arn': 'string', 'lineage_entity': 'string',
151
- 'lineage_source': 'string',
150
+ 'arn': 'string', 'lineage_entity': 'string',
151
+ 'lineage_source': 'string',
152
152
'_session': <sagemaker.session.Session object>
153
153
}
154
-
154
+
155
155
"""
156
- return ( str (self .__dict__ ) )
156
+ return str (self .__dict__ )
157
157
158
158
def to_lineage_object (self ):
159
159
"""Convert the ``Vertex`` object to its corresponding lineage object.
@@ -201,6 +201,90 @@ def _artifact_to_lineage_object(self):
201
201
return Artifact .load (artifact_arn = self .arn , sagemaker_session = self ._session )
202
202
203
203
204
+ class DashVisualizer (object ):
205
+ """Create object used for visualizing graph using Dash library."""
206
+
207
+ def __init__ (self ):
208
+ """Init for DashVisualizer."""
209
+ # import visualization packages
210
+ self .cyto , self .JupyterDash , self .html = self ._import_visual_modules ()
211
+
212
+ def _import_visual_modules (self ):
213
+ """Import modules needed for visualization."""
214
+ try :
215
+ import dash_cytoscape as cyto
216
+ except ImportError as e :
217
+ print (e )
218
+ print ("try pip install dash-cytoscape" )
219
+
220
+ try :
221
+ from jupyter_dash import JupyterDash
222
+ except ImportError as e :
223
+ print (e )
224
+ print ("try pip install jupyter-dash" )
225
+
226
+ try :
227
+ from dash import html
228
+ except ImportError as e :
229
+ print (e )
230
+ print ("try pip install dash" )
231
+
232
+ return cyto , JupyterDash , html
233
+
234
+ def _get_app (self , elements ):
235
+ """Create JupyterDash app for interactivity on Jupyter notebook."""
236
+ app = self .JupyterDash (__name__ )
237
+ self .cyto .load_extra_layouts ()
238
+
239
+ app .layout = self .html .Div (
240
+ [
241
+ self .cyto .Cytoscape (
242
+ id = "cytoscape-layout-1" ,
243
+ elements = elements ,
244
+ style = {"width" : "100%" , "height" : "350px" },
245
+ layout = {"name" : "klay" },
246
+ stylesheet = [
247
+ {
248
+ "selector" : "node" ,
249
+ "style" : {
250
+ "label" : "data(label)" ,
251
+ "font-size" : "3.5vw" ,
252
+ "height" : "10vw" ,
253
+ "width" : "10vw" ,
254
+ },
255
+ },
256
+ {
257
+ "selector" : "edge" ,
258
+ "style" : {
259
+ "label" : "data(label)" ,
260
+ "color" : "gray" ,
261
+ "text-halign" : "left" ,
262
+ "text-margin-y" : "3px" ,
263
+ "text-margin-x" : "-2px" ,
264
+ "font-size" : "3%" ,
265
+ "width" : "1%" ,
266
+ "curve-style" : "taxi" ,
267
+ "target-arrow-color" : "gray" ,
268
+ "target-arrow-shape" : "triangle" ,
269
+ "line-color" : "gray" ,
270
+ "arrow-scale" : "0.5" ,
271
+ },
272
+ },
273
+ ],
274
+ responsive = True ,
275
+ )
276
+ ]
277
+ )
278
+
279
+ return app
280
+
281
+ def render (self , elements , mode ):
282
+ """Render graph for lineage query result."""
283
+ app = self ._get_app (elements )
284
+
285
+ return app .run_server (mode = mode )
286
+
287
+
204
288
class LineageQueryResult (object ):
205
289
"""A wrapper around the results of a lineage query."""
206
290
@@ -226,29 +310,74 @@ def __init__(
226
310
227
311
def __str__ (self ):
228
312
"""Define string representation of ``LineageQueryResult``.
229
-
313
+
230
314
Format:
231
315
{
232
316
'edges':[
233
317
{
234
- 'source_arn': 'string', 'destination_arn': 'string',
318
+ 'source_arn': 'string', 'destination_arn': 'string',
235
319
'association_type': 'string'
236
320
},
237
321
...
238
322
]
239
323
'vertices':[
240
324
{
241
- 'arn': 'string', 'lineage_entity': 'string',
242
- 'lineage_source': 'string',
325
+ 'arn': 'string', 'lineage_entity': 'string',
326
+ 'lineage_source': 'string',
243
327
'_session': <sagemaker.session.Session object>
244
328
},
245
329
...
246
330
]
247
331
}
248
-
332
+
249
333
"""
250
334
result_dict = vars (self )
251
- return (str ({k : [vars (val ) for val in v ] for k , v in result_dict .items ()}))
335
+ return str ({k : [vars (val ) for val in v ] for k , v in result_dict .items ()})
336
+
337
+ def _covert_vertices_to_tuples (self ):
338
+ """Convert vertices to tuple format for visualizer."""
339
+ verts = []
340
+ for vert in self .vertices :
341
+ verts .append ((vert .arn , vert .lineage_source ))
342
+ return verts
343
+
344
+ def _covert_edges_to_tuples (self ):
345
+ """Convert edges to tuple format for visualizer."""
346
+ edges = []
347
+ for edge in self .edges :
348
+ edges .append ((edge .source_arn , edge .destination_arn , edge .association_type ))
349
+ return edges
350
+
351
+ def _get_visualization_elements (self ):
352
+ """Get elements for visualization."""
353
+ verts = self ._covert_vertices_to_tuples ()
354
+ edges = self ._covert_edges_to_tuples ()
355
+
356
+ nodes = [
357
+ {
358
+ "data" : {"id" : id , "label" : label },
359
+ }
360
+ for id , label in verts
361
+ ]
362
+
363
+ edges = [
364
+ {"data" : {"source" : source , "target" : target , "label" : label }}
365
+ for source , target , label in edges
366
+ ]
367
+
368
+ elements = nodes + edges
369
+
370
+ return elements
371
+
372
+ def visualize (self ):
373
+ """Visualize lineage query result."""
374
+ elements = self ._get_visualization_elements ()
375
+
376
+ dash_vis = DashVisualizer ()
377
+
378
+ dash_server = dash_vis .render (elements = elements , mode = "inline" )
379
+
380
+ return dash_server
252
381
253
382
254
383
class LineageFilter (object ):
0 commit comments