@@ -134,31 +134,24 @@ def read_block(self, block_index=0, lazy=False,
134134
135135 bl = Block (** bl_annotations )
136136
137- # Group for AnalogSignals
137+ # Group for AnalogSignals coming from signal_streams
138138 if create_group_across_segment ['AnalogSignal' ]:
139- all_channels = self .header ['signal_channels' ]
140- channel_indexes_list = self .get_group_signal_channel_indexes ()
141- sig_groups = []
142- for channel_index in channel_indexes_list :
143- for i , (ind_within , ind_abs ) in self ._make_signal_channel_subgroups (
144- channel_index , signal_group_mode = signal_group_mode ).items ():
145- group = Group (name = 'AnalogSignal group {}' .format (i ))
146- # @andrew @ julia @michael : do we annotate group across segment with this arrays ?
147- group .annotate (ch_names = all_channels [ind_abs ]['name' ].astype ('U' )) # ??
148- group .annotate (channel_ids = all_channels [ind_abs ]['id' ]) # ??
149- bl .groups .append (group )
150- sig_groups .append (group )
139+ signal_streams = self .header ['signal_streams' ]
140+ sub_streams = self .get_sub_signal_streams (signal_group_mode )
141+ sub_stream_groups = []
142+ for sub_stream in sub_streams :
143+ stream_index , inner_stream_channels , name = sub_stream
144+ group = Group (name = name , stream_id = signal_streams [stream_index ]['id' ])
145+ bl .groups .append (group )
146+ sub_stream_groups .append (group )
151147
152148 if create_group_across_segment ['SpikeTrain' ]:
153- unit_channels = self .header ['unit_channels ' ]
149+ spike_channels = self .header ['spike_channels ' ]
154150 st_groups = []
155- for c in range (unit_channels .size ):
151+ for c in range (spike_channels .size ):
156152 group = Group (name = 'SpikeTrain group {}' .format (c ))
157- group .annotate (unit_name = unit_channels [c ]['name' ])
158- group .annotate (unit_id = unit_channels [c ]['id' ])
159- unit_annotations = self .raw_annotations ['unit_channels' ][c ]
160- unit_annotations = check_annotations (unit_annotations )
161- group .annotate (** unit_annotations )
153+ group .annotate (unit_name = spike_channels [c ]['name' ])
154+ group .annotate (unit_id = spike_channels [c ]['id' ])
162155 bl .groups .append (group )
163156 st_groups .append (group )
164157
@@ -183,7 +176,7 @@ def read_block(self, block_index=0, lazy=False,
183176 for seg in bl .segments :
184177 if create_group_across_segment ['AnalogSignal' ]:
185178 for c , anasig in enumerate (seg .analogsignals ):
186- sig_groups [c ].add (anasig )
179+ sub_stream_groups [c ].add (anasig )
187180
188181 if create_group_across_segment ['SpikeTrain' ]:
189182 for c , sptr in enumerate (seg .spiketrains ):
@@ -231,38 +224,35 @@ def read_segment(self, block_index=0, seg_index=0, lazy=False,
231224 signal_group_mode = self ._prefered_signal_group_mode
232225
233226 # annotations
234- seg_annotations = dict ( self .raw_annotations ['blocks' ][block_index ]['segments' ][seg_index ])
235- for k in ('signals' , 'units ' , 'events' ):
227+ seg_annotations = self .raw_annotations ['blocks' ][block_index ]['segments' ][seg_index ]. copy ( )
228+ for k in ('signals' , 'spikes ' , 'events' ):
236229 seg_annotations .pop (k )
237230 seg_annotations = check_annotations (seg_annotations )
238231
239232 seg = Segment (index = seg_index , ** seg_annotations )
240233
241234 # AnalogSignal
242- signal_channels = self .header ['signal_channels' ]
243- if signal_channels .size > 0 :
244- channel_indexes_list = self .get_group_signal_channel_indexes ()
245- for channel_indexes in channel_indexes_list :
246- for i , (ind_within , ind_abs ) in self ._make_signal_channel_subgroups (
247- channel_indexes ,
248- signal_group_mode = signal_group_mode ).items ():
249- # make a proxy...
250- anasig = AnalogSignalProxy (rawio = self , global_channel_indexes = ind_abs ,
251- block_index = block_index , seg_index = seg_index )
252-
253- if not lazy :
254- # ... and get the real AnalogSIgnal if not lazy
255- anasig = anasig .load (time_slice = time_slice , strict_slicing = strict_slicing )
256- # TODO magnitude_mode='rescaled'/'raw'
257-
258- anasig .segment = seg
259- seg .analogsignals .append (anasig )
235+ signal_streams = self .header ['signal_streams' ]
236+ sub_streams = self .get_sub_signal_streams (signal_group_mode )
237+ for sub_stream in sub_streams :
238+ stream_index , inner_stream_channels , name = sub_stream
239+ anasig = AnalogSignalProxy (rawio = self , stream_index = stream_index ,
240+ inner_stream_channels = inner_stream_channels ,
241+ block_index = block_index , seg_index = seg_index )
242+ anasig .name = name
243+
244+ if not lazy :
245+ # ... and get the real AnalogSignal if not lazy
246+ anasig = anasig .load (time_slice = time_slice , strict_slicing = strict_slicing )
247+
248+ anasig .segment = seg
249+ seg .analogsignals .append (anasig )
260250
261251 # SpikeTrain and waveforms (optional)
262- unit_channels = self .header ['unit_channels ' ]
263- for unit_index in range (len (unit_channels )):
252+ spike_channels = self .header ['spike_channels ' ]
253+ for spike_channel_index in range (len (spike_channels )):
264254 # make a proxy...
265- sptr = SpikeTrainProxy (rawio = self , unit_index = unit_index ,
255+ sptr = SpikeTrainProxy (rawio = self , spike_channel_index = spike_channel_index ,
266256 block_index = block_index , seg_index = seg_index )
267257
268258 if not lazy :
@@ -286,7 +276,7 @@ def read_segment(self, block_index=0, seg_index=0, lazy=False,
286276 seg .events .append (e )
287277 elif event_channels ['type' ][chan_ind ] == b'epoch' :
288278 e = EpochProxy (rawio = self , event_channel_index = chan_ind ,
289- block_index = block_index , seg_index = seg_index )
279+ block_index = block_index , seg_index = seg_index )
290280 if not lazy :
291281 e = e .load (time_slice = time_slice , strict_slicing = strict_slicing )
292282 e .segment = seg
@@ -295,37 +285,50 @@ def read_segment(self, block_index=0, seg_index=0, lazy=False,
295285 seg .create_many_to_one_relationship ()
296286 return seg
297287
298- def _make_signal_channel_subgroups (self , channel_indexes ,
299- signal_group_mode = 'group-by-same-units' ):
288+ def get_sub_signal_streams (self , signal_group_mode = 'group-by-same-units' ):
300289 """
301- For some RawIO channel are already splitted in groups.
302- But in any cases, channel need to be splitted again in sub groups
303- because they do not have the same units.
304-
305- They can also be splitted one by one to match previous behavior for
306- some IOs in older version of neo (<=0.5).
290+ When signal streams don't have homogeneous SI units across channels,
291+ they have to be split in sub streams to construct AnalogSignal objects with unique units.
307292
308- This method aggregate signal channels with same units or split them all.
293+ For backward compatibility (neo version <= 0.5) sub-streams can also be
294+ used to generate one AnalogSignal per channel.
309295 """
310- all_channels = self .header ['signal_channels' ]
311- if channel_indexes is None :
312- channel_indexes = np .arange (all_channels .size , dtype = int )
313- channels = all_channels [channel_indexes ]
314-
315- groups = collections .OrderedDict ()
316- if signal_group_mode == 'group-by-same-units' :
317- all_units = np .unique (channels ['units' ])
318-
319- for i , unit in enumerate (all_units ):
320- ind_within , = np .nonzero (channels ['units' ] == unit )
321- ind_abs = channel_indexes [ind_within ]
322- groups [i ] = (ind_within , ind_abs )
323-
324- elif signal_group_mode == 'split-all' :
325- for i , chan_index in enumerate (channel_indexes ):
326- ind_within = [i ]
327- ind_abs = channel_indexes [ind_within ]
328- groups [i ] = (ind_within , ind_abs )
329- else :
330- raise (NotImplementedError )
331- return groups
296+ signal_streams = self .header ['signal_streams' ]
297+ signal_channels = self .header ['signal_channels' ]
298+
299+ sub_streams = []
300+ for stream_index in range (len (signal_streams )):
301+ stream_id = signal_streams [stream_index ]['id' ]
302+ stream_name = signal_streams [stream_index ]['name' ]
303+ mask = signal_channels ['stream_id' ] == stream_id
304+ channels = signal_channels [mask ]
305+ if signal_group_mode == 'group-by-same-units' :
306+ # this does not keep the original order
307+ _ , idx = np .unique (channels ['units' ], return_index = True )
308+ all_units = channels ['units' ][np .sort (idx )]
309+
310+ if len (all_units ) == 1 :
311+ # no substream
312+ # None iwill be transform as slice later
313+ inner_stream_channels = None
314+ name = stream_name
315+ sub_stream = (stream_index , inner_stream_channels , name )
316+ sub_streams .append (sub_stream )
317+ else :
318+ for units in all_units :
319+ inner_stream_channels , = np .nonzero (channels ['units' ] == units )
320+ chan_names = channels [inner_stream_channels ]['name' ]
321+ name = 'Channels: (' + ' ' .join (chan_names ) + ')'
322+ sub_stream = (stream_index , inner_stream_channels , name )
323+ sub_streams .append (sub_stream )
324+ elif signal_group_mode == 'split-all' :
325+ # mimic all neo <= 0.5 behavior
326+ for i , channel in enumerate (channels ):
327+ inner_stream_channels = [i ]
328+ name = channels [i ]['name' ]
329+ sub_stream = (stream_index , inner_stream_channels , name )
330+ sub_streams .append (sub_stream )
331+ else :
332+ raise (NotImplementedError )
333+
334+ return sub_streams
0 commit comments