self.protocol=self._get_protocol(self.subject)self.readers={k:getattr(readers,v)fork,vinself.reader_names.items()}
+ self.reader_protocols={k:getattr(readers,v).protocolsfork,vinself.reader_names.items()}
- def_load_index(self):
+ def_load_index(self)->pd.DataFrame:"""Loads the data index. Used internally to determine montage and localization nubmers. """
- ifCMLReader._indexisNone:
- CMLReader._index=get_data_index(self.protocol,rootdir=self.rootdir)
+ index=get_data_index(self.protocol,rootdir=self.rootdir)
- # Some subjects don't explicitly specify localization/montage
- # numbers in the index, so they appear as NaNs.
- CMLReader._index.montage.replace({np.nan:"0"},inplace=True)
- CMLReader._index.localization.replace({np.nan:"0"},inplace=True)
+ # Some subjects don't explicitly specify localization/montage
+ # numbers in the index, so they appear as NaNs.
+ try:
+ index["montage"].replace({np.nan:"0"},inplace=True)
+ index["localization"].replace({np.nan:"0"},inplace=True)
+ exceptKeyError:
+ # We're using a protocol that doesn't include localization data
+ # (e.g., ltp)
+ pass
+
+ returnindex@staticmethoddef_get_protocol(subject:str)->str:
@@ -247,9 +254,11 @@
- (start_index, stop_index) - (start_index, stop_index, file_number) when the EEG
- for the session is is split over multiple recordings.
+ for the session is is split over multiple recordings. Incompatible with passing ``events``. scheme
@@ -435,7 +452,7 @@
[docs]defmilliseconds_to_samples(millis:Union[int,float],
+ sample_rate:Union[int,float])->int:
+ """Covert times in milliseconds to number of samples.
+
+ Parameters
+ ----------
+ millis
+ Time in ms.
+ sample_rate
+ Sample rate in samples per second.
+
+ Returns
+ -------
+ Number of samples.
+
+ """
+ returnint(sample_rate*millis/1000.)
+
+
+
[docs]defsamples_to_milliseconds(samples:int,
+ sample_rate:Union[int,float])->Union[int,float]:
+ """Convert samples to milliseconds.
+
+ Parameters
+ ----------
+ samples
+ Number of samples.
+ sample_rate
+ Sample rate in samples per second.
+
+ Returns
+ -------
+ Samples converted to milliseconds.
+
+ """
+ return1000*samples/sample_rate
+
+
+
[docs]defmilliseconds_to_events(onsets:List[Union[int,float]],
+ sample_rate:Union[int,float])->pd.DataFrame:
+ """Take times and produce a minimal events :class:`pd.DataFrame` to load
+ EEG data with.
+
+ Parameters
+ ----------
+ onsets
+ Onset times in ms.
+ sample_rate
+ Sample rate in samples per second.
+
+ Returns
+ -------
+ events
+ A :class:`pd.DataFrame` with ``eegoffset`` as the only column.
+
+ """
+ samples=[milliseconds_to_samples(onset,sample_rate)foronsetinonsets]
+ returnpd.DataFrame({"eegoffset":samples})
+
+
+
[docs]defevents_to_epochs(events:pd.DataFrame,rel_start:int,rel_stop:int,
+ sample_rate:Union[int,float],
+ basenames:Optional[List[str]]=None
+ )->List[Tuple[int,int,int]]:
+ """Convert events to epochs.
+
+ Parameters
+ ----------
+ events
+ Events to read.
+ rel_start
+ Start time relative to events in ms.
+ rel_stop
+ Stop time relative to events in ms.
+ sample_rate
+ Sample rate in Hz.
+
+ Returns
+ -------
+ epochs
+ A list of tuples giving absolute start and stop times in number of
+ samples.
+
+ """
+ rel_start=milliseconds_to_samples(rel_start,sample_rate)
+ rel_stop=milliseconds_to_samples(rel_stop,sample_rate)
+ offsets=events.eegoffset.values
+ ifbasenamesisnotNone:
+ eegfiles=events.eegfile.values
+ epochs=[(offset+rel_start,offset+rel_stop,
+ basenames.index(eegfile))
+ for(offset,eegfile)inzip(offsets,eegfiles)]
+ else:
+ epochs=[(offset+rel_start,offset+rel_stop,0)
+ foroffsetinoffsets]
+ returnepochs