44The RawIO assumes all segments and all blocks have the same structure.
55It supports all kinds of NEO objects.
66
7- Author: Chek Yin Choi
7+ Author: Chek Yin Choi, Julia Sprenger
88"""
99
10- from .baserawio import (BaseRawIO , _signal_channel_dtype , _signal_stream_dtype ,
11- _spike_channel_dtype , _event_channel_dtype )
10+ import os .path
1211
13- from ..io .nixio import NixIO
14- from ..io .nixio import check_nix_version
1512import numpy as np
13+
14+ from .baserawio import (BaseRawIO , _signal_channel_dtype , _signal_stream_dtype ,
15+ _spike_channel_dtype , _event_channel_dtype )
16+ from ..io .nixio import check_nix_version
17+
1618try :
1719 import nixio as nix
1820
@@ -50,7 +52,7 @@ def _source_name(self):
5052 def _parse_header (self ):
5153 self .file = nix .File .open (self .filename , nix .FileMode .ReadOnly )
5254 signal_channels = []
53- size_list = []
55+ anasig_ids = { 0 : []} # ids of analogsignals by segment
5456 stream_ids = []
5557 for bl in self .file .blocks :
5658 for seg in bl .groups :
@@ -61,19 +63,18 @@ def _parse_header(self):
6163 units = str (da .unit )
6264 dtype = str (da .dtype )
6365 sr = 1 / da .dimensions [0 ].sampling_interval
64- da_leng = da .size
65- if da_leng not in size_list :
66- size_list .append (da_leng )
67- stream_ids .append (str (len (size_list )))
68- # very important! group_id use to store
69- # channel groups!!!
70- # use only for different signal length
71- stream_index = size_list .index (da_leng )
72- stream_id = stream_ids [stream_index ]
66+ anasig_id = da .name .split ('.' )[- 2 ]
67+ if anasig_id not in anasig_ids [0 ]:
68+ anasig_ids [0 ].append (anasig_id )
69+ stream_id = anasig_ids [0 ].index (anasig_id )
70+ if stream_id not in stream_ids :
71+ stream_ids .append (stream_id )
7372 gain = 1
7473 offset = 0.
7574 signal_channels .append ((ch_name , chan_id , sr , dtype ,
7675 units , gain , offset , stream_id ))
76+ # only read structure of first segment and assume the same
77+ # across segments
7778 break
7879 break
7980 signal_channels = np .array (signal_channels , dtype = _signal_channel_dtype )
@@ -210,21 +211,6 @@ def _parse_header(self):
210211 props = group .metadata .inherited_properties ()
211212 seg_ann .update (self ._filter_properties (props , "segment" ))
212213
213- # TODO handle annotation at stream level
214- '''
215- sig_idx = 0
216- groupdas = NixIO._group_signals(grp.data_arrays)
217- for nix_name, signals in groupdas.items():
218- da = signals[0]
219- if da.type == 'neo.analogsignal' and seg_ann['signals']:
220- # collect and group DataArrays
221- sig_ann = seg_ann['signals'][sig_idx]
222- sig_chan_ann = self.raw_annotations['signal_channels'][sig_idx]
223- props = da.metadata.inherited_properties()
224- sig_ann.update(self._filter_properties(props, 'analogsignal'))
225- sig_chan_ann.update(self._filter_properties(props, 'analogsignal'))
226- sig_idx += 1
227- '''
228214 sp_idx = 0
229215 ev_idx = 0
230216 for mt in group .multi_tags :
@@ -242,6 +228,38 @@ def _parse_header(self):
242228 event_ann .update (self ._filter_properties (props , 'event' ))
243229 ev_idx += 1
244230
231+ # adding array annotations to analogsignals
232+ annotated_anasigs = []
233+ sig_ann = seg_ann ['signals' ]
234+ # this implementation relies on analogsignals always being
235+ # stored in the same stream order across segments
236+ stream_id = 0
237+ for da_idx , da in enumerate (group .data_arrays ):
238+ if da .type != "neo.analogsignal" :
239+ continue
240+ anasig_id = da .name .split ('.' )[- 2 ]
241+ # skip already annotated signals as each channel already
242+ # contains the complete set of annotations and
243+ # array_annotations
244+ if anasig_id in annotated_anasigs :
245+ continue
246+ annotated_anasigs .append (anasig_id )
247+
248+ # collect annotation properties
249+ props = [p for p in da .metadata .props
250+ if p .type != 'ARRAYANNOTATION' ]
251+ props_dict = self ._filter_properties (props , "analogsignal" )
252+ sig_ann [stream_id ].update (props_dict )
253+
254+ # collect array annotation properties
255+ props = [p for p in da .metadata .props
256+ if p .type == 'ARRAYANNOTATION' ]
257+ props_dict = self ._filter_properties (props , "analogsignal" )
258+ sig_ann [stream_id ]['__array_annotations__' ].update (
259+ props_dict )
260+
261+ stream_id += 1
262+
245263 def _segment_t_start (self , block_index , seg_index ):
246264 t_start = 0
247265 for mt in self .file .blocks [block_index ].groups [seg_index ].multi_tags :
0 commit comments