diff --git a/.github/workflows/gds-integration-tests.yml b/.github/workflows/gds-integration-tests.yml
index 21034a7..fb51388 100644
--- a/.github/workflows/gds-integration-tests.yml
+++ b/.github/workflows/gds-integration-tests.yml
@@ -39,5 +39,5 @@ jobs:
env:
AURA_API_CLIENT_ID: 4V1HYCYEeoU4dSxThKnBeLvE2U4hSphx
AURA_API_CLIENT_SECRET: ${{ secrets.AURA_API_CLIENT_SECRET }}
- AURA_API_TENANT_ID: eee7ec28-6b1a-5286-8e3a-3362cc1c4c78
+ AURA_API_TENANT_ID: 3f8df5e7-4800-4d4f-ad1d-2d044dfd587c
run: uv run pytest tests/ --include-neo4j-and-gds
diff --git a/changelog.md b/changelog.md
index 2b09d1e..500e1c1 100644
--- a/changelog.md
+++ b/changelog.md
@@ -6,12 +6,9 @@
## Bug fixes
-- Fixed a bug in displaying the `Download`, `Selection` and `Layout` buttons, which was introduced in 1.2.0.
-
## Improvements
-- Support `neo4j.EagerResult` in the `from_neo4j` integration which is the default return type by `neo4j.Driver.execute_query()`.
-- Detect light/dark theme changes and adapt rendering unless theme was explicitly set. Before the theme would only be checked on the first render.
-
+* Support Aura Graph Analytics
+* Support `gds.v2` endpoints
## Other changes
diff --git a/examples/gds-example.ipynb b/examples/gds-example.ipynb
index 29b1387..cd7ab33 100644
--- a/examples/gds-example.ipynb
+++ b/examples/gds-example.ipynb
@@ -2,6 +2,7 @@
"cells": [
{
"cell_type": "markdown",
+ "id": "133e0a86",
"metadata": {},
"source": [
"# Visualizing Neo4j Graph Data Science (GDS) Graphs"
@@ -10,54 +11,112 @@
{
"cell_type": "code",
"execution_count": null,
+ "id": "eab42b4e",
"metadata": {},
"outputs": [],
"source": [
"%pip install graphdatascience\n",
- "%pip install matplotlib"
+ "%pip install matplotlib\n",
+ "%pip install python-dotenv"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1dde3aae",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import dotenv\n",
+ "\n",
+ "dotenv.load_dotenv()"
]
},
{
"cell_type": "markdown",
+ "id": "d9daded3",
"metadata": {},
"source": [
- "## Setup GDS graph"
+ "## Setup GDS graph\n",
+ "\n",
+ "To use GDS, you can either use GDS as a plugin or Aura Graph Analytics.\n",
+ "In the following, you can choose:\n",
+ "\n",
+ " * Provide Aura API credentials and and use Aura Graph Analytics.\n",
+ " * Use Neo4j + GDS Plugin.\n",
+ "\n",
+ "For more information, see the [GDS documentation](https://neo4j.com/docs/graph-data-science/current/installation/)."
]
},
{
"cell_type": "code",
"execution_count": null,
+ "id": "9ca9a1de",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
+ "from graphdatascience.session import (\n",
+ " GdsSessions,\n",
+ " DbmsConnectionInfo,\n",
+ " AuraAPICredentials,\n",
+ " SessionMemory,\n",
+ ")\n",
"from graphdatascience import GraphDataScience\n",
"\n",
"# Get Neo4j DB URI, credentials and name from environment if applicable\n",
- "NEO4J_URI = os.environ.get(\"NEO4J_URI\", \"bolt://localhost:7687\")\n",
- "NEO4J_AUTH = (\"neo4j\", None)\n",
- "NEO4J_DB = os.environ.get(\"NEO4J_DB\", \"neo4j\")\n",
- "if os.environ.get(\"NEO4J_USER\") and os.environ.get(\"NEO4J_PASSWORD\"):\n",
- " NEO4J_AUTH = (\n",
- " os.environ.get(\"NEO4J_USER\"),\n",
- " os.environ.get(\"NEO4J_PASSWORD\"),\n",
+ "db_connection = DbmsConnectionInfo(\n",
+ " aura_instance_id=os.environ.get(\"AURA_INSTANCEID\"),\n",
+ " username=os.environ.get(\"NEO4J_USERNAME\", \"neo4j\"),\n",
+ " password=os.environ.get(\"NEO4J_PASSWORD\"),\n",
+ " uri=os.environ[\"NEO4J_URI\"],\n",
+ ")\n",
+ "\n",
+ "session_name = \"neo4j-viz-gds-example\"\n",
+ "if os.environ.get(\"AURA_API_CLIENT_ID\"):\n",
+ " # Use Aura Graph Analytics\n",
+ " sessions = GdsSessions(\n",
+ " api_credentials=AuraAPICredentials(\n",
+ " client_id=os.environ[\"AURA_API_CLIENT_ID\"],\n",
+ " client_secret=os.environ[\"AURA_API_CLIENT_SECRET\"],\n",
+ " project_id=os.environ.get(\"AURA_API_PROJECT_ID\"),\n",
+ " )\n",
+ " )\n",
+ " gds = sessions.get_or_create(\n",
+ " session_name=session_name,\n",
+ " memory=SessionMemory.m_2GB,\n",
+ " db_connection=db_connection,\n",
" )\n",
- "gds = GraphDataScience(NEO4J_URI, auth=NEO4J_AUTH, database=NEO4J_DB)"
+ "else:\n",
+ " # Use GDS Plugin\n",
+ " sessions = None\n",
+ " gds = GraphDataScience(\n",
+ " endpoint=db_connection.get_uri(),\n",
+ " auth=(db_connection.username, db_connection.password),\n",
+ " )"
]
},
{
"cell_type": "code",
"execution_count": null,
+ "id": "735411fa",
"metadata": {},
"outputs": [],
"source": [
"G = gds.graph.load_cora(graph_name=\"cora\")"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "8cbc843a",
+ "metadata": {},
+ "source": []
+ },
{
"cell_type": "code",
"execution_count": null,
+ "id": "35a65700",
"metadata": {},
"outputs": [],
"source": [
@@ -71,6 +130,7 @@
},
{
"cell_type": "markdown",
+ "id": "cde09804",
"metadata": {},
"source": [
"## Visualization"
@@ -79,1648 +139,32 @@
{
"cell_type": "code",
"execution_count": null,
+ "id": "cab5ffab",
"metadata": {},
"outputs": [],
"source": [
"from neo4j_viz.gds import from_gds\n",
"\n",
- "VG = from_gds(gds, G, max_node_count=500)\n",
- "str(VG)"
+ "VG = from_gds(\n",
+ " gds,\n",
+ " G,\n",
+ " max_node_count=100,\n",
+ ")"
]
},
{
"cell_type": "code",
- "execution_count": 6,
- "metadata": {
- "tags": [
- "preserve-output"
- ]
- },
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " neo4j-viz\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- "\n"
- ],
- "text/plain": [
- ""
- ]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "execution_count": null,
+ "id": "9f37e34f",
+ "metadata": {},
+ "outputs": [],
"source": [
- "VG.render(theme=\"auto\")"
+ "VG.render()"
]
},
{
"cell_type": "markdown",
+ "id": "47f4b968",
"metadata": {},
"source": [
"### Changing captions\n",
@@ -1732,6 +176,7 @@
{
"cell_type": "code",
"execution_count": null,
+ "id": "ceb601eb",
"metadata": {},
"outputs": [],
"source": [
@@ -1742,9 +187,8 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "tags": []
- },
+ "id": "1ad40c84",
+ "metadata": {},
"outputs": [],
"source": [
"VG.render()"
@@ -1752,6 +196,7 @@
},
{
"cell_type": "markdown",
+ "id": "a752ad45",
"metadata": {},
"source": [
"## Sizing the nodes\n",
@@ -1762,16 +207,17 @@
{
"cell_type": "code",
"execution_count": null,
+ "id": "4e6f0c10",
"metadata": {},
"outputs": [],
"source": [
"VG.resize_nodes(property=\"pagerank\")\n",
- "VG.color_nodes(property=\"componentId\")\n",
"VG.render()"
]
},
{
"cell_type": "markdown",
+ "id": "c36a218b",
"metadata": {},
"source": [
"### Coloring"
@@ -1779,6 +225,7 @@
},
{
"cell_type": "markdown",
+ "id": "40665ee4",
"metadata": {},
"source": [
"There are two main ways of coloring the nodes of a graph:\n",
@@ -1792,17 +239,17 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "tags": []
- },
+ "id": "25afe567",
+ "metadata": {},
"outputs": [],
"source": [
- "VG.color_nodes(property=\"componentId\")\n",
+ "VG.color_nodes(property=\"subject\")\n",
"VG.render()"
]
},
{
"cell_type": "markdown",
+ "id": "dbe78a8c",
"metadata": {},
"source": [
"Now, let us color by our continuous node field \"size\" that we computed above with PageRank, again using the default colors.\n",
@@ -1813,9 +260,8 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "tags": []
- },
+ "id": "931a3465",
+ "metadata": {},
"outputs": [],
"source": [
"from neo4j_viz.colors import ColorSpace\n",
@@ -1826,6 +272,7 @@
},
{
"cell_type": "markdown",
+ "id": "07a51bda",
"metadata": {},
"source": [
"#### Custom coloring\n",
@@ -1837,6 +284,7 @@
{
"cell_type": "code",
"execution_count": null,
+ "id": "583b37b7",
"metadata": {},
"outputs": [],
"source": [
@@ -1846,6 +294,7 @@
{
"cell_type": "code",
"execution_count": null,
+ "id": "fa2a8d32",
"metadata": {},
"outputs": [],
"source": [
@@ -1863,1637 +312,17 @@
},
{
"cell_type": "code",
- "execution_count": 14,
- "metadata": {
- "tags": [
- "preserve-output"
- ]
- },
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " neo4j-viz\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- "\n"
- ],
- "text/plain": [
- ""
- ]
- },
- "execution_count": 14,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "execution_count": null,
+ "id": "dd7b6944",
+ "metadata": {},
+ "outputs": [],
"source": [
"VG.render()"
]
},
{
"cell_type": "markdown",
+ "id": "e163e522",
"metadata": {},
"source": [
"### Render options\n",
@@ -3509,1639 +338,19 @@
},
{
"cell_type": "code",
- "execution_count": 15,
- "metadata": {
- "tags": [
- "preserve-output"
- ]
- },
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " neo4j-viz\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- "\n"
- ],
- "text/plain": [
- ""
- ]
- },
- "execution_count": 15,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "execution_count": null,
+ "id": "02d2e7ce",
+ "metadata": {},
+ "outputs": [],
"source": [
"from neo4j_viz import Layout\n",
"\n",
- "VG.render(layout=Layout.CIRCULAR, initial_zoom=0.15)"
+ "VG.render(layout=Layout.CIRCULAR, initial_zoom=0.5)"
]
},
{
"cell_type": "markdown",
+ "id": "c325ea54",
"metadata": {},
"source": [
"## Saving the visualization"
@@ -5150,6 +359,7 @@
{
"cell_type": "code",
"execution_count": null,
+ "id": "d505dfb9",
"metadata": {},
"outputs": [],
"source": [
@@ -5164,6 +374,7 @@
},
{
"cell_type": "markdown",
+ "id": "71006712",
"metadata": {},
"source": [
"## Cleanup\n",
@@ -5174,15 +385,23 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "tags": [
- "teardown"
- ]
- },
+ "id": "b2197a5f",
+ "metadata": {},
"outputs": [],
"source": [
"gds.graph.drop(\"cora\")"
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "74468c43",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if sessions:\n",
+ " sessions.delete(session_name=session_name)"
+ ]
}
],
"metadata": {
@@ -5191,5 +410,5 @@
}
},
"nbformat": 4,
- "nbformat_minor": 4
+ "nbformat_minor": 5
}
diff --git a/examples/neo4j-example.ipynb b/examples/neo4j-example.ipynb
index 0fb1310..2e8da54 100644
--- a/examples/neo4j-example.ipynb
+++ b/examples/neo4j-example.ipynb
@@ -24,7 +24,8 @@
"outputs": [],
"source": [
"%pip install neo4j\n",
- "%pip install neo4j-viz"
+ "%pip install neo4j-viz\n",
+ "%pip install python-dotenv"
]
},
{
@@ -43,12 +44,13 @@
"outputs": [],
"source": [
"import os\n",
+ "import dotenv\n",
+ "\n",
+ "dotenv.load_dotenv()\n",
"\n",
- "URI = os.environ.get(\"NEO4J_URI\", \"bolt://localhost:7687\")\n",
"\n",
- "auth = None\n",
- "if os.environ.get(\"NEO4J_USER\") and os.environ.get(\"NEO4J_PASSWORD\"):\n",
- " auth = (os.environ.get(\"NEO4J_USER\"), os.environ.get(\"NEO4J_PASSWORD\"))"
+ "URI = os.environ.get(\"NEO4J_URI\", \"bolt://localhost:7687\")\n",
+ "auth = (os.environ.get(\"NEO4J_USERNAME\"), os.environ.get(\"NEO4J_PASSWORD\"))"
]
},
{
@@ -1775,12 +1777,12 @@
" Expected window.__NEO4J_VIZ_DATA__ to be set.
\n",
" This page should be generated by neo4j_viz's render() method.
\n",
" \n",
- " `,new Error(\"window.__NEO4J_VIZ_DATA__ is not defined\");const ypr={get(t){return x3[t]},on(){},off(){},set(){},save_changes(){}},_3=document.getElementById(\"neo4j-viz-26eaf825ab79\");if(!_3)throw new Error(\"Container element #neo4j-viz-26eaf825ab79 not found\");_3.style.width=x3.width??\"100%\";_3.style.height=x3.height??\"100vh\";mpr.render({model:ypr,el:_3});\n",
+ " `,new Error(\"window.__NEO4J_VIZ_DATA__ is not defined\");const ypr={get(t){return x3[t]},on(){},off(){},set(){},save_changes(){}},_3=document.getElementById(\"neo4j-viz-03e8377c9452\");if(!_3)throw new Error(\"Container element #neo4j-viz-03e8377c9452 not found\");_3.style.width=x3.width??\"100%\";_3.style.height=x3.height??\"100vh\";mpr.render({model:ypr,el:_3});\n",
" \n",
- " \n",
+ " \n",
"\n",
" \n",
- " \n",
+ " \n",
" \n",
"