neo4j-viz 0.2.5__tar.gz → 0.2.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/PKG-INFO +1 -1
  2. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/pyproject.toml +1 -1
  3. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/visualization_graph.py +27 -3
  4. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz.egg-info/PKG-INFO +1 -1
  5. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/tests/test_colors.py +83 -0
  6. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/README.md +0 -0
  7. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/setup.cfg +0 -0
  8. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/__init__.py +0 -0
  9. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/colors.py +0 -0
  10. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/gds.py +0 -0
  11. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/neo4j.py +0 -0
  12. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/node.py +0 -0
  13. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/node_size.py +0 -0
  14. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/nvl.py +0 -0
  15. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/options.py +0 -0
  16. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/pandas.py +0 -0
  17. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/py.typed +0 -0
  18. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/relationship.py +0 -0
  19. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz/resources/nvl_entrypoint/base.js +0 -0
  20. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz.egg-info/SOURCES.txt +0 -0
  21. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz.egg-info/dependency_links.txt +0 -0
  22. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz.egg-info/requires.txt +0 -0
  23. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/src/neo4j_viz.egg-info/top_level.txt +0 -0
  24. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/tests/test_gds.py +0 -0
  25. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/tests/test_neo4j.py +0 -0
  26. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/tests/test_node.py +0 -0
  27. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/tests/test_notebooks.py +0 -0
  28. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/tests/test_options.py +0 -0
  29. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/tests/test_pandas.py +0 -0
  30. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/tests/test_pinned.py +0 -0
  31. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/tests/test_relationship.py +0 -0
  32. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/tests/test_render.py +0 -0
  33. {neo4j_viz-0.2.5 → neo4j_viz-0.2.6}/tests/test_sizes.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: neo4j-viz
3
- Version: 0.2.5
3
+ Version: 0.2.6
4
4
  Summary: A simple graph visualization tool
5
5
  Author-email: Neo4j <team-gds@neo4j.org>
6
6
  Project-URL: Homepage, https://neo4j.com/
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "neo4j-viz"
7
- version = "0.2.5"
7
+ version = "0.2.6"
8
8
  description = "A simple graph visualization tool"
9
9
  readme = "README.md"
10
10
  authors = [{ name = "Neo4j", email = "team-gds@neo4j.org" }]
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import warnings
4
4
  from collections.abc import Iterable
5
- from typing import Optional
5
+ from typing import Any, Hashable, Optional
6
6
 
7
7
  from IPython.display import HTML
8
8
  from pydantic_extra_types.color import Color, ColorType
@@ -201,7 +201,8 @@ class VisualizationGraph:
201
201
  Parameters
202
202
  ----------
203
203
  property:
204
- The property of the nodes to use for coloring.
204
+ The property of the nodes to use for coloring. The type of this property must be hashable, or be a
205
+ list, set or dict containing only hashable types.
205
206
  colors:
206
207
  The colors to use for the nodes. If a dictionary is given, it should map from property to color.
207
208
  If an iterable is given, the colors are used in order.
@@ -238,7 +239,11 @@ class VisualizationGraph:
238
239
  prop_to_color = {}
239
240
  colors_iter = iter(colors)
240
241
  for node in self.nodes:
241
- prop = getattr(node, property)
242
+ raw_prop = getattr(node, property)
243
+ try:
244
+ prop = self._make_hashable(raw_prop)
245
+ except ValueError:
246
+ raise ValueError(f"Unable to color nodes by unhashable property type '{type(raw_prop)}'")
242
247
 
243
248
  if prop not in prop_to_color:
244
249
  next_color = next(colors_iter, None)
@@ -263,3 +268,22 @@ class VisualizationGraph:
263
268
  f"Ran out of colors for property '{property}'. {len(prop_to_color)} colors were needed, but only "
264
269
  f"{len(set(prop_to_color.values()))} were given, so reused colors"
265
270
  )
271
+
272
+ @staticmethod
273
+ def _make_hashable(raw_prop: Any) -> Hashable:
274
+ prop = raw_prop
275
+ if isinstance(raw_prop, list):
276
+ prop = tuple(raw_prop)
277
+ elif isinstance(raw_prop, set):
278
+ prop = frozenset(raw_prop)
279
+ elif isinstance(raw_prop, dict):
280
+ prop = tuple(sorted(raw_prop.items()))
281
+
282
+ try:
283
+ hash(prop)
284
+ except TypeError:
285
+ raise ValueError(f"Unable to convert property '{raw_prop}' of type {type(raw_prop)} to a hashable type")
286
+
287
+ assert isinstance(prop, Hashable)
288
+
289
+ return prop
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: neo4j-viz
3
- Version: 0.2.5
3
+ Version: 0.2.6
4
4
  Summary: A simple graph visualization tool
5
5
  Author-email: Neo4j <team-gds@neo4j.org>
6
6
  Project-URL: Homepage, https://neo4j.com/
@@ -103,3 +103,86 @@ def test_color_nodes_default() -> None:
103
103
  assert VG.nodes[1].color == Color(neo4j_colors[1])
104
104
  assert VG.nodes[2].color == Color(neo4j_colors[1])
105
105
  assert VG.nodes[3].color == Color(neo4j_colors[2])
106
+
107
+
108
+ def test_color_nodes_lists() -> None:
109
+ nodes = [
110
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:0", caption="Person", labels=["Person"]),
111
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:6", caption="Product", labels=["Product"]),
112
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:11", caption="Product", labels=["Product"]),
113
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:1", caption="Both", labels=["Person", "Product"]),
114
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:2", caption="Both again", labels=["Person", "Product"]),
115
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:3", caption="Both reorder", labels=["Product", "Person"]),
116
+ ]
117
+
118
+ VG = VisualizationGraph(nodes=nodes, relationships=[])
119
+
120
+ VG.color_nodes("labels", ["#000000", "#00FF00", "#FF0000", "#0000FF"])
121
+
122
+ assert VG.nodes[0].color == Color("#000000")
123
+ assert VG.nodes[1].color == Color("#00ff00")
124
+ assert VG.nodes[2].color == Color("#00ff00")
125
+ assert VG.nodes[3].color == Color("#ff0000")
126
+ assert VG.nodes[4].color == Color("#ff0000")
127
+ assert VG.nodes[5].color == Color("#0000ff")
128
+
129
+
130
+ def test_color_nodes_sets() -> None:
131
+ nodes = [
132
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:0", caption="Person", labels={"Person"}),
133
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:6", caption="Product", labels={"Product"}),
134
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:11", caption="Product", labels={"Product"}),
135
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:1", caption="Both", labels={"Person", "Product"}),
136
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:2", caption="Both again", labels={"Person", "Product"}),
137
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:3", caption="Both reorder", labels={"Product", "Person"}),
138
+ ]
139
+
140
+ VG = VisualizationGraph(nodes=nodes, relationships=[])
141
+
142
+ VG.color_nodes("labels", ["#000000", "#00FF00", "#FF0000", "#0000FF"])
143
+
144
+ assert VG.nodes[0].color == Color("#000000")
145
+ assert VG.nodes[1].color == Color("#00ff00")
146
+ assert VG.nodes[2].color == Color("#00ff00")
147
+ assert VG.nodes[3].color == Color("#ff0000")
148
+ assert VG.nodes[4].color == Color("#ff0000")
149
+ assert VG.nodes[4].color == Color("#ff0000")
150
+
151
+
152
+ def test_color_nodes_dicts() -> None:
153
+ nodes = [
154
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:0", caption="Person", config={"age": 18}),
155
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:6", caption="Product", config={"price": 100}),
156
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:11", caption="Product", config={"price": 100}),
157
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:1", caption="Product", config={"price": 1}),
158
+ ]
159
+
160
+ VG = VisualizationGraph(nodes=nodes, relationships=[])
161
+
162
+ VG.color_nodes("config", ["#000000", "#00FF00", "#FF0000", "#0000FF"])
163
+
164
+ assert VG.nodes[0].color == Color("#000000")
165
+ assert VG.nodes[1].color == Color("#00ff00")
166
+ assert VG.nodes[2].color == Color("#00ff00")
167
+ assert VG.nodes[3].color == Color("#ff0000")
168
+
169
+
170
+ def test_color_nodes_unhashable() -> None:
171
+ nodes = [
172
+ Node(
173
+ id="4:d09f48a4-5fca-421d-921d-a30a896c604d:0",
174
+ caption="Person",
175
+ config={"movies": ["Star Wars", "Star Trek"]},
176
+ ),
177
+ ]
178
+ VG = VisualizationGraph(nodes=nodes, relationships=[])
179
+
180
+ with pytest.raises(ValueError, match="Unable to color nodes by unhashable property type '<class 'dict'>'"):
181
+ VG.color_nodes("config", ["#000000"])
182
+
183
+ nodes = [
184
+ Node(id="4:d09f48a4-5fca-421d-921d-a30a896c604d:0", caption="Person", list_of_lists=[[1, 2], [3, 4]]),
185
+ ]
186
+ VG = VisualizationGraph(nodes=nodes, relationships=[])
187
+ with pytest.raises(ValueError, match="Unable to color nodes by unhashable property type '<class 'list'>'"):
188
+ VG.color_nodes("list_of_lists", ["#000000"])
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes