Skip to content

Commit c1be765

Browse files
author
Yi-Ting Lee
committed
change: lineage query visualization experience enhancement
1 parent a9e5114 commit c1be765

File tree

3 files changed

+110
-18
lines changed

3 files changed

+110
-18
lines changed

src/sagemaker/lineage/query.py

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
from datetime import datetime
1717
from enum import Enum
18-
from platform import node
1918
from typing import Optional, Union, List, Dict
2019
import re
2120

@@ -263,7 +262,7 @@ def __init__(self, graph_styles):
263262
self.Network,
264263
self.Options,
265264
self.IFrame,
266-
self.BeautifulSoup
265+
self.BeautifulSoup,
267266
) = self._import_visual_modules()
268267

269268
self.graph_styles = graph_styles
@@ -316,9 +315,53 @@ def _node_color(self, entity):
316315
return self.graph_styles[entity]["style"]["background-color"]
317316

318317
def _add_legend(self, path):
319-
f = open(path, "r+")
320-
soup = self.BeautifulSoup(f, 'html.parser')
321-
print(soup.prettify())
318+
"""Embed legend to html file generated by pyvis."""
319+
f = open(path, "r")
320+
content = self.BeautifulSoup(f, "html.parser")
321+
322+
legend = """
323+
<div style="display: inline-block; font-size: 1vw; font-family: verdana;
324+
vertical-align: top; padding: 1vw;">
325+
<div>
326+
<div style="background-color: rgb(246, 207, 97); width: 1.6vw; height: 1.6vw;
327+
display: inline-block; font-size: 1.5vw; vertical-align: -0.2em;"></div>
328+
<div style="width: 0.3vw; height: 1.5vw; display: inline-block;"></div>
329+
<div style="display: inline-block; font-size: 1.5vw;">Trial Component</div>
330+
</div>
331+
<div>
332+
<div style="background-color: rgb(255, 153, 0); width: 1.6vw; height: 1.6vw;
333+
display: inline-block; font-size: 1.5vw; vertical-align: -0.2em;"></div>
334+
<div style="width: 0.3vw; height: 1.5vw; display: inline-block;"></div>
335+
<div style="display: inline-block; font-size: 1.5vw;">Context</div>
336+
</div>
337+
<div>
338+
<div style="background-color: rgb(136, 195, 150); width: 1.6vw; height: 1.6vw;
339+
display: inline-block; font-size: 1.5vw; vertical-align: -0.2em;"></div>
340+
<div style="width: 0.3vw; height: 1.5vw; display: inline-block;"></div>
341+
<div style="display: inline-block; font-size: 1.5vw;">Action</div>
342+
</div>
343+
<div>
344+
<div style="background-color: rgb(20, 110, 180); width: 1.6vw; height: 1.6vw;
345+
display: inline-block; font-size: 1.5vw; vertical-align: -0.2em;"></div>
346+
<div style="width: 0.3vw; height: 1.5vw; display: inline-block;"></div>
347+
<div style="display: inline-block; font-size: 1.5vw;">Artifact</div>
348+
</div>
349+
<div>
350+
<div style="background-color: rgb(255, 255, 255); width: 1.6vw; height: 1.6vw;
351+
display: inline-block; font-size: 0.9vw;">star</div>
352+
<div style="width: 0.3vw; height: 1.5vw; display: inline-block;"></div>
353+
<div style="display: inline-block; font-size: 1.5vw;">StartArn</div>
354+
</div>
355+
</div>
356+
"""
357+
legend_div = self.BeautifulSoup(legend, "html.parser")
358+
359+
content.div.insert_after(legend_div)
360+
361+
html = content.prettify()
362+
363+
with open(path, "w", encoding="utf8") as file:
364+
file.write(html)
322365

323366
def render(self, elements, path="pyvisExample.html"):
324367
"""Render graph for lineage query result.
@@ -338,19 +381,42 @@ def render(self, elements, path="pyvisExample.html"):
338381
display graph: The interactive visualization is presented as a static HTML file.
339382
340383
"""
341-
net = self.Network(height="500px", width="100%", notebook=True, directed=True)
384+
net = self.Network(height="600px", width="82%", notebook=True, directed=True)
342385
net.set_options(self._options)
343386

344387
# add nodes to graph
345388
for arn, source, entity, is_start_arn in elements["nodes"]:
389+
entity_text = re.sub(r"(\w)([A-Z])", r"\1 \2", entity)
346390
source = re.sub(r"(\w)([A-Z])", r"\1 \2", source)
347-
node_info = "Entity: " + entity + "\n" + "Type: " + source + "\n" + "Name: " + arn
391+
account_id = re.search(r":\d{12}:", arn)
392+
name = re.search(r"\/.*", arn)
393+
node_info = (
394+
"Entity: "
395+
+ entity_text
396+
+ "\nType: "
397+
+ source
398+
+ "\nAccount ID: "
399+
+ str(account_id.group()[1:-1])
400+
+ "\nName: "
401+
+ str(name.group()[1:])
402+
)
348403
if is_start_arn: # startarn
349404
net.add_node(
350-
arn, label=source, title=node_info, color=self._node_color(entity), shape="star", borderWidth=3
405+
arn,
406+
label=source,
407+
title=node_info,
408+
color=self._node_color(entity),
409+
shape="star",
410+
borderWidth=3,
351411
)
352412
else:
353-
net.add_node(arn, label=source, title=node_info, color=self._node_color(entity), borderWidth=3)
413+
net.add_node(
414+
arn,
415+
label=source,
416+
title=node_info,
417+
color=self._node_color(entity),
418+
borderWidth=3,
419+
)
354420

355421
# add edges to graph
356422
for src, dest, asso_type in elements["edges"]:
@@ -359,7 +425,7 @@ def render(self, elements, path="pyvisExample.html"):
359425
net.write_html(path)
360426
self._add_legend(path)
361427

362-
return self.IFrame(path, width="100%", height="500px")
428+
return self.IFrame(path, width="100%", height="600px")
363429

364430

365431
class LineageQueryResult(object):

tests/integ/sagemaker/lineage/test_lineage_visualize.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from __future__ import absolute_import
1515
import time
1616
import os
17+
import re
1718

1819
import pytest
1920

@@ -160,31 +161,56 @@ def test_graph_visualize(sagemaker_session, extract_data_from_html):
160161
"color": "#146eb4",
161162
"label": "Model",
162163
"shape": "star",
163-
"title": "Artifact",
164+
"title": "Entity: Artifact"
165+
+ "\nType: Model"
166+
+ "\nAccount ID: "
167+
+ str(re.search(r":\d{12}:", graph_startarn).group()[1:-1])
168+
+ "\nName: "
169+
+ str(re.search(r"\/.*", graph_startarn).group()[1:]),
164170
},
165171
image_artifact: {
166172
"color": "#146eb4",
167173
"label": "Image",
168174
"shape": "dot",
169-
"title": "Artifact",
175+
"title": "Entity: Artifact"
176+
+ "\nType: Image"
177+
+ "\nAccount ID: "
178+
+ str(re.search(r":\d{12}:", image_artifact).group()[1:-1])
179+
+ "\nName: "
180+
+ str(re.search(r"\/.*", image_artifact).group()[1:]),
170181
},
171182
dataset_artifact: {
172183
"color": "#146eb4",
173-
"label": "DataSet",
184+
"label": "Data Set",
174185
"shape": "dot",
175-
"title": "Artifact",
186+
"title": "Entity: Artifact"
187+
+ "\nType: Data Set"
188+
+ "\nAccount ID: "
189+
+ str(re.search(r":\d{12}:", dataset_artifact).group()[1:-1])
190+
+ "\nName: "
191+
+ str(re.search(r"\/.*", dataset_artifact).group()[1:]),
176192
},
177193
modeldeploy_action: {
178194
"color": "#88c396",
179-
"label": "ModelDeploy",
195+
"label": "Model Deploy",
180196
"shape": "dot",
181-
"title": "Action",
197+
"title": "Entity: Action"
198+
+ "\nType: Model Deploy"
199+
+ "\nAccount ID: "
200+
+ str(re.search(r":\d{12}:", modeldeploy_action).group()[1:-1])
201+
+ "\nName: "
202+
+ str(re.search(r"\/.*", modeldeploy_action).group()[1:]),
182203
},
183204
endpoint_context: {
184205
"color": "#ff9900",
185206
"label": "Endpoint",
186207
"shape": "dot",
187-
"title": "Context",
208+
"title": "Entity: Context"
209+
+ "\nType: Endpoint"
210+
+ "\nAccount ID: "
211+
+ str(re.search(r":\d{12}:", endpoint_context).group()[1:-1])
212+
+ "\nName: "
213+
+ str(re.search(r"\/.*", endpoint_context).group()[1:]),
188214
},
189215
}
190216

tests/unit/sagemaker/lineage/test_query.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ def test_query_lineage_result_str(sagemaker_session):
580580

581581
assert (
582582
response_str
583-
== "{\n'edges': [\n\t{'source_arn': 'arn1', 'destination_arn': 'arn2', 'association_type': 'Produced'}],"
583+
== "{'edges': [\n\t{'source_arn': 'arn1', 'destination_arn': 'arn2', 'association_type': 'Produced'}],"
584584
+ "\n\n'vertices': [\n\t{'arn': 'arn1', 'lineage_entity': 'Artifact', 'lineage_source': 'Endpoint', "
585585
+ "'_session': <Mock id=''>}, \n\t{'arn': 'arn2', 'lineage_entity': 'Context', 'lineage_source': "
586586
+ "'Model', '_session': <Mock id=''>}],\n\n'startarn': "

0 commit comments

Comments
 (0)