From 72cb5acf232337ae4224f50752cb50981ba2bc00 Mon Sep 17 00:00:00 2001 From: Adam Schill Collberg Date: Fri, 13 Jun 2025 14:43:52 +0200 Subject: [PATCH 1/2] Set labels as caption in `from_gds` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Florentin Dörre --- changelog.md | 3 ++- python-wrapper/src/neo4j_viz/gds.py | 3 +++ python-wrapper/tests/test_gds.py | 27 +++++++++++++++++---------- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index d0a5590b..547eb770 100644 --- a/changelog.md +++ b/changelog.md @@ -3,7 +3,8 @@ ## Breaking changes -* The `from_gds` methods now fetches all node properties of a given GDS projection by default, instead of none. +* The `from_gds` method now fetches all node properties of a given GDS projection by default, instead of none. +* The `from_gds` now adds node labels as captions for nodes. ## New features diff --git a/python-wrapper/src/neo4j_viz/gds.py b/python-wrapper/src/neo4j_viz/gds.py index 9bdbebd4..e1ec024b 100644 --- a/python-wrapper/src/neo4j_viz/gds.py +++ b/python-wrapper/src/neo4j_viz/gds.py @@ -111,6 +111,9 @@ def from_gds( node_df = node_props_df.merge(node_labels_df, on="id") + if "caption" not in actual_node_properties: + node_df["caption"] = node_df["labels"].astype(str) + rel_df = _rel_df(gds, G) rel_df.rename(columns={"sourceNodeId": "source", "targetNodeId": "target"}, inplace=True) diff --git a/python-wrapper/tests/test_gds.py b/python-wrapper/tests/test_gds.py index 0b213851..ff5da5e3 100644 --- a/python-wrapper/tests/test_gds.py +++ b/python-wrapper/tests/test_gds.py @@ -8,7 +8,7 @@ @pytest.mark.requires_neo4j_and_gds -def test_from_gds_integration(gds: Any) -> None: +def test_from_gds_integration_size(gds: Any) -> None: from neo4j_viz.gds import from_gds nodes = pd.DataFrame( @@ -41,9 +41,14 @@ def test_from_gds_integration(gds: Any) -> None: assert len(VG.nodes) == 3 assert sorted(VG.nodes, key=lambda x: x.id) == [ - Node(id=0, size=float(1337), properties=dict(labels=["A"], component=float(1), size=0.1)), - Node(id=1, size=float(42), properties=dict(labels=["C"], component=float(4), size=0.2)), - Node(id=2, size=float(3.14), properties=dict(labels=["A", "B"], component=float(2), size=0.3)), + Node(id=0, size=float(1337), caption="['A']", properties=dict(labels=["A"], component=float(1), size=0.1)), + Node(id=1, size=float(42), caption="['C']", properties=dict(labels=["C"], component=float(4), size=0.2)), + Node( + id=2, + size=float(3.14), + caption="['A', 'B']", + properties=dict(labels=["A", "B"], component=float(2), size=0.3), + ), ] assert len(VG.relationships) == 3 @@ -93,9 +98,11 @@ def test_from_gds_integration_all_properties(gds: Any) -> None: assert len(VG.nodes) == 3 assert sorted(VG.nodes, key=lambda x: x.id) == [ - Node(id=0, size=0.1, properties=dict(labels=["A"], component=float(1), score=1337.0)), - Node(id=1, size=0.2, properties=dict(labels=["C"], component=float(4), score=42.0)), - Node(id=2, size=0.3, properties=dict(labels=["A", "B"], component=float(2), score=3.14)), + Node(id=0, size=0.1, caption="['A']", properties=dict(labels=["A"], component=float(1), score=1337.0)), + Node(id=1, size=0.2, caption="['C']", properties=dict(labels=["C"], component=float(4), score=42.0)), + Node( + id=2, size=0.3, caption="['A', 'B']", properties=dict(labels=["A", "B"], component=float(2), score=3.14) + ), ] assert len(VG.relationships) == 3 @@ -176,9 +183,9 @@ def test_from_gds_mocked(mocker: MockerFixture) -> None: assert len(VG.nodes) == 3 assert sorted(VG.nodes, key=lambda x: x.id) == [ - Node(id=0, size=float(1337), properties=dict(labels=["A"], component=float(1))), - Node(id=1, size=float(42), properties=dict(labels=["C"], component=float(4))), - Node(id=2, size=float(3.14), properties=dict(labels=["A", "B"], component=float(2))), + Node(id=0, caption="['A']", size=float(1337), properties=dict(labels=["A"], component=float(1))), + Node(id=1, caption="['C']", size=float(42), properties=dict(labels=["C"], component=float(4))), + Node(id=2, caption="['A', 'B']", size=float(3.14), properties=dict(labels=["A", "B"], component=float(2))), ] assert len(VG.relationships) == 3 From 2b6fe4406ef99dfaaabe55421033036ffd04290e Mon Sep 17 00:00:00 2001 From: Adam Schill Collberg Date: Fri, 13 Jun 2025 14:48:57 +0200 Subject: [PATCH 2/2] Update GDS notebook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Florentin Dörre --- examples/gds-example.ipynb | 135 +++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 66 deletions(-) diff --git a/examples/gds-example.ipynb b/examples/gds-example.ipynb index 5a3aecf2..08d76029 100644 --- a/examples/gds-example.ipynb +++ b/examples/gds-example.ipynb @@ -196,27 +196,27 @@ "}\n", "\n", " \n", - "
\n", + "
\n", "
\n", - " \n", - " \n", - " \n", "
\n", - "
\n", + "
\n", "
\n", "\n", " \n", @@ -258,7 +258,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Adding captions" + "### Changing captions\n", + "\n", + "We can also change the node captions, if we want to see something other that the node labels.\n", + "For this dataset it might make sense to caption by scientific subject." ] }, { @@ -340,27 +343,27 @@ "}\n", "\n", " \n", - "
\n", + "
\n", "
\n", - " \n", - " \n", - " \n", "
\n", - "
\n", + "
\n", "
\n", "\n", " \n", @@ -486,27 +489,27 @@ "}\n", "\n", " \n", - "
\n", + "
\n", "
\n", - " \n", - " \n", - " \n", "
\n", - "
\n", + "
\n", "
\n", "\n", " \n", @@ -623,27 +626,27 @@ "}\n", "\n", " \n", - "
\n", + "
\n", "
\n", - " \n", - " \n", - " \n", "
\n", - "
\n", + "
\n", "
\n", "\n", " \n", @@ -790,27 +793,27 @@ "}\n", "\n", " \n", - "
\n", + "
\n", "
\n", - " \n", - " \n", - " \n", "
\n", - "
\n", + "
\n", "
\n", "\n", " \n", @@ -932,27 +935,27 @@ "}\n", "\n", " \n", - "
\n", + "
\n", "
\n", - " \n", - " \n", - " \n", "
\n", - "
\n", + "
\n", "
\n", "\n", "