Skip to content

Commit d24c8e0

Browse files
authored
Merge pull request #60 from wey-gu/dynamic_render_filename
optmize graph rendering
2 parents f8968a2 + 1d766a9 commit d24c8e0

File tree

5 files changed

+122
-31
lines changed

5 files changed

+122
-31
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ examples/*.html
1616

1717
# python
1818
.venv
19+
.ipynb_checkpoints/
20+
Untitled.ipynb

README.md

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,42 @@ https://github.com/wey-gu/jupyter_nebulagraph/assets/1651790/10135264-77b5-4d3c-
1515

1616
## Getting Started
1717

18-
Explore the capabilities of `jupyter_nebulagraph` by trying it on [Google Colab](https://colab.research.google.com/github/wey-gu/jupyter_nebulagraph/blob/main/docs/get_started.ipynb), and the equivalent Jupyter Notebook is available in Docs [here](https://jupyter-nebulagraph.readthedocs.io/en/latest/get_started_docs/).
18+
```bash
19+
pip install jupyter_nebulagraph
20+
```
21+
22+
Load the extension in Jupyter Notebook or iPython:
23+
24+
```python
25+
%load_ext ngql
26+
%ngql --address 127.0.0.1 --port 9669 --user root --password nebula
27+
```
28+
29+
Make queries:
30+
31+
```python
32+
%ngql USE basketballplayer;
33+
%ngql MATCH p=(v:player)-->(v2:player) WHERE id(v) == "player100" RETURN p;
34+
```
35+
36+
Draw the graph:
37+
38+
```python
39+
%ng_draw
40+
```
41+
42+
Discover the features of `jupyter_nebulagraph` by experimenting with it on [Google Colab](https://colab.research.google.com/github/wey-gu/jupyter_nebulagraph/blob/main/docs/get_started.ipynb). You can also access a similar Jupyter Notebook in the documentation [here](https://jupyter-nebulagraph.readthedocs.io/en/stable/get_started_docs/).
1943

20-
For a comprehensive guide, visit the [official documentation](https://jupyter-nebulagraph.readthedocs.io/).
44+
For a detailed guide, refer to the [official documentation](https://jupyter-nebulagraph.readthedocs.io/en/stable).
2145

2246
| Feature | Cheat Sheet | Example | Command Documentation |
2347
| ------- | ----------- | --------- | ---------------------- |
24-
| Connect | `%ngql --address 127.0.0.1 --port 9669 --user user --password password` | [Connect](https://jupyter-nebulagraph.readthedocs.io/en/latest/get_started_docs/#connect-to-nebulagraph) | [`%ngql`](https://jupyter-nebulagraph.readthedocs.io/en/latest/magic_words/ngql/#connect-to-nebulagraph) |
25-
| Load Data from CSV | `%ng_load --source actor.csv --tag player --vid 0 --props 1:name,2:age --space basketballplayer` | [Load Data](https://jupyter-nebulagraph.readthedocs.io/en/latest/get_started_docs/#load-data-from-csv) | [`%ng_load`](https://jupyter-nebulagraph.readthedocs.io/en/latest/magic_words/ng_load/) |
26-
| Query Execution | `%ngql MATCH p=(v:player{name:"Tim Duncan"})-->(v2:player) RETURN p;`| [Query Execution](https://jupyter-nebulagraph.readthedocs.io/en/latest/get_started_docs/#query) | [`%ngql` or `%%ngql`(multi-line)](https://jupyter-nebulagraph.readthedocs.io/en/latest/magic_words/ngql/#make-queries) |
27-
| Result Visualization | `%ng_draw` | [Draw Graph](https://jupyter-nebulagraph.readthedocs.io/en/latest/magic_words/ng_draw/) | [`%ng_draw`](https://jupyter-nebulagraph.readthedocs.io/en/latest/magic_words/ng_draw/) |
28-
| Draw Schema | `%ng_draw_schema` | [Draw Schema](https://jupyter-nebulagraph.readthedocs.io/en/latest/magic_words/ng_draw_schema/) | [`%ng_draw_schema`](https://jupyter-nebulagraph.readthedocs.io/en/latest/magic_words/ng_draw_schema/) |
29-
| Tweak Query Result | `df = _` to get last query result as `pd.dataframe` or [`ResultSet`](https://github.com/vesoft-inc/nebula-python/blob/master/nebula3/data/ResultSet.py) | [Tweak Result](https://jupyter-nebulagraph.readthedocs.io/en/latest/get_started_docs/#result-handling) | [Configure `ngql_result_style`](https://jupyter-nebulagraph.readthedocs.io/en/latest/configurations/#configure-ngql_result_style) |
48+
| Connect | `%ngql --address 127.0.0.1 --port 9669 --user user --password password` | [Connect](https://jupyter-nebulagraph.readthedocs.io/en/stable/get_started_docs/#connect-to-nebulagraph) | [`%ngql`](https://jupyter-nebulagraph.readthedocs.io/en/stable/magic_words/ngql/#connect-to-nebulagraph) |
49+
| Load Data from CSV | `%ng_load --source actor.csv --tag player --vid 0 --props 1:name,2:age --space basketballplayer` | [Load Data](https://jupyter-nebulagraph.readthedocs.io/en/stable/get_started_docs/#load-data-from-csv) | [`%ng_load`](https://jupyter-nebulagraph.readthedocs.io/en/stable/magic_words/ng_load/) |
50+
| Query Execution | `%ngql MATCH p=(v:player{name:"Tim Duncan"})-->(v2:player) RETURN p;`| [Query Execution](https://jupyter-nebulagraph.readthedocs.io/en/stable/get_started_docs/#query) | [`%ngql` or `%%ngql`(multi-line)](https://jupyter-nebulagraph.readthedocs.io/en/stable/magic_words/ngql/#make-queries) |
51+
| Result Visualization | `%ng_draw` | [Draw Graph](https://jupyter-nebulagraph.readthedocs.io/en/stable/magic_words/ng_draw/) | [`%ng_draw`](https://jupyter-nebulagraph.readthedocs.io/en/stable/magic_words/ng_draw/) |
52+
| Draw Schema | `%ng_draw_schema` | [Draw Schema](https://jupyter-nebulagraph.readthedocs.io/en/stable/magic_words/ng_draw_schema/) | [`%ng_draw_schema`](https://jupyter-nebulagraph.readthedocs.io/en/stable/magic_words/ng_draw_schema/) |
53+
| Tweak Query Result | `df = _` to get last query result as `pd.dataframe` or [`ResultSet`](https://github.com/vesoft-inc/nebula-python/blob/master/nebula3/data/ResultSet.py) | [Tweak Result](https://jupyter-nebulagraph.readthedocs.io/en/stable/get_started_docs/#result-handling) | [Configure `ngql_result_style`](https://jupyter-nebulagraph.readthedocs.io/en/stable/configurations/#configure-ngql_result_style) |
3054

3155

3256
<details>

ngql/magic.py

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ def get_color(input_str):
8181
return COLORS[hash_val % len(COLORS)]
8282

8383

84+
def is_human_readable(field):
85+
return any(c.isalpha() for c in field) and len(field) < 20
86+
87+
8488
@magics_class
8589
class IPythonNGQL(Magics, Configurable):
8690
ngql_verbose = Bool(False, config=True, help="Set verbose mode")
@@ -404,6 +408,18 @@ def ng_draw(self, line, cell=None, local_ns={}):
404408
for item in row:
405409
self.render_pd_item(g, g_nx, item)
406410

411+
try:
412+
# Calculate PageRank
413+
pagerank_scores = nx.pagerank(g_nx)
414+
415+
# Update node sizes based on PageRank scores
416+
for node_id, score in pagerank_scores.items():
417+
g.get_node(node_id)["size"] = (
418+
10 + score * 130
419+
) # Normalized size for visibility
420+
except Exception as e:
421+
print(f"[WARN]: failed to calculate PageRank\n { e }")
422+
407423
g.repulsion(
408424
node_distance=90,
409425
central_gravity=0.2,
@@ -412,20 +428,22 @@ def ng_draw(self, line, cell=None, local_ns={}):
412428
damping=0.09,
413429
)
414430
# g.show_buttons(filter_='physics')
415-
# return g.show("nebulagraph_draw.html", notebook=True)
416-
g_html_string = g.generate_html("nebulagraph.html")
417-
with open("nebulagraph.html", "w", encoding="utf-8") as f:
431+
# return g.show("nebulagraph.html", notebook=True)
432+
cell_num = get_ipython().execution_count
433+
graph_render_filename = f"nebulagraph_cell_{cell_num}.html"
434+
g_html_string = g.generate_html(graph_render_filename)
435+
with open(graph_render_filename, "w", encoding="utf-8") as f:
418436
f.write(g_html_string)
419437
# detect if we are in colab or not
420438
try:
421439
if "google.colab" in str(get_ipython()):
422440
display(HTML(g_html_string))
423441
else:
424-
display(IFrame(src="nebulagraph.html", width="100%", height="500px"))
442+
display(IFrame(src=graph_render_filename, width="100%", height="500px"))
425443
except Exception as e:
426444
print(f"[WARN]: failed to display the graph\n { e }")
427445
try:
428-
display(IFrame(src="nebulagraph.html", width="100%", height="500px"))
446+
display(IFrame(src=graph_render_filename, width="100%", height="500px"))
429447
except Exception as e:
430448
print(f"[WARN]: failed to display the graph\n { e }")
431449

@@ -549,9 +567,26 @@ def ng_draw_schema(self, line, cell=None, local_ns={}):
549567
edge_schema["dst_tag"],
550568
edge_schema["edge_type"],
551569
)
552-
g.add_edge(src_tag, dst_tag, label=edge_type, title=str(edge_schema))
570+
title = (
571+
"{\n "
572+
+ "\n ".join([f"{k}: {v}" for k, v in edge_schema.items()])
573+
+ "\n}"
574+
)
575+
g.add_edge(src_tag, dst_tag, label=edge_type, title=title)
553576
g_nx.add_edge(src_tag, dst_tag, **edge_schema)
554577

578+
try:
579+
# Calculate PageRank
580+
pagerank_scores = nx.pagerank(g_nx)
581+
582+
# Update node sizes based on PageRank scores
583+
for node_id, score in pagerank_scores.items():
584+
g.get_node(node_id)["size"] = (
585+
10 + score * 130
586+
) # Normalized size for visibility
587+
except Exception as e:
588+
print(f"[WARN]: failed to calculate PageRank\n { e }")
589+
555590
g.repulsion(
556591
node_distance=90,
557592
central_gravity=0.2,
@@ -561,23 +596,21 @@ def ng_draw_schema(self, line, cell=None, local_ns={}):
561596
)
562597
# g.show_buttons(filter_='physics')
563598
# return g.show("nebulagraph_draw.html", notebook=True)
564-
g_html_string = g.generate_html("nebulagraph_schema.html")
565-
with open("nebulagraph_schema.html", "w", encoding="utf-8") as f:
599+
cell_num = get_ipython().execution_count
600+
schema_html_filename = f"nebulagraph_schema_cell_{cell_num}_{space}.html"
601+
g_html_string = g.generate_html(schema_html_filename)
602+
with open(schema_html_filename, "w", encoding="utf-8") as f:
566603
f.write(g_html_string)
567604
# detect if we are in colab or not
568605
try:
569606
if "google.colab" in str(get_ipython()):
570607
display(HTML(g_html_string))
571608
else:
572-
display(
573-
IFrame(src="nebulagraph_schema.html", width="100%", height="500px")
574-
)
609+
display(IFrame(src=schema_html_filename, width="100%", height="500px"))
575610
except Exception as e:
576611
print(f"[WARN]: failed to display the graph\n { e }")
577612
try:
578-
display(
579-
IFrame(src="nebulagraph_schema.html", width="100%", height="500px")
580-
)
613+
display(IFrame(src=schema_html_filename, width="100%", height="500px"))
581614
except Exception as e:
582615
print(f"[WARN]: failed to display the graph\n { e }")
583616

@@ -590,26 +623,36 @@ def render_pd_item(self, g, g_nx, item):
590623
if isinstance(item, Node):
591624
node_id = str(item.get_id().cast())
592625
tags = item.tags() # list of strings
626+
tags_str = tags[0] if len(tags) == 1 else ",".join(tags)
593627
props_raw = dict()
594628
for tag in tags:
595629
props_raw.update(item.properties(tag))
596630
props = {
597631
k: str(v.cast()) if hasattr(v, "cast") else str(v)
598632
for k, v in props_raw.items()
599633
}
634+
# populating empty and null properties
635+
props = {
636+
k: v for k, v in props.items() if v not in ["__NULL__", "__EMPTY__"]
637+
}
600638

601639
if "name" in props:
602640
label = props["name"]
603641
else:
604-
label = f"tag: {tags}, id: {node_id}"
642+
if is_human_readable(node_id):
643+
label = f"tag: {tags_str},\nid: {node_id}"
644+
else:
645+
label = f"tag: {tags_str},\nid: {node_id[:3]}..{node_id[-3:]}"
605646
for k in props:
606647
if "name" in str(k).lower():
607648
label = props[k]
608649
break
650+
609651
if "id" not in props:
610652
props["id"] = node_id
653+
title = "\n".join([f"{k}: {v}" for k, v in props.items()])
611654

612-
g.add_node(node_id, label=label, title=str(props), color=get_color(node_id))
655+
g.add_node(node_id, label=label, title=title, color=get_color(node_id))
613656

614657
# networkx
615658
if len(tags) > 1:
@@ -627,19 +670,33 @@ def render_pd_item(self, g, g_nx, item):
627670
}
628671
if rank != 0:
629672
props.update({"rank": rank})
673+
# populating empty and null properties
674+
props = {
675+
k: v for k, v in props.items() if v not in ["__NULL__", "__EMPTY__"]
676+
}
630677
# ensure start and end vertex exist in graph
631678
if not src_id in g.node_ids:
679+
label = (
680+
f"tag: {src_id[:3]}..{src_id[-3:]}"
681+
if not is_human_readable(src_id)
682+
else src_id
683+
)
632684
g.add_node(
633685
src_id,
634-
label=str(src_id),
635-
title=str(src_id),
686+
label=label,
687+
title=src_id,
636688
color=get_color(src_id),
637689
)
638690
if not dst_id in g.node_ids:
691+
label = (
692+
f"tag: {dst_id[:3]}..{dst_id[-3:]}"
693+
if not is_human_readable(dst_id)
694+
else dst_id
695+
)
639696
g.add_node(
640697
dst_id,
641-
label=str(dst_id),
642-
title=str(dst_id),
698+
label=label,
699+
title=dst_id,
643700
color=get_color(dst_id),
644701
)
645702
props_str_list: List[str] = []
@@ -650,11 +707,19 @@ def render_pd_item(self, g, g_nx, item):
650707
props_str = "\n".join(props_str_list)
651708

652709
label = f"{props_str}\n{edge_name}" if props else edge_name
710+
if props:
711+
title = (
712+
"{\n "
713+
+ "\n ".join([f"{k}: {v}" for k, v in props.items()])
714+
+ "\n}"
715+
)
716+
else:
717+
title = edge_name
653718
g.add_edge(
654719
src_id,
655720
dst_id,
656721
label=label,
657-
title=str(props),
722+
title=title,
658723
weight=props.get("rank", 0),
659724
)
660725
# networkx

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="jupyter_nebulagraph",
8-
version="0.12.3",
8+
version="0.12.4",
99
author="Wey Gu",
1010
author_email="[email protected]",
1111
description="Jupyter extension for NebulaGraph",

setup_ipython.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="ipython-ngql",
8-
version="0.12.3",
8+
version="0.12.4",
99
author="Wey Gu",
1010
author_email="[email protected]",
1111
description="Jupyter extension for NebulaGraph",

0 commit comments

Comments
 (0)