Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .github/workflows/js-code-style.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Check JS code style

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "main" branch
push:
branches: ["main"]
pull_request:
paths:
- "js-applet/**" # js/ts code + its resources
branches: ["main"]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

permissions:
contents: read

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
js-code-style:
# The type of runner that the job will run on
runs-on: ubuntu-latest

defaults:
run:
working-directory: js-applet

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "lts/*"

- name: Install dependencies
run: yarn

- name: Lint
run: yarn lint

- name: Check formatting
run: yarn format:check
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Check code style
name: Python - Check code style

# Controls when the workflow will run
on:
Expand Down Expand Up @@ -35,5 +35,5 @@ jobs:
- run: uv venv
- run: uv sync --group dev --extra pandas --extra neo4j --extra gds --extra snowflake

- name: Check code styleyes
- name: Check code style
run: source .venv/bin/activate && cd ${GITHUB_WORKSPACE} && ./scripts/checkstyle.sh
4 changes: 1 addition & 3 deletions examples/gds-example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,7 @@
"outputs": [],
"source": [
"# Run some algorithms to use later for visualization\n",
"gds.nodeSimilarity.mutate(\n",
" G, mutateRelationshipType=\"SIMILAR\", mutateProperty=\"similarity\"\n",
")\n",
"gds.nodeSimilarity.mutate(G, mutateRelationshipType=\"SIMILAR\", mutateProperty=\"similarity\")\n",
"gds.pageRank.mutate(G, mutateProperty=\"pagerank\")\n",
"gds.louvain.mutate(G, mutateProperty=\"componentId\")"
]
Expand Down
4 changes: 1 addition & 3 deletions examples/getting-started.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,7 @@
" other_nodes = [n for n in widget.nodes if n.id != source_node.id]\n",
" target_node = random.choice(other_nodes)\n",
" widget.add_data(\n",
" relationships=Relationship(\n",
" source=source_node.id, target=target_node.id, caption=\"KNOWS\"\n",
" ),\n",
" relationships=Relationship(source=source_node.id, target=target_node.id, caption=\"KNOWS\"),\n",
" )\n",
"\n",
"\n",
Expand Down
6 changes: 5 additions & 1 deletion examples/marimo-example.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import marimo

__generated_with = "0.20.4"
__generated_with = "0.23.16"
app = marimo.App(width="full", app_title="Neo4jVizExample")


Expand Down Expand Up @@ -68,6 +68,7 @@ def _(VisualizationGraph, nodes, relationships):
VG = VisualizationGraph(nodes=nodes, relationships=relationships)
# Note, we need to pass the theme explicitly in Marimo.
widget = VG.render_widget(renderer="canvas")
widget
return VG, widget


Expand Down Expand Up @@ -101,6 +102,9 @@ def _(mo):
@app.cell
def _(VG):
# Save the visualization to a file
import os

os.makedirs("out", exist_ok=True)
with open("out/marimo_output.html", "w") as f:
print(f"{f}")
f.write(VG.render(renderer="canvas").data)
Expand Down
8 changes: 2 additions & 6 deletions examples/neo4j-example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,7 @@
" result_transformer_=Result.graph,\n",
" )\n",
"\n",
"print(\n",
" f\"Result graph has: {len(result.nodes)} nodes, {len(result.relationships)} relationships\"\n",
")"
"print(f\"Result graph has: {len(result.nodes)} nodes, {len(result.relationships)} relationships\")"
]
},
{
Expand Down Expand Up @@ -3460,9 +3458,7 @@
"outputs": [],
"source": [
"with GraphDatabase.driver(URI, auth=auth) as driver:\n",
" result = driver.execute_query(\n",
" \"MATCH (n:Person|Product) DETACH DELETE n RETURN count(n) \"\n",
" )\n",
" result = driver.execute_query(\"MATCH (n:Person|Product) DETACH DELETE n RETURN count(n) \")\n",
" print(result.summary.counters)"
]
},
Expand Down
10 changes: 2 additions & 8 deletions examples/nodes_2025_demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,7 @@
"source": [
"from neo4j import Result\n",
"\n",
"node_count = driver.execute_query(\n",
" \"MATCH (n) RETURN count(n) as count\", result_transformer_=Result.to_df\n",
").iloc[0, 0]\n",
"node_count = driver.execute_query(\"MATCH (n) RETURN count(n) as count\", result_transformer_=Result.to_df).iloc[0, 0]\n",
"if node_count == 0:\n",
" import requests\n",
"\n",
Expand Down Expand Up @@ -313,11 +311,7 @@
"outputs": [],
"source": [
"# To make sure certain nodes are always visible, we can pin them. Here we pin \"Keanu Reeves\".\n",
"pinned_nodes = {\n",
" node.id: True\n",
" for node in VG.nodes\n",
" if node.properties.get(\"name\") in [\"Keanu Reeves\"]\n",
"}\n",
"pinned_nodes = {node.id: True for node in VG.nodes if node.properties.get(\"name\") in [\"Keanu Reeves\"]}\n",
"\n",
"VG.toggle_nodes_pinned(pinned_nodes)\n",
"VG.render()"
Expand Down
6 changes: 6 additions & 0 deletions examples/ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extend = "../python-wrapper/pyproject.toml"

[lint]
# Marimo notebook cells (marimo-example.py) use a bare trailing expression as
# the cell output, which ruff flags as a useless expression.
ignore = ["B018"]
8 changes: 2 additions & 6 deletions examples/snowflake-example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,7 @@
"metadata": {},
"outputs": [],
"source": [
"session.sql(\n",
" \"CREATE OR REPLACE TABLE EXAMPLE_DB.DATA_SCHEMA.PERSONS (NODEID VARCHAR);\"\n",
").collect()\n",
"session.sql(\"CREATE OR REPLACE TABLE EXAMPLE_DB.DATA_SCHEMA.PERSONS (NODEID VARCHAR);\").collect()\n",
"\n",
"session.sql(\"\"\"\n",
"INSERT INTO EXAMPLE_DB.DATA_SCHEMA.PERSONS VALUES\n",
Expand All @@ -116,9 +114,7 @@
"metadata": {},
"outputs": [],
"source": [
"session.sql(\n",
" \"CREATE OR REPLACE TABLE EXAMPLE_DB.DATA_SCHEMA.INSTRUMENTS (NODEID VARCHAR);\"\n",
").collect()\n",
"session.sql(\"CREATE OR REPLACE TABLE EXAMPLE_DB.DATA_SCHEMA.INSTRUMENTS (NODEID VARCHAR);\").collect()\n",
"\n",
"session.sql(\"\"\"\n",
" INSERT INTO EXAMPLE_DB.DATA_SCHEMA.INSTRUMENTS VALUES\n",
Expand Down
25 changes: 6 additions & 19 deletions examples/streamlit-example.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@


st.title("Neo4j Viz Streamlit Example")
st.text(
"This is an example of how to use Streamlit with the Graph Visualization for Python library by Neo4j."
)
st.text("This is an example of how to use Streamlit with the Graph Visualization for Python library by Neo4j.")


def create_small_graph() -> VisualizationGraph:
Expand All @@ -22,10 +20,7 @@ def create_small_graph() -> VisualizationGraph:
("Carol", "Engineer"),
("Dan", "Manager"),
]
nodes = [
Node(id=str(i), caption=name, properties={"role": role})
for i, (name, role) in enumerate(people)
]
nodes = [Node(id=str(i), caption=name, properties={"role": role}) for i, (name, role) in enumerate(people)]
relationships = [
Relationship(source="0", target="1", caption="KNOWS"),
Relationship(source="1", target="2", caption="KNOWS"),
Expand All @@ -47,12 +42,8 @@ def create_small_graph() -> VisualizationGraph:
with st.sidebar:
height = st.slider("Height in pixels", 100, 2000, 600, 50)
if st.button("Add random node"):
existing_ids = [n.id for n in small_graph.nodes] + [
n.id for n in st.session_state.added_nodes
]
new_node = Node(
id=f"added-{len(st.session_state.added_nodes)}", caption="New", size=20
)
existing_ids = [n.id for n in small_graph.nodes] + [n.id for n in st.session_state.added_nodes]
new_node = Node(id=f"added-{len(st.session_state.added_nodes)}", caption="New", size=20)
st.session_state.added_nodes.append(new_node)
# Link the new node to a random existing one.
st.session_state.added_relationships.append(
Expand All @@ -75,16 +66,12 @@ def create_small_graph() -> VisualizationGraph:
# Build the widget from the small graph plus any runtime additions.
graph_widget = small_graph.render_widget(height=f"{height}px")
if st.session_state.added_nodes:
graph_widget.add_data(
st.session_state.added_nodes, st.session_state.added_relationships
)
graph_widget.add_data(st.session_state.added_nodes, st.session_state.added_relationships)

display_widget(graph_widget, key="small-graph-widget")

selection = graph_widget.selected
st.write(
f"Selected {len(selection.nodeIds)} node(s) and {len(selection.relationshipIds)} relationship(s)."
)
st.write(f"Selected {len(selection.nodeIds)} node(s) and {len(selection.relationshipIds)} relationship(s).")
if selection.nodeIds:
st.write("Selected node IDs:", selection.nodeIds)

Expand Down
9 changes: 9 additions & 0 deletions js-applet/.oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["react", "typescript", "import", "jsx-a11y"],
"env": {
"browser": true,
"node": true
},
"ignorePatterns": ["node_modules/**", "dist/**", "coverage/**"]
}
54 changes: 30 additions & 24 deletions js-applet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,39 @@
"build:html": "vite build --config vite.config.html.ts",
"build:streamlit": "vite build --config vite.config.streamlit.ts",
"test": "vitest run",
"test:watch": "vitest"
"test:watch": "vitest",
"lint": "oxlint .",
"lint:fix": "oxlint . --fix",
"format": "oxfmt .",
"format:check": "oxfmt --check ."
},
"dependencies": {
"@anywidget/react": "^0.2.2",
"@neo4j-ndl/base": "4.17.4",
"@neo4j-ndl/react": "4.18.4",
"@neo4j-ndl/react-graph": "2.1.3",
"@neo4j-nvl/base": "^1.2.1",
"@neo4j-nvl/interaction-handlers": "^1.2.1",
"@neo4j-nvl/react": "^1.2.1",
"@tanstack/react-table": "^8.21.3",
"react": "^19.2.8",
"react-dom": "^19.2.8"
},
"devDependencies": {
"@anywidget/vite": "^0.2.2",
"@anywidget/vite": "^0.3.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/react": "^16.3.2",
"@types/node": "^25.2.3",
"@types/react": "^19.2.13",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^4.5.2",
"concurrently": "^9.2.1",
"jsdom": "^29.1.1",
"typescript": "5.9.3",
"vite": "^6.3.5",
"vite-plugin-singlefile": "^2.3.0",
"vitest": "^4.0.0"
},
"dependencies": {
"@anywidget/react": "^0.2.0",
"@neo4j-ndl/base": "4.12.0",
"@neo4j-ndl/react": "4.12.0",
"@neo4j-ndl/react-graph": "1.3.34",
"@neo4j-nvl/base": "^1.1.0",
"@neo4j-nvl/interaction-handlers": "^1.1.0",
"@neo4j-nvl/react": "^1.1.0",
"@tanstack/react-table": "^8.20.5",
"react": "^19.2.4",
"react-dom": "^19.2.4"
"@types/node": "^26.2.0",
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.4",
"@vitejs/plugin-react": "^6.0.5",
"concurrently": "^10.0.4",
"jsdom": "^30.0.1",
"oxfmt": "0.36.0",
"oxlint": "1.51.0",
"typescript": "7.0.2",
"vite": "^8.2.1",
"vite-plugin-singlefile": "^2.3.3",
"vitest": "^4.1.10"
}
}
4 changes: 1 addition & 3 deletions js-applet/src/data-transforms.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,7 @@ describe("data-transforms", () => {
});

it("should respect exting labels", () => {
const nodes: SerializedNode[] = [
{ id: "35", properties: { labels: ["User"] } },
];
const nodes: SerializedNode[] = [{ id: "35", properties: { labels: ["User"] } }];

const result = transformNodes(nodes);
expect(result).toHaveLength(1);
Expand Down
Loading