Skip to content

Commit c481de6

Browse files
committed
Merge branch 'rawio_improvement' of github.com:samuelgarcia/python-neo into spikegadgets_implementation
2 parents da1af2e + a827909 commit c481de6

38 files changed

+1710
-1319
lines changed

doc/source/rawio.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,11 @@ Then browse the internal header and display information::
7777
nb_block: 1
7878
nb_segment: [1]
7979
signal_channels: [V1]
80-
unit_channels: [Wspk1u, Wspk2u, Wspk4u, Wspk5u ... Wspk29u Wspk30u Wspk31u Wspk32u]
80+
spike_channels: [Wspk1u, Wspk2u, Wspk4u, Wspk5u ... Wspk29u Wspk30u Wspk31u Wspk32u]
8181
event_channels: []
8282

8383
You get the number of blocks and segments per block. You have information
84-
about channels: **signal_channels**, **unit_channels**, **event_channels**.
84+
about channels: **signal_channels**, **spike_channels**, **event_channels**.
8585

8686
All this information is internally available in the *header* dict::
8787

@@ -91,7 +91,7 @@ All this information is internally available in the *header* dict::
9191
event_channels []
9292
nb_segment [1]
9393
nb_block 1
94-
unit_channels [('Wspk1u', 'ch1#0', '', 0.00146484, 0., 0, 30000.)
94+
spike_channels [('Wspk1u', 'ch1#0', '', 0.00146484, 0., 0, 30000.)
9595
('Wspk2u', 'ch2#0', '', 0.00146484, 0., 0, 30000.)
9696
...
9797

@@ -141,7 +141,7 @@ Inspect units channel. Each channel gives a SpikeTrain for each Segment.
141141
Note that for many formats a physical channel can have several units after spike
142142
sorting. So the nb_unit could be more than physical channel or signal channels.
143143

144-
>>> nb_unit = reader.unit_channels_count()
144+
>>> nb_unit = reader.spike_channels_count()
145145
>>> print('nb_unit', nb_unit)
146146
nb_unit 30
147147
>>> for unit_index in range(nb_unit):

examples/read_files_neo_rawio.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
print(sampling_rate, t_start, units)
3333

3434
# Count unit and spike per units
35-
nb_unit = reader.unit_channels_count()
35+
nb_unit = reader.spike_channels_count()
3636
print('nb_unit', nb_unit)
3737
for unit_index in range(nb_unit):
3838
nb_spike = reader.spike_count(block_index=0, seg_index=0, unit_index=unit_index)

neo/io/basefromrawio.py

Lines changed: 167 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -134,31 +134,38 @@ def read_block(self, block_index=0, lazy=False,
134134

135135
bl = Block(**bl_annotations)
136136

137-
# Group for AnalogSignals
137+
# Group for AnalogSignals come 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+
#~ 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)
151+
152+
signal_streams = self.header['signal_streams']
153+
sub_streams = self.get_sub_signal_streams(signal_group_mode)
154+
sub_stream_groups = []
155+
for sub_stream in sub_streams:
156+
stream_index, inner_stream_channels, name = sub_stream
157+
group = Group(name=name,
158+
stream_id=signal_streams[stream_index]['id'])
159+
bl.groups.append(group)
160+
sub_stream_groups.append(group)
151161

152162
if create_group_across_segment['SpikeTrain']:
153-
unit_channels = self.header['unit_channels']
163+
spike_channels = self.header['spike_channels']
154164
st_groups = []
155-
for c in range(unit_channels.size):
165+
for c in range(spike_channels.size):
156166
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)
167+
group.annotate(unit_name=spike_channels[c]['name'])
168+
group.annotate(unit_id=spike_channels[c]['id'])
162169
bl.groups.append(group)
163170
st_groups.append(group)
164171

@@ -183,7 +190,7 @@ def read_block(self, block_index=0, lazy=False,
183190
for seg in bl.segments:
184191
if create_group_across_segment['AnalogSignal']:
185192
for c, anasig in enumerate(seg.analogsignals):
186-
sig_groups[c].add(anasig)
193+
sub_stream_groups[c].add(anasig)
187194

188195
if create_group_across_segment['SpikeTrain']:
189196
for c, sptr in enumerate(seg.spiketrains):
@@ -231,38 +238,67 @@ def read_segment(self, block_index=0, seg_index=0, lazy=False,
231238
signal_group_mode = self._prefered_signal_group_mode
232239

233240
# annotations
234-
seg_annotations = dict(self.raw_annotations['blocks'][block_index]['segments'][seg_index])
235-
for k in ('signals', 'units', 'events'):
241+
seg_annotations = self.raw_annotations['blocks'][block_index]['segments'][seg_index].copy()
242+
for k in ('signals', 'spikes', 'events'):
236243
seg_annotations.pop(k)
237244
seg_annotations = check_annotations(seg_annotations)
238245

239246
seg = Segment(index=seg_index, **seg_annotations)
240247

241248
# 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)
249+
#~ signal_channels = self.header['signal_channels']
250+
#~ if signal_channels.size > 0:
251+
#~ channel_indexes_list = self.get_group_signal_channel_indexes()
252+
#~ for channel_indexes in channel_indexes_list:
253+
#~ for i, (ind_within, ind_abs) in self._make_signal_channel_subgroups(
254+
#~ channel_indexes,
255+
#~ signal_group_mode=signal_group_mode).items():
256+
#~ # make a proxy...
257+
#~ anasig = AnalogSignalProxy(rawio=self, global_channel_indexes=ind_abs,
258+
#~ block_index=block_index, seg_index=seg_index)
259+
260+
#~ if not lazy:
261+
#~ # ... and get the real AnalogSIgnal if not lazy
262+
#~ anasig = anasig.load(time_slice=time_slice, strict_slicing=strict_slicing)
263+
#~ # TODO magnitude_mode='rescaled'/'raw'
264+
265+
#~ anasig.segment = seg
266+
#~ seg.analogsignals.append(anasig)
267+
268+
# AnalogSignal
269+
#~ signal_streams = self.header['signal_streams']
270+
#~ for stream_index in range(len(signal_streams)):
271+
#~ anasig = AnalogSignalProxy(rawio=self, stream_index=stream_index,
272+
#~ block_index=block_index, seg_index=seg_index)
273+
#~ if not lazy:
274+
#~ # ... and get the real AnalogSIgnal if not lazy
275+
#~ anasig = anasig.load(time_slice=time_slice, strict_slicing=strict_slicing)
276+
277+
#~ anasig.segment = seg
278+
#~ seg.analogsignals.append(anasig)
279+
signal_streams = self.header['signal_streams']
280+
sub_streams = self.get_sub_signal_streams(signal_group_mode)
281+
for sub_stream in sub_streams:
282+
stream_index, inner_stream_channels, name = sub_stream
283+
anasig = AnalogSignalProxy(rawio=self, stream_index=stream_index,
284+
inner_stream_channels=inner_stream_channels,
285+
block_index=block_index, seg_index=seg_index)
286+
anasig.name = name
287+
288+
if not lazy:
289+
# ... and get the real AnalogSIgnal if not lazy
290+
anasig = anasig.load(time_slice=time_slice, strict_slicing=strict_slicing)
291+
292+
anasig.segment = seg
293+
seg.analogsignals.append(anasig)
294+
295+
260296

261297
# SpikeTrain and waveforms (optional)
262-
unit_channels = self.header['unit_channels']
263-
for unit_index in range(len(unit_channels)):
298+
spike_channels = self.header['spike_channels']
299+
for spike_channel_index in range(len(spike_channels)):
264300
# make a proxy...
265-
sptr = SpikeTrainProxy(rawio=self, unit_index=unit_index,
301+
sptr = SpikeTrainProxy(rawio=self, spike_channel_index=spike_channel_index,
266302
block_index=block_index, seg_index=seg_index)
267303

268304
if not lazy:
@@ -295,37 +331,92 @@ def read_segment(self, block_index=0, seg_index=0, lazy=False,
295331
seg.create_many_to_one_relationship()
296332
return seg
297333

298-
def _make_signal_channel_subgroups(self, channel_indexes,
299-
signal_group_mode='group-by-same-units'):
334+
def get_sub_signal_streams(self, signal_group_mode='group-by-same-units'):
300335
"""
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).
307-
308-
This method aggregate signal channels with same units or split them all.
336+
When a signal streams don't have homogeneous si units accros channels.
337+
They have to be splitted in sub streams to construct AnalogSignal (unique units).
338+
339+
They function also help to split each channel into one AnalogSignal like in
340+
old neo (<=0.5).
341+
309342
"""
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
343+
signal_streams = self.header['signal_streams']
344+
signal_channels = self.header['signal_channels']
345+
346+
sub_streams = []
347+
for stream_index in range(len(signal_streams)):
348+
stream_id = signal_streams[stream_index]['id']
349+
stream_name = signal_streams[stream_index]['name']
350+
mask = signal_channels['stream_id'] == stream_id
351+
channels = signal_channels[mask]
352+
if signal_group_mode == 'group-by-same-units':
353+
# standard behavior
354+
355+
## this do not keep the original order
356+
## all_units = np.unique(channels['units'])
357+
# so python loop
358+
all_units = []
359+
for units in channels['units']:
360+
if units not in all_units:
361+
all_units.append(units)
362+
363+
if len(all_units) == 1:
364+
#no substream
365+
inner_stream_channels = None # None iwill be transform as slice later
366+
name = stream_name
367+
sub_stream = (stream_index, inner_stream_channels, name)
368+
sub_streams.append(sub_stream)
369+
else:
370+
for units in all_units:
371+
inner_stream_channels, = np.nonzero(channels['units'] == units)
372+
chan_names = channels[inner_stream_channels]['name']
373+
name = 'Channels: (' + ' '.join(chan_names) + ')'
374+
sub_stream = (stream_index, inner_stream_channels, name)
375+
sub_streams.append(sub_stream)
376+
elif signal_group_mode == 'split-all':
377+
# mimic all neo <= 0.5 behavior
378+
for i, channel in enumerate(channels):
379+
inner_stream_channels = [i]
380+
name = channels[i]['name']
381+
sub_stream = (stream_index, inner_stream_channels, name)
382+
sub_streams.append(sub_stream)
383+
else:
384+
raise (NotImplementedError)
385+
386+
return sub_streams
387+
388+
389+
#~ def _make_signal_channel_subgroups(self, channel_indexes,
390+
#~ signal_group_mode='group-by-same-units'):
391+
#~ """
392+
#~ For some RawIO channel are already splitted in groups.
393+
#~ But in any cases, channel need to be splitted again in sub groups
394+
#~ because they do not have the same units.
395+
396+
#~ They can also be splitted one by one to match previous behavior for
397+
#~ some IOs in older version of neo (<=0.5).
398+
399+
#~ This method aggregate signal channels with same units or split them all.
400+
#~ """
401+
#~ all_channels = self.header['signal_channels']
402+
#~ if channel_indexes is None:
403+
#~ channel_indexes = np.arange(all_channels.size, dtype=int)
404+
#~ channels = all_channels[channel_indexes]
405+
406+
#~ groups = collections.OrderedDict()
407+
#~ if signal_group_mode == 'group-by-same-units':
408+
#~ all_units = np.unique(channels['units'])
409+
410+
#~ for i, unit in enumerate(all_units):
411+
#~ ind_within, = np.nonzero(channels['units'] == unit)
412+
#~ ind_abs = channel_indexes[ind_within]
413+
#~ groups[i] = (ind_within, ind_abs)
414+
415+
#~ elif signal_group_mode == 'split-all':
416+
#~ for i, chan_index in enumerate(channel_indexes):
417+
#~ ind_within = [i]
418+
#~ ind_abs = channel_indexes[ind_within]
419+
#~ groups[i] = (ind_within, ind_abs)
420+
#~ else:
421+
#~ raise (NotImplementedError)
422+
#~ return groups

0 commit comments

Comments
 (0)