Esempio n. 1
0
    def __init__(self, subject, experiment, session, outdir, rootdir=None):
        self.rootdir = get_root_dir(rootdir)
        self.outdir = Path(self.rootdir).joinpath(outdir)
        self.reader = CMLReader(subject, experiment, session, rootdir=rootdir)

        sources_filename = self.reader.path_finder.find("sources")
        with open(sources_filename, "r") as infile:
            self.sources = json.load(infile)

        self.eeg_files = [
            sorted(
                Path(sources_filename).parent.joinpath("noreref").glob(
                    info["name"] + "*")) for info in self.sources.values()
        ]
Esempio n. 2
0
def test_get_root_dir(path, with_env_var):
    with set_cml_root("/override" if with_env_var else None):

        root = get_root_dir(path)

        if with_env_var:
            if path is None:
                assert root == os.environ["CML_ROOT"]
            else:
                assert root == path
        else:
            if path is None:
                assert root == "/"
            else:
                assert root == path
Esempio n. 3
0
    def as_timeseries(self, events: pd.DataFrame,
                      rel_start: Union[float, int],
                      rel_stop: Union[float, int]) -> EEGContainer:
        """Read the timeseries.

        Parameters
        ----------
        events
            Events to read EEG data from
        rel_start
            Relative start times in ms
        rel_stop
            Relative stop times in ms

        Returns
        -------
        A time series with shape (channels, epochs, time). By default, this
        returns data as it was physically recorded (e.g., if recorded with a
        common reference, each channel will be a contact's reading referenced
        to the common reference, a.k.a. "monopolar channels").

        Raises
        ------
        RereferencingNotPossibleError
            When rereferencing is not possible.

        """
        eegs = []

        # sanity check on the offsets

        if rel_start != 0 and rel_stop != -1 and rel_start > rel_stop:
            raise ValueError('rel_start must precede rel_stop')

        for filename in events["eegfile"].unique():
            # select subset of events for this basename
            ev = events[events["eegfile"] == filename]

            # determine experiment, session, dtype, and sample rate
            experiment = ev["experiment"].unique()[0]
            session = ev["session"].unique()[0]
            basename = os.path.basename(filename)
            finder = PathFinder(subject=self.subject,
                                experiment=experiment,
                                session=session,
                                eeg_basename=basename,
                                rootdir=self.rootdir)
            sources = EEGMetaReader.fromfile(finder.find("sources"),
                                             subject=self.subject)
            sample_rate = sources["sample_rate"]
            dtype = sources["data_format"]
            is_scalp = dtype in (".bdf", ".raw", ".mff")

            # Convert events to epochs (onset & offset times)
            if rel_start == 0 and rel_stop == -1 and len(events) == 1:
                epochs = [(0, None)]
            else:
                epochs = convert.events_to_epochs(ev, rel_start, rel_stop,
                                                  sample_rate)

            # Scalp EEG reader requires onsets, rel_start (in sec), and rel_
            # stop (in sec) to cut data into epochs
            if is_scalp:
                on_off_epochs = epochs  # The onset & offset times will still
                # be passed to the EEGContainer later
                if rel_start == 0 and rel_stop == -1 and len(events) == 1:
                    epochs = None
                else:
                    epochs = np.zeros((len(ev), 3), dtype=int)
                    epochs[:, 0] = ev["eegoffset"]
                    epochs = dict(epochs=epochs, tmin=rel_start / 1000.,
                                  tmax=rel_stop / 1000.)

            root = get_root_dir(self.rootdir)
            eeg_filename = os.path.join(root, filename.lstrip("/"))
            reader_class = self._get_reader_class(filename)
            reader = reader_class(filename=eeg_filename,
                                  dtype=dtype,
                                  epochs=epochs,
                                  scheme=self.scheme,
                                  clean=self.clean)
            # if scalp EEG, info is an MNE Info object; if iEEG, info is a list
            # of contacts
            data, info = reader.read()

            attrs = {}
            if is_scalp:
                # Pass MNE info and events as extra attributes, to be able to
                # fully reconstruct MNE Raw/Epochs objects
                attrs["mne_info"] = info
                channels = info["ch_names"]
                if epochs is not None:
                    # Crop out any events/epoch times that ran beyond the
                    # bounds of the EEG recording
                    te_pre = info["truncated_events_pre"] \
                        if info["truncated_events_pre"] > 0 else None
                    te_post = -info["truncated_events_post"] \
                        if info["truncated_events_post"] > 0 else None
                    on_off_epochs = on_off_epochs[te_pre:te_post]
                    ev = ev[te_pre:te_post]
                # Pass the onset & offset time epoch list to EEGContainer, NOT
                # the MNE-formatted epoch list
                epochs = on_off_epochs
            elif self.scheme is not None:
                data, channels = reader.rereference(data, info)
            else:
                channels = ["CH{}".format(n + 1) for n in range(data.shape[1])]

            eegs.append(
                EEGContainer(
                    data,
                    sample_rate,
                    epochs=epochs,
                    events=ev,
                    channels=channels,
                    tstart=rel_start,
                    attrs=attrs
                )
            )

        eegs = EEGContainer.concatenate(eegs)
        eegs.attrs["rereferencing_possible"] = reader.rereferencing_possible
        return eegs
Esempio n. 4
0
    def as_timeseries(self, events: pd.DataFrame, rel_start: Union[float, int],
                      rel_stop: Union[float, int]) -> EEGContainer:
        """Read the timeseries.

        Parameters
        ----------
        events
            Events to read EEG data from
        rel_start
            Relative start times in ms
        rel_stop
            Relative stop times in ms

        Returns
        -------
        A time series with shape (channels, epochs, time). By default, this
        returns data as it was physically recorded (e.g., if recorded with a
        common reference, each channel will be a contact's reading referenced to
        the common reference, a.k.a. "monopolar channels").

        Raises
        ------
        RereferencingNotPossibleError
            When rereferencing is not possible.

        """
        eegs = []

        for filename in events["eegfile"].unique():
            # select subset of events for this basename
            ev = events[events["eegfile"] == filename]

            # determine experiment, session, dtype, and sample rate
            experiment = ev["experiment"].unique()[0]
            session = ev["session"].unique()[0]
            finder = PathFinder(subject=self.subject,
                                experiment=experiment,
                                session=session,
                                rootdir=self.rootdir)
            sources = EEGMetaReader.fromfile(finder.find("sources"),
                                             subject=self.subject)
            sample_rate = sources["sample_rate"]
            dtype = sources["data_format"]

            # convert events to epochs
            if rel_stop < 0:
                # We're trying to load to the end of the session. Only allow
                # this in cases where we're trying to load a whole session.
                if len(events) > 1:
                    raise ValueError("rel_stop must not be negative")
                epochs = [(0, None)]
            else:
                epochs = convert.events_to_epochs(ev, rel_start, rel_stop,
                                                  sample_rate)

            root = get_root_dir(self.rootdir)
            eeg_filename = os.path.join(root, filename.lstrip("/"))
            reader_class = self._get_reader_class(filename)
            reader = reader_class(filename=eeg_filename,
                                  dtype=dtype,
                                  epochs=epochs,
                                  scheme=self.scheme)
            data, contacts = reader.read()

            if self.scheme is not None:
                data, labels = reader.rereference(data, contacts)
                channels = labels
            else:
                channels = ["CH{}".format(n + 1) for n in range(data.shape[1])]

            eegs.append(
                EEGContainer(
                    data,
                    sample_rate,
                    epochs=epochs,
                    events=ev,
                    channels=channels,
                    tstart=rel_start,
                ))

        eegs = EEGContainer.concatenate(eegs)
        eegs.attrs["rereferencing_possible"] = reader.rereferencing_possible
        return eegs