1
+ import logging , pandas as pd
2
+ from datetime import datetime
1
3
from .pygraphistry import util
2
4
5
+ logger = logging .getLogger (__name__ )
6
+
3
7
node_id_key = u'_bolt_node_id_key'
4
8
node_type_key = u'type'
5
9
node_label_prefix_key = u'_lbl_'
8
12
relationship_id_key = u'_bolt_relationship_id'
9
13
relationship_type_key = u'type'
10
14
11
- def is_neotime (v ):
12
- try :
13
- return v .__module__ == 'neotime'
14
- except :
15
- return False
16
-
15
+ t0 = datetime .min .time ()
17
16
18
- def stringify_neotimes ( df ) :
19
- #Otherwise currently encountering a toString error
17
+ try :
18
+ import neo4j
20
19
import neotime
21
- df2 = df .copy ()
22
- for c in df .columns :
23
- df2 [c ] = df [c ].apply (lambda v : str (v ) if is_neotime (v ) else v )
24
- return df2
20
+ except :
21
+ pass
22
+
25
23
26
24
def to_bolt_driver (driver = None ):
27
25
if driver is None :
@@ -35,7 +33,6 @@ def to_bolt_driver(driver=None):
35
33
raise BoltSupportModuleNotFound ()
36
34
37
35
def bolt_graph_to_edges_dataframe (graph ):
38
- import pandas as pd
39
36
df = pd .DataFrame ([
40
37
util .merge_two_dicts (
41
38
{ key : value for (key , value ) in relationship .items () },
@@ -48,11 +45,10 @@ def bolt_graph_to_edges_dataframe(graph):
48
45
)
49
46
for relationship in graph .relationships
50
47
])
51
- return stringify_neotimes (df )
48
+ return neo_df_to_pd_df (df )
52
49
53
50
54
- def bolt_graph_to_nodes_dataframe (graph ):
55
- import pandas as pd
51
+ def bolt_graph_to_nodes_dataframe (graph ) -> pd .DataFrame :
56
52
df = pd .DataFrame ([
57
53
util .merge_two_dicts (
58
54
{ key : value for (key , value ) in node .items () },
@@ -64,7 +60,143 @@ def bolt_graph_to_nodes_dataframe(graph):
64
60
{ node_label_prefix_key + str (label ): True for label in node .labels }))
65
61
for node in graph .nodes
66
62
])
67
- return stringify_neotimes (df )
63
+ return neo_df_to_pd_df (df )
64
+
65
+
66
+ ## Knowing a col is all-spatial, flatten into primitive cols
67
+ def flatten_spatial_col (df : pd .DataFrame , col : str ) -> pd .DataFrame :
68
+ out_df = df .copy (deep = False )
69
+
70
+ ####
71
+
72
+ #TODO: Can we do better than duck typing the spatial fields?
73
+ try :
74
+ out_df [f'{ col } _x' ] = df [col ].apply (lambda v : None if v is None else v .x )
75
+ except :
76
+ pass
77
+
78
+ try :
79
+ out_df [f'{ col } _y' ] = df [col ].apply (lambda v : None if v is None else v .y )
80
+ except :
81
+ pass
82
+
83
+ try :
84
+ out_df [f'{ col } _z' ] = df [col ].apply (lambda v : None if v is None else v .z )
85
+ except :
86
+ pass
87
+
88
+ try :
89
+ out_df [f'{ col } _srid' ] = df [col ].apply (lambda v : None if v is None else v .srid )
90
+ except :
91
+ pass
92
+
93
+ try :
94
+ out_df [f'{ col } _longitude' ] = df [col ].apply (lambda v : None if v is None else v .longitude )
95
+ except :
96
+ pass
97
+
98
+ try :
99
+ out_df [f'{ col } _latitude' ] = df [col ].apply (lambda v : None if v is None else v .latitude )
100
+ except :
101
+ pass
102
+
103
+ ###
104
+
105
+ out_df [col ] = df [col ].apply (str )
106
+
107
+ return out_df
108
+
109
+
110
+
111
+
112
+
113
+ #dtype='obj' -> 'a
114
+ def neo_val_to_pd_val (v ):
115
+
116
+ if v is None :
117
+ return v
118
+
119
+ try :
120
+ v_mod = v .__module__
121
+ except :
122
+ return v
123
+
124
+ #neo4j 3
125
+ if v_mod == 'neotime' :
126
+ return str (v )
127
+
128
+ #neo4j 4
129
+ if v_mod == 'neo4j.time' :
130
+ if v .__class__ == neo4j .time .DateTime :
131
+ return v .to_native () #datetime.datetime
132
+ elif v .__class__ == neo4j .time .Date :
133
+ return datetime .combine (v .to_native (), t0 ) #datatime.datatime
134
+ elif v .__class__ == neo4j .time .Time :
135
+ return pd .to_timedelta (v .iso_format ()) #timedelta
136
+ elif v .__class__ == neo4j .time .Duration :
137
+ #TODO expand out?
138
+ return v .iso_format () #str
139
+ else :
140
+ return str (v )
141
+
142
+ #handle neo4j.spatial.* later
143
+
144
+ return v
145
+
146
+
147
+ def stringify_spatial (v ):
148
+ if v is None :
149
+ return None
150
+ if isinstance (v , neo4j .spatial .Point ):
151
+ ##TODO rep as JSON / dict?
152
+ return str (v )
153
+ return v
154
+
155
+
156
+ def get_mod (v ):
157
+ try :
158
+ return v .__module__
159
+ except :
160
+ return None
161
+
162
+
163
+ ## if a col has spatials:
164
+ ## - all: flatten into new primitive cols
165
+ ## - some: stringify
166
+ def flatten_spatial (df : pd .DataFrame , col : str ) -> pd .DataFrame :
167
+
168
+ any_spatial = (df [col ].apply (get_mod ) == 'neo4j.spatial' ).any ()
169
+ if not any_spatial :
170
+ return df
171
+
172
+ with_vals = df [col ].dropna ()
173
+ if len (with_vals ) == 0 :
174
+ return df
175
+
176
+ out_df = df .copy (deep = False )
177
+
178
+ t0 = with_vals [0 ]
179
+ try :
180
+ all_t0 = (with_vals .apply (lambda s : s .__class__ ) == t0 .__class__ ).all ()
181
+ except :
182
+ all_t0 = False
183
+
184
+ if all_t0 :
185
+ out_df = flatten_spatial_col (df , col )
186
+ else :
187
+ out_df [col ] = df [col ].apply (stringify_spatial )
188
+
189
+ return out_df
190
+
191
+
192
+ def neo_df_to_pd_df (df ):
193
+ out_df = df .copy (deep = False )
194
+ for col in df :
195
+ if df [col ].dtype .name == 'object' :
196
+ out_df [col ] = df [col ].apply (neo_val_to_pd_val )
197
+ out_df = flatten_spatial (out_df , col )
198
+ return out_df
199
+
68
200
69
201
class BoltSupportModuleNotFound (Exception ):
70
202
def __init__ (self ):
0 commit comments