Skip to content

Commit 25c27ec

Browse files
authored
Merge pull request #64 from neo4j/coordinate-layout
Add COORDINATE layout
2 parents 28927b4 + f5decd8 commit 25c27ec

File tree

7 files changed

+40
-10
lines changed

7 files changed

+40
-10
lines changed

js-applet/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NVL } from '@neo4j-nvl/base'
1+
import { FreeLayoutType, NVL } from '@neo4j-nvl/base'
22
import type { Node, NvlOptions, Relationship } from '@neo4j-nvl/base'
33
import { DragNodeInteraction, PanInteraction, ZoomInteraction } from '@neo4j-nvl/interaction-handlers'
44

@@ -22,6 +22,10 @@ class PyNVL {
2222
this.zoomInteraction = new ZoomInteraction(this.nvl)
2323
this.panInteraction = new PanInteraction(this.nvl)
2424
this.dragNodeInteraction = new DragNodeInteraction(this.nvl)
25+
26+
if (options.layout === FreeLayoutType) {
27+
this.nvl.setNodePositions(nvlNodes, false)
28+
}
2529
}
2630
}
2731

python-wrapper/src/neo4j_viz/node.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class Node(BaseModel, extra="allow"):
3434
size: Optional[RealNumber] = Field(None, ge=0, description="The size of the node as radius in pixel")
3535
color: Optional[ColorType] = Field(None, description="The color of the node")
3636
pinned: Optional[bool] = Field(None, description="Whether the node is pinned in the visualization")
37+
x: Optional[RealNumber] = Field(None, description="The x-coordinate of the node")
38+
y: Optional[RealNumber] = Field(None, description="The y-coordinate of the node")
3739

3840
@field_serializer("color")
3941
def serialize_color(self, color: Color) -> str:

python-wrapper/src/neo4j_viz/options.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ class Layout(str, Enum):
1717
FORCE_DIRECTED = "forcedirected"
1818
HIERARCHICAL = "hierarchical"
1919
GRID = "grid"
20-
# TODO expose free layout for X,Y based
20+
COORDINATE = "free"
21+
""""
22+
The coordinate layout sets the position of each node based on the `x` and `y` properties of the node.
23+
"""
2124

2225

2326
class Renderer(str, Enum):

python-wrapper/src/neo4j_viz/resources/nvl_entrypoint/base.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python-wrapper/tests/test_node.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ def test_nodes_with_all_options() -> None:
1212
color="#FF0000",
1313
size=10,
1414
pinned=True,
15+
x=1,
16+
y=10,
1517
)
1618

1719
assert node.to_dict() == {
@@ -22,6 +24,8 @@ def test_nodes_with_all_options() -> None:
2224
"color": "#ff0000",
2325
"size": 10,
2426
"pinned": True,
27+
"x": 1,
28+
"y": 10,
2529
}
2630

2731

@@ -66,3 +70,8 @@ def test_id_aliases(alias: str) -> None:
6670
assert node.to_dict() == {
6771
"id": "1",
6872
}
73+
74+
75+
def test_node_validation() -> None:
76+
with pytest.raises(ValueError, match="Input should be a valid integer, unable to parse string as an integer"):
77+
Node(id="1", x="not a number")

python-wrapper/tests/test_render.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,20 @@
1212
"default": {},
1313
"force layout": {"layout": Layout.FORCE_DIRECTED},
1414
"grid layout": {"layout": Layout.GRID},
15+
"coordinate layout": {"layout": Layout.COORDINATE},
1516
}
1617

1718

1819
@pytest.mark.parametrize("render_option", render_cases.values(), ids=render_cases.keys())
1920
def test_basic_render(render_option: dict[str, Any], tmp_path: Path) -> None:
2021
nodes = [
21-
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:0", caption="Person"),
22-
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:6", caption="Product"),
23-
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:11", caption="Product", pinned=True),
24-
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:12", caption="Product"),
25-
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:1", caption="Person"),
26-
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:7", caption="Product"),
27-
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:8", caption="Product"),
22+
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:0", caption="Person", x=1, y=10),
23+
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:6", caption="Product", x=2, y=15),
24+
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:11", caption="Product", x=3, pinned=True),
25+
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:12", caption="Product", x=4),
26+
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:1", caption="Person", x=5),
27+
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:7", caption="Product", x=6),
28+
Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:8", caption="Product", x=7),
2829
]
2930
relationships = [
3031
Relationship(

scripts/build_js_applet.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
GIT_ROOT=$(git rev-parse --show-toplevel)
2+
3+
set -o errexit
4+
set -o nounset
5+
set -o pipefail
6+
7+
(
8+
cd "${GIT_ROOT}/js-applet"
9+
yarn
10+
yarn build
11+
)

0 commit comments

Comments
 (0)