@@ -76,42 +76,44 @@ def write_node_info(g, filename, delimiter=','):
7676 f_nodeinfo .write ('\n ' )
7777 f_nodeinfo .close ()
7878
79-
8079class SynapseListObj :
81-
82- def __init__ (self , skdata , category , proj_opts ):
83- if category == 'pre' :
84- cat_ind = 0
85- elif category == 'post' :
86- cat_ind = 1
87- else :
88- raise NameError ('category should be pre or post only' )
89-
90- self .conn_ids = [dat [1 ] for dat in skdata [1 ] if dat [2 ] == cat_ind ]
91- self .conn_id2node_id = {dat [1 ]: dat [0 ]
92- for dat in skdata [1 ] if dat [2 ] == cat_ind }
93- self .conn_id2loc = {dat [1 ]: dat [3 :6 ]
94- for dat in skdata [1 ] if dat [2 ] == cat_ind }
95-
80+ def __init__ (self , conndata ):
81+ self .conn_ids = [ dat [0 ] for dat in conndata ]
9682
9783class InputSynapseListObj (SynapseListObj ):
98-
99- def __init__ (self , skdata , proj_opts ):
100- SynapseListObj .__init__ (self , skdata , 'post' , proj_opts )
101-
84+ def __init__ (self , conndata , self_id ):
85+ SynapseListObj .__init__ (self , conndata )
86+ self .target_node_ids = {}
87+ for dat in conndata :
88+ for skid , nid in zip ( dat [1 ]['postsynaptic_to' ], dat [1 ]['postsynaptic_to_node' ] ):
89+ if skid == self_id :
90+ if dat [0 ] in self .target_node_ids :
91+ self .target_node_ids [ dat [0 ] ].append (nid )
92+ else :
93+ self .target_node_ids [ dat [0 ] ] = [nid ]
94+ self .from_ids = { dat [0 ] : dat [1 ]['presynaptic_to' ] for dat in conndata }
95+ self .from_node_ids = { dat [0 ] : dat [1 ]['presynaptic_to_node' ] for dat in conndata }
10296 def num (self ):
103- return len (self .conn_ids )
104-
97+ return sum ( map ( lambda x : len (x ), self .target_node_ids .values () ) )
10598
10699class OutputSynapseListObj (SynapseListObj ):
107-
108- def __init__ (self , skdata , proj_opts ):
109- SynapseListObj .__init__ (self , skdata , 'pre' , proj_opts )
110- self .num_targets = {val [0 ]: val [1 ] for val in skdata [5 ]}
100+ def __init__ (self , conndata , self_id ):
101+ SynapseListObj .__init__ (self , conndata )
102+ self .from_node_ids = {dat [0 ] : dat [1 ]['presynaptic_to_node' ] for dat in conndata }
103+ self .target_ids = { dat [0 ] : dat [1 ]['postsynaptic_to' ] for dat in conndata }
104+ self .target_node_ids = {dat [0 ] : dat [1 ]['postsynaptic_to_node' ] for dat in conndata }
105+
106+ def num_targets ( self ):
107+ return {id : len (self .target_ids [id ]) for id in self .target_ids }
108+
109+ def num_targets_connector ( self , conn_id ):
110+ if conn_id in self .target_ids :
111+ return len ( self .target_ids [conn_id ])
112+ else :
113+ print ( 'No such presynaptic connector id in neuron' )
111114
112115 def num (self ):
113- return sum ( self .num_targets .values () )
114-
116+ return sum ( self .num_targets ().values () )
115117
116118class NeuronObj :
117119
@@ -141,8 +143,10 @@ def __init__(self, skid, proj_opts):
141143 self .Ab [self .node2ind [key ], self .node2ind [
142144 self .nodeparent [key ]]] = 1
143145
144- self .inputs = InputSynapseListObj (skdata , proj_opts )
145- self .outputs = OutputSynapseListObj (skdata , proj_opts )
146+ pre_conn_ids = [dat [1 ] for dat in skdata [1 ] if dat [2 ] == 0 ]
147+ post_conn_ids = [dat [1 ] for dat in skdata [1 ] if dat [2 ] == 1 ]
148+ self .inputs = InputSynapseListObj ( ci .get_connector_data ( post_conn_ids , proj_opts ), self .id )
149+ self .outputs = OutputSynapseListObj ( ci .get_connector_data ( pre_conn_ids , proj_opts ), self .id )
146150
147151 def __str__ ( self ):
148152 return self .name
@@ -163,118 +167,122 @@ def get_url_to_node( self, nodeid, proj_opts, printflag=True, zoomlevel = 0 ):
163167 else :
164168 return ur
165169
170+ def find_end_nodes (self ):
171+ # Returns a list of node ids that are end nodes (have no children)
172+ y = np .where (self .Ab .sum (0 ) == 0 )[1 ]
173+ return [self .nodeids [ind ] for ind in y ]
174+
175+ def find_branch_points (self ):
176+ # Returns a list of node ids that are branch points (have multiple children)
177+ y = np .where (self .Ab .sum (0 ) > 1 )[1 ]
178+ return [self .nodeids [ind ] for ind in y ]
179+
180+ def minimal_paths (self ):
181+ # Returns list of lists, the minimally overlapping paths from each end
182+ # point toward root
183+ D = dist_to_root (self )
184+ ids_end = self .find_end_nodes ()
185+
186+ ends_sorted = [ids_end [ind ] for ind in np .argsort (
187+ D [[self .node2ind [id ] for id in ids_end ]])[::- 1 ]]
188+ not_visited = [True ] * len (self .nodeids )
189+ min_paths = []
190+
191+ for start_nd in ends_sorted :
192+ nd = start_nd
193+ min_paths .append ([nd ]) # Start a new list with this end as a seed
194+ while not_visited [self .node2ind [nd ]] and (self .nodeparent [nd ] is not None ):
195+ not_visited [self .node2ind [nd ]] = False
196+ nd = self .nodeparent [nd ]
197+ min_paths [- 1 ].append (nd )
198+
199+ return min_paths
200+
201+ def strahler_number (self ):
202+ # Computes strahler number for a neuron
203+ paths = self .minimal_paths ()
204+ sn = {}
205+ for nid in self .nodeids :
206+ sn [nid ] = 0
207+
208+ for path in paths [::- 1 ]:
209+ sn [path [0 ]] = 1
210+ for ii , nid in enumerate (path [1 :]):
211+ if sn [nid ] == sn [path [ii ]]:
212+ sn [nid ] = sn [path [ii ]] + 1
213+ else :
214+ sn [nid ] = sn [path [ii ]]
215+ return sn
216+
217+ def split_into_components (self , nids , from_parent = True ):
218+ # Return n-component list, each element is a list of node ids in the component.
219+ # nids is a list of child nodes that will be split from their parent node.
220+ # if from_parent is toggled false, parents divorce childen and not the
221+ # default.
222+ Ab_sp = copy .deepcopy (self .Ab )
223+
224+ if from_parent :
225+ for id in nids :
226+ nind = self .node2ind [id ]
227+ Ab_sp [:, nind ] = 0
228+ else :
229+ for id in nids :
230+ nind = self .node2ind [id ]
231+ Ab_sp [nind , :] = 0
166232
233+ ncmp , cmp_label = csgraph .connected_components (Ab_sp , directed = False )
167234
168- class SynapseDict :
169-
170- def __init__ (self , neuron_list ):
171- self .pre_skid = dict ()
172- self .post_skid = defaultdict (list )
173- for neuron in neuron_list :
174- rel_skid = neuron .id
175- for connid in neuron .inputs .conn_ids :
176- self .post_skid [connid ].append (rel_skid )
177- for connid in neuron .outputs .conn_ids :
178- self .pre_skid [connid ] = rel_skid
179-
180- def update_synapse_dict (self , neuron_list ):
181- for neuron in neuron_list :
182- rel_skid = neuron .id
183- for connid in neuron .inputs .conn_ids :
184- self .post_skid [connid ].append (rel_skid )
185- for connid in neuron .outputs .conn_ids :
186- self .pre_skid [connid ] = rel_skid
187-
188-
189- def dist_to_root (nrn ):
190- # Returns distance to root for each node in nrn as an array
191- D = csgraph .shortest_path (
192- nrn .A .transpose (), directed = True , unweighted = False , method = 'D' )
193- return D [nrn .node2ind [nrn .root ]]
194-
195-
196- def find_end_nodes (nrn ):
197- # Returns a list of node ids that are end nodes (have no children)
198- y = np .where (nrn .Ab .sum (0 ) == 0 )[1 ]
199- return [nrn .nodeids [ind ] for ind in y ]
200-
201- def find_branch_points (nrn ):
202- # Returns a list of node ids that are branch points (have multiple children)
203- y = np .where (nrn .Ab .sum (0 ) > 1 )[1 ]
204- return [nrn .nodeids [ind ] for ind in y ]
235+ cmps = list ()
236+ for cmp_val in range (ncmp ):
237+ comp_inds = np .where (cmp_label == cmp_val )
238+ cmps .append ([self .nodeids [ind ] for ind in comp_inds [0 ]])
205239
240+ cmp_label_dict = {self .nodeids [ind ]:cmp for ind ,cmp in enumerate (cmp_label ) }
206241
207- def minimal_paths (nrn ):
208- # Returns list of lists, the minimally overlapping paths from each end
209- # point toward root
210- D = dist_to_root (nrn )
211- ids_end = find_end_nodes (nrn )
242+ return cmps , cmp_label_dict
212243
213- ends_sorted = [ids_end [ind ] for ind in np .argsort (
214- D [[nrn .node2ind [id ] for id in ids_end ]])[::- 1 ]]
215- not_visited = [True ] * len (nrn .nodeids )
216- min_paths = []
244+ def dist_to_root (self ):
245+ # Returns distance to root for each node in nrn as an array
246+ D = csgraph .shortest_path (
247+ self .A .transpose (), directed = True , unweighted = False , method = 'D' )
248+ return D [self .node2ind [self .root ]]
217249
218- for start_nd in ends_sorted :
219- nd = start_nd
220- min_paths .append ([nd ]) # Start a new list with this end as a seed
221- while not_visited [nrn .node2ind [nd ]] and (nrn .nodeparent [nd ] is not None ):
222- not_visited [nrn .node2ind [nd ]] = False
223- nd = nrn .nodeparent [nd ]
224- min_paths [- 1 ].append (nd )
250+ def split_by_tag ( self , tag_str ):
251+ nids = self .tags [ tag_str ]
252+ cmps , cmp_label = self .split_into_components ( nids )
253+ return cmps , cmp_label
225254
226- return min_paths
255+ class SynapseObject :
256+ def __init__ (self , conn_ids , proj_opts ):
257+ conndata = ci .get_connector_data ( post_conn_ids , proj_opts )
258+ self .connectors = { dat [0 ] : dat [1 ] for dat in conndata }
227259
228- def neurons_from_annotations ( annotation_list , proj_opts , syns = None ):
260+ def neurons_from_annotations ( annotation_list , proj_opts ):
229261 anno_dict = ci .get_annotation_dict ( proj_opts )
230262 id_list = ci .get_ids_from_annotation ( [anno_dict [anno ] for anno in annotation_list ], proj_opts )
231- ( neurons , syns ) = neurons_from_id_list ( id_list , proj_opts , syns = syns )
232- return ( neurons , syns )
263+ neurons = neurons_from_id_list ( id_list , proj_opts )
264+ return neurons
233265
234- def neurons_from_id_list (id_list , proj_opts , syns = None ):
235- # Given a list of ids, build a list of NeuronObj and a SynapseDict
266+ def neurons_from_id_list (id_list , proj_opts ):
267+ # Given a list of ids, build a list of NeuronObjs
236268 # associated with them, if one is already pre-existing
237269 neurons = [NeuronObj (id , proj_opts ) for id in id_list ]
270+ return neurons
238271
239- if syns is None :
240- syns = SynapseDict (neurons )
241- else :
242- syns .update_synapse_dict (neurons )
243-
244- return (neurons , syns )
245-
246-
247- def strahler_number (neuron ):
248- # Computes strahler number for a neuron
249- paths = minimal_paths (neuron )
250- sn = {}
251- for nid in neuron .nodeids :
252- sn [nid ] = 0
253-
254- for path in paths [::- 1 ]:
255- sn [path [0 ]] = 1
256- for ii , nid in enumerate (path [1 :]):
257- if sn [nid ] == sn [path [ii ]]:
258- sn [nid ] = sn [path [ii ]] + 1
259- else :
260- sn [nid ] = sn [path [ii ]]
261-
262- return sn
263-
264- def get_adjacency_matrix ( neurons , syns , input_normalized = False ):
272+ def get_adjacency_matrix ( neurons , input_normalized = False ):
265273 # Build a weighted adjacency matrix from neurons
266274 A = np .zeros ( (len (neurons ), len (neurons )) )
267275 skid_to_ind = { skid :ii for ii , skid in enumerate ([nrn .id for nrn in neurons ])}
268276 ind_to_skid = { ii :skid for ii , skid in enumerate ([nrn .id for nrn in neurons ])}
269-
277+ ids = [ nrn . id for nrn in neurons ]
270278 for nrn in neurons :
271- for conn_id in nrn .outputs .conn_ids :
272- for targ in syns . post_skid [ conn_id ]:
273- if input_normalized is True :
274- A [ skid_to_ind [ targ ], skid_to_ind [ nrn . id ]] += 1.0 / neurons [ skid_to_ind [ targ ] ]. inputs . num ()
275- else :
276- A [ skid_to_ind [ targ ], skid_to_ind [ nrn . id ]] += 1
277-
279+ for conn_id in nrn .outputs .target_ids :
280+ for targ in nrn . outputs . target_ids [ conn_id ]:
281+ if targ in ids :
282+ if input_normalized is True :
283+ A [ skid_to_ind [ targ ], skid_to_ind [ nrn . id ]] += 1.0 / neurons [ skid_to_ind [ targ ] ]. inputs . num ()
284+ else :
285+ A [ skid_to_ind [ targ ], skid_to_ind [ nrn . id ]] += 1
278286 return A , skid_to_ind , ind_to_skid
279287
280288def group_adjacency_matrix ( neurons , syns , groups , func = np .sum ):
@@ -288,11 +296,6 @@ def group_adjacency_matrix( neurons, syns, groups, func=np.sum ):
288296 Agr [ ii , jj ] = func ( Ared )
289297 return Agr
290298
291- def split_neuron_by_tag ( neuron , tag_str ):
292- nids = neuron .tags [ tag_str ]
293- cmps , cmp_label = split_neuron_into_components ( neuron , nids )
294- return cmps , cmp_label
295-
296299def sort_neurons_by ( neurons , sort_vector ):
297300 if len ( sort_vector ) != len ( neurons ):
298301 print ( 'Vector must be same length as neurons' )
@@ -310,30 +313,3 @@ def number_inputs( neurons ):
310313
311314def number_outputs ( neurons ):
312315 return [nrn .outputs .num () for nrn in neurons ]
313-
314- def split_neuron_into_components (neuron , nids , from_parent = True ):
315- # Return n-component list, each element is a list of node ids in the component.
316- # nids is a list of child nodes that will be split from their parent node.
317- # if from_parent is toggled false, parents divorce childen and not the
318- # default.
319- Ab_sp = copy .deepcopy (neuron .Ab )
320-
321- if from_parent :
322- for id in nids :
323- nind = neuron .node2ind [id ]
324- Ab_sp [:, nind ] = 0
325- else :
326- for id in nids :
327- nind = neuron .node2ind [id ]
328- Ab_sp [nind , :] = 0
329-
330- ncmp , cmp_label = csgraph .connected_components (Ab_sp , directed = False )
331-
332- cmps = list ()
333- for cmp_val in range (ncmp ):
334- comp_inds = np .where (cmp_label == cmp_val )
335- cmps .append ([neuron .nodeids [ind ] for ind in comp_inds [0 ]])
336-
337- cmp_label_dict = {neuron .nodeids [ind ]:cmp for ind ,cmp in enumerate (cmp_label ) }
338-
339- return cmps , cmp_label_dict
0 commit comments