diff --git a/.github/workflows/gds-integration-tests.yml b/.github/workflows/gds-integration-tests.yml index 53a94b86..69a40f31 100644 --- a/.github/workflows/gds-integration-tests.yml +++ b/.github/workflows/gds-integration-tests.yml @@ -20,6 +20,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] + gds-version: ["1.22", "2.0.0a1"] defaults: run: working-directory: python-wrapper @@ -33,11 +34,12 @@ jobs: with: python-version: "3.11" enable-cache: true - - run: uv sync --group dev --extra pandas --extra neo4j --extra gds + - name: Install just + uses: extractions/setup-just@v2 - name: Run tests env: AURA_API_CLIENT_ID: 4V1HYCYEeoU4dSxThKnBeLvE2U4hSphx AURA_API_CLIENT_SECRET: ${{ secrets.AURA_API_CLIENT_SECRET }} AURA_API_PROJECT_ID: 3f8df5e7-4800-4d4f-ad1d-2d044dfd587c - run: uv run pytest tests/ --include-neo4j-and-gds + run: just py-ci-test-gds "${{ matrix.gds-version }}" diff --git a/changelog.md b/changelog.md index 7db9a34d..097f1d81 100644 --- a/changelog.md +++ b/changelog.md @@ -1,21 +1,14 @@ -# Changes in 1.5.0 +# Changes ## Breaking changes ## New features -* Add `GraphWidget` methods to change render options in place without re-rendering: `set_layout`, `set_zoom`, `set_pan`, `set_renderer`, and `set_show_layout_button` -* Add `GraphWidget` methods to change styling in place without re-rendering such as `color_relationships` +* Added the ability to set the selection mode (gesture) of the `GraphWidget` from Python, via the `selection_mode` render option or the `GraphWidget.set_selection_mode` method. +* Added the `GraphWidget.selected` trait to read back the IDs of the nodes and relationships selected in the widget UI. Use the `GraphWidget.on_selection_change` method (or `widget.observe`) to react to selection changes. ## Bug fixes -* Warn when relationships reference node ids that are not in the graph. It is configurable via the `on_dangling` parameter (`"warn"` (default), `"error"`, or `"none"`) on `render`, `render_widget`, and `GraphWidget.add_data` - ## Improvements -* Support Python 3.14 -* Support Aura Graph Analytics -* Support `gds.v2` endpoints -* Use typed options field in `GraphWidget` - ## Other changes diff --git a/docs/antora/modules/ROOT/pages/customizing.adoc b/docs/antora/modules/ROOT/pages/customizing.adoc index af7737d0..e4e6502c 100644 --- a/docs/antora/modules/ROOT/pages/customizing.adoc +++ b/docs/antora/modules/ROOT/pages/customizing.adoc @@ -233,6 +233,38 @@ In the following example, we pin the node with ID 1337 and unpin the node with I VG.toggle_nodes_pinned(1337: True, 42: False)}) ---- +== Reading the selection + +When a graph is rendered as an interactive widget via +link:{api-docs-uri}/visualization-graph/#neo4j_viz.VisualizationGraph.render_widget[`neo4j_viz.VisualizationGraph.render_widget()`], +you can read back which nodes and relationships the user has selected in the UI (using single, box, or lasso selection). + +The widget exposes the `selected` attribute, a typed link:{api-docs-uri}/widget[`GraphSelection`] with `nodeIds` and +`relationshipIds` fields holding the IDs of the currently selected nodes and relationships. +Note that the IDs are strings, so match them against `str(node.id)` / `str(relationship.id)` to recover the +link:{api-docs-uri}/node[Node] and link:{api-docs-uri}/relationship[Relationship] objects. + +To react to selection changes interactively, register a callback with `widget.on_selection_change(...)`. This is a +convenience wrapper around `widget.observe(..., names=["selected"])`: the callback runs every time the user selects +nodes or relationships in the widget, and receives the new `GraphSelection` directly. + +[source, python] +---- +# VG is a VisualizationGraph object +widget = VG.render_widget() + + +def on_selection_change(selection): + selected_nodes = [node for node in widget.nodes if str(node.id) in set(selection.nodeIds)] + # ... act on the selected nodes, e.g. add data or update other widgets + + +widget.on_selection_change(on_selection_change) +---- + +`on_selection_change` returns the registered handler, which you can pass to `widget.unobserve(handler, names=["selected"])` +to stop reacting. You can also read `widget.selected` directly at any point for the current selection. + == Direct modification of nodes and relationships Nodes and relationships can also be modified directly by accessing the `nodes` and `relationships` fields of an diff --git a/docs/source/api-reference/render_options.rst b/docs/source/api-reference/render_options.rst index c49e98fe..56e5eaf7 100644 --- a/docs/source/api-reference/render_options.rst +++ b/docs/source/api-reference/render_options.rst @@ -20,3 +20,6 @@ .. autoenum:: neo4j_viz.Renderer :members: + +.. autoenum:: neo4j_viz.SelectionMode + :members: diff --git a/docs/source/api-reference/widget.rst b/docs/source/api-reference/widget.rst index 8ec6510f..2c2fb220 100644 --- a/docs/source/api-reference/widget.rst +++ b/docs/source/api-reference/widget.rst @@ -1,2 +1,6 @@ .. autoclass:: neo4j_viz.GraphWidget :members: + +.. autoclass:: neo4j_viz.GraphSelection + :members: + :exclude-members: model_config diff --git a/examples/getting-started.ipynb b/examples/getting-started.ipynb index 7a012a5a..6a7a506c 100644 --- a/examples/getting-started.ipynb +++ b/examples/getting-started.ipynb @@ -20,13 +20,13 @@ "The only mandatory fields for a node are the \"id\", and \"source\" and \"target\" for a relationship.\n", "But the other fields can optionally be used to customize the appearance of the nodes and relationships in the visualization.\n", "\n", - "Lastly we create a `VisualizationGraph` object with the nodes and relationships we created, and call its `render` method to display the graph.\n" + "Lastly we create a `VisualizationGraph` object with the nodes and relationships we created, and call its `render_widget` method to display the graph as an interactive widget." ] }, { "cell_type": "code", "execution_count": 1, - "id": "801d0bed", + "id": "2ec305c1", "metadata": { "tags": [ "preserve-output" @@ -35,1615 +35,13 @@ "outputs": [ { "data": { - "text/html": [ - "\n", - "\n", - "
\n", - " \n", - " \n", - "