neo4j-viz 0.4.1__py3-none-any.whl → 0.5.0__py3-none-any.whl
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.
- neo4j_viz/gds.py +34 -27
- neo4j_viz/pandas.py +1 -1
- neo4j_viz/resources/nvl_entrypoint/base.js +1 -1
- neo4j_viz/snowflake.py +344 -0
- neo4j_viz/visualization_graph.py +2 -1
- {neo4j_viz-0.4.1.dist-info → neo4j_viz-0.5.0.dist-info}/METADATA +5 -3
- {neo4j_viz-0.4.1.dist-info → neo4j_viz-0.5.0.dist-info}/RECORD +9 -8
- {neo4j_viz-0.4.1.dist-info → neo4j_viz-0.5.0.dist-info}/WHEEL +0 -0
- {neo4j_viz-0.4.1.dist-info → neo4j_viz-0.5.0.dist-info}/top_level.txt +0 -0
neo4j_viz/gds.py
CHANGED
|
@@ -2,12 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import warnings
|
|
4
4
|
from itertools import chain
|
|
5
|
-
from typing import Optional
|
|
5
|
+
from typing import Optional, cast
|
|
6
6
|
from uuid import uuid4
|
|
7
7
|
|
|
8
8
|
import pandas as pd
|
|
9
9
|
from graphdatascience import Graph, GraphDataScience
|
|
10
|
-
from pandas import Series
|
|
11
10
|
|
|
12
11
|
from .pandas import _from_dfs
|
|
13
12
|
from .visualization_graph import VisualizationGraph
|
|
@@ -24,22 +23,25 @@ def _fetch_node_dfs(
|
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
|
|
27
|
-
def
|
|
28
|
-
|
|
29
|
-
assert isinstance(relationship_properties, Series)
|
|
26
|
+
def _fetch_rel_dfs(gds: GraphDataScience, G: Graph) -> list[pd.DataFrame]:
|
|
27
|
+
rel_types = G.relationship_types()
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
property_set: set[str] = set()
|
|
33
|
-
for props in relationship_properties_per_type:
|
|
34
|
-
if props:
|
|
35
|
-
property_set.update(props)
|
|
29
|
+
rel_props = {rel_type: G.relationship_properties(rel_type) for rel_type in rel_types}
|
|
36
30
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
)
|
|
31
|
+
rel_dfs: list[pd.DataFrame] = []
|
|
32
|
+
# Have to call per stream per relationship type as there was a bug in GDS < 2.21
|
|
33
|
+
for rel_type, props in rel_props.items():
|
|
34
|
+
assert isinstance(props, list)
|
|
35
|
+
if len(props) > 0:
|
|
36
|
+
rel_df = gds.graph.relationshipProperties.stream(
|
|
37
|
+
G, relationship_types=rel_type, relationship_properties=list(props), separate_property_columns=True
|
|
38
|
+
)
|
|
39
|
+
else:
|
|
40
|
+
rel_df = gds.graph.relationships.stream(G, relationship_types=[rel_type])
|
|
41
|
+
|
|
42
|
+
rel_dfs.append(rel_df)
|
|
41
43
|
|
|
42
|
-
return
|
|
44
|
+
return rel_dfs
|
|
43
45
|
|
|
44
46
|
|
|
45
47
|
def from_gds(
|
|
@@ -79,31 +81,32 @@ def from_gds(
|
|
|
79
81
|
"""
|
|
80
82
|
node_properties_from_gds = G.node_properties()
|
|
81
83
|
assert isinstance(node_properties_from_gds, pd.Series)
|
|
82
|
-
actual_node_properties = node_properties_from_gds.to_dict()
|
|
84
|
+
actual_node_properties: dict[str, list[str]] = cast(dict[str, list[str]], node_properties_from_gds.to_dict())
|
|
83
85
|
all_actual_node_properties = list(chain.from_iterable(actual_node_properties.values()))
|
|
84
86
|
|
|
85
87
|
if size_property is not None:
|
|
86
88
|
if size_property not in all_actual_node_properties:
|
|
87
89
|
raise ValueError(f"There is no node property '{size_property}' in graph '{G.name()}'")
|
|
88
90
|
|
|
91
|
+
node_properties_by_label_sets: dict[str, set[str]] = dict()
|
|
89
92
|
if additional_node_properties is None:
|
|
90
|
-
|
|
93
|
+
node_properties_by_label_sets = {k: set(v) for k, v in actual_node_properties.items()}
|
|
91
94
|
else:
|
|
92
95
|
for prop in additional_node_properties:
|
|
93
96
|
if prop not in all_actual_node_properties:
|
|
94
97
|
raise ValueError(f"There is no node property '{prop}' in graph '{G.name()}'")
|
|
95
98
|
|
|
96
|
-
node_properties_by_label = {}
|
|
97
99
|
for label, props in actual_node_properties.items():
|
|
98
|
-
|
|
100
|
+
node_properties_by_label_sets[label] = {
|
|
99
101
|
prop for prop in actual_node_properties[label] if prop in additional_node_properties
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
if size_property is not None:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
# For some reason mypy are unable to understand that this is dict[str, set[str]]
|
|
106
|
+
for label, props in node_properties_by_label_sets.items(): # type: ignore
|
|
107
|
+
props.add(size_property) # type: ignore
|
|
105
108
|
|
|
106
|
-
node_properties_by_label = {k: list(v) for k, v in
|
|
109
|
+
node_properties_by_label = {k: list(v) for k, v in node_properties_by_label_sets.items()}
|
|
107
110
|
|
|
108
111
|
node_count = G.node_count()
|
|
109
112
|
if node_count > max_node_count:
|
|
@@ -131,7 +134,7 @@ def from_gds(
|
|
|
131
134
|
for df in node_dfs.values():
|
|
132
135
|
df.drop(columns=[property_name], inplace=True)
|
|
133
136
|
|
|
134
|
-
|
|
137
|
+
rel_dfs = _fetch_rel_dfs(gds, G_fetched)
|
|
135
138
|
finally:
|
|
136
139
|
if G_fetched.name() != G.name():
|
|
137
140
|
G_fetched.drop()
|
|
@@ -146,7 +149,10 @@ def from_gds(
|
|
|
146
149
|
if size_property is not None:
|
|
147
150
|
if "size" in all_actual_node_properties and size_property != "size":
|
|
148
151
|
node_props_df.rename(columns={"size": "__size"}, inplace=True)
|
|
149
|
-
|
|
152
|
+
if additional_node_properties is not None and size_property not in additional_node_properties:
|
|
153
|
+
node_props_df.rename(columns={size_property: "size"}, inplace=True)
|
|
154
|
+
else:
|
|
155
|
+
node_props_df["size"] = node_props_df[size_property]
|
|
150
156
|
|
|
151
157
|
for lbl, df in node_dfs.items():
|
|
152
158
|
if "labels" in all_actual_node_properties:
|
|
@@ -161,12 +167,13 @@ def from_gds(
|
|
|
161
167
|
if "caption" not in all_actual_node_properties:
|
|
162
168
|
node_df["caption"] = node_df["labels"].astype(str)
|
|
163
169
|
|
|
164
|
-
|
|
165
|
-
|
|
170
|
+
for rel_df in rel_dfs:
|
|
171
|
+
if "caption" not in rel_df.columns:
|
|
172
|
+
rel_df["caption"] = rel_df["relationshipType"]
|
|
166
173
|
|
|
167
174
|
try:
|
|
168
175
|
return _from_dfs(
|
|
169
|
-
node_df,
|
|
176
|
+
node_df, rel_dfs, node_radius_min_max=node_radius_min_max, rename_properties={"__size": "size"}, dropna=True
|
|
170
177
|
)
|
|
171
178
|
except ValueError as e:
|
|
172
179
|
err_msg = str(e)
|
neo4j_viz/pandas.py
CHANGED
|
@@ -74,7 +74,7 @@ def _parse_nodes(
|
|
|
74
74
|
has_size = True
|
|
75
75
|
nodes = []
|
|
76
76
|
for node_df in node_dfs_iter:
|
|
77
|
-
has_size &= "size" in node_df.columns
|
|
77
|
+
has_size &= "size" in [c.lower() for c in node_df.columns]
|
|
78
78
|
for _, row in node_df.iterrows():
|
|
79
79
|
if dropna:
|
|
80
80
|
row = row.dropna(inplace=False)
|