02. Detect HFOs on BIDS Dataset#

MNE-HFO requires strict adherence to the BIDS specification for EEG/iEEG data. It currently depends on the data structures defined by MNE-Python and MNE-BIDS.

In this example, we use MNE-BIDS to load real raw data and then use MNE-HFO to detect HFOs. Specifically, we will follow these steps:

1. Load data via mne_bids.read_raw_bids(). We will load a sample subject from the Fedele dataset [1].

  1. Run a few mne_hfo.base.Detector instances to detect HFOs

  2. Format the detected HFOs as a pandas.DataFrame

  3. Write to disk according to BEP-021 and read it in again.

References#

[1] Fedele T, Burnos S, Boran E, Krayenbühl N, Hilfiker P, Grunwald T, Sarnthein J.

Resection of high frequency oscillations predicts seizure outcome in the individual patient. Scientific Reports. 2017;7(1):13836. https://www.nature.com/articles/s41598-017-13064-1. doi:10.1038/s41598-017-13064-1

# Authors: Adam Li <adam2392@gmail.com>
#

We are importing everything we need for this example:

from pathlib import Path

from mne_bids import BIDSPath, read_raw_bids, make_report, print_dir_tree

from mne_hfo import (RMSDetector, write_annotations,
                     read_annotations)

Load the data#

First, we need some data to work with. We will use the test dataset available with the repository under data/ directory.

# root of BIDs dataset
root = Path('../mne_hfo/tests/data/')

# BIDS entities
subject = '01'
task = 'interictalsleep'
run = '01'
datatype = 'ieeg'

show the contents of the BIDS dataset

print_dir_tree(root)

# Let's summarize the dataset.
print(make_report(root, verbose=False))
|data/
|--- .bidsignore
|--- README
|--- dataset_description.json
|--- participants.json
|--- participants.tsv
|--- derivatives/
|------ sub-01/
|--------- ieeg/
|------------ sub-01_task-interictalsleep_run-01_annotations.json
|------------ sub-01_task-interictalsleep_run-01_annotations.tsv
|--- sub-01/
|------ sub-01_scans.tsv
|------ ieeg/
|--------- sub-01_task-interictalsleep_run-01_channels.tsv
|--------- sub-01_task-interictalsleep_run-01_events.tsv
|--------- sub-01_task-interictalsleep_run-01_ieeg.eeg
|--------- sub-01_task-interictalsleep_run-01_ieeg.json
|--------- sub-01_task-interictalsleep_run-01_ieeg.vhdr
|--------- sub-01_task-interictalsleep_run-01_ieeg.vmrk
 The Fedele-epilepsy-HFO-iEEG Dataset dataset was created by Fedele T, Burnos S,
Boran E, Krayenbühl N, Hilfiker P, Grunwald T, and Sarnthein J and conforms to
BIDS version 1.4.0. This report was generated with MNE-BIDS
(https://doi.org/10.21105/joss.01896). The dataset consists of 1 participants
(comprised of 1 male and 0 female participants; handedness were all unknown;
ages ranged from 25.0 to 25.0 (mean = 25.0, std = 0.0)) . Data was recorded
using an iEEG system (Elekta) sampled at 2000.0 Hz with line noise at 50.0 Hz.
There was 1 scan in total. Recording durations ranged from 5.0 to 5.0 seconds
(mean = 5.0, std = 0.0), for a total of 5.0 seconds of data recorded over all
scans. For each dataset, there were on average 50.0 (std = 0.0) recording
channels per scan, out of which 50.0 (std = 0.0) were used in analysis (0.0 +/-
0.0 were removed from analysis).

Load the dataset.

bids_path = BIDSPath(subject=subject, task=task,
                     run=run, datatype=datatype, root=root,
                     suffix='ieeg', extension='.vhdr')
raw = read_raw_bids(bids_path)
Extracting parameters from ../mne_hfo/tests/data/sub-01/ieeg/sub-01_task-interictalsleep_run-01_ieeg.vhdr...
Setting channel info structure...
Reading events from ../mne_hfo/tests/data/sub-01/ieeg/sub-01_task-interictalsleep_run-01_events.tsv.
Reading channel info from ../mne_hfo/tests/data/sub-01/ieeg/sub-01_task-interictalsleep_run-01_channels.tsv.
/home/circleci/project/examples/01_working_with_bids.py:73: RuntimeWarning: Did not find any electrodes.tsv associated with sub-01_task-interictalsleep_run-01.

The search_str was "../mne_hfo/tests/data/sub-01/**/ieeg/sub-01*electrodes.tsv"
  raw = read_raw_bids(bids_path)
/home/circleci/project/examples/01_working_with_bids.py:73: RuntimeWarning: Did not find any coordsystem.json associated with sub-01_task-interictalsleep_run-01.

The search_str was "../mne_hfo/tests/data/sub-01/**/ieeg/sub-01*coordsystem.json"
  raw = read_raw_bids(bids_path)

Let’s plot the data and see what it looks like raw.plot()

Detect HFOs#

All detectors inherit from the base class mne_hfo.base.Detector, which inherits from the sklearn.base.BaseEstimator class. To run any estimator, one instantiates it along with the hyper-parameters, and then calls the fit function. Afterwards, detected HFOs are available in the various data structures. The recommended usage is the DataFrame, which is accessible via the mne_hfo.base.Detector.to_data_frame property.

kwargs = {
    'threshold': 3,  # threshold for "significance"
    'win_size': 100,  # window size in samples
    'overlap': 0.25  # overlap in percentage relative to the window size
}
detector = RMSDetector(**kwargs)

# run detector
detector.fit(X=raw)

# get the HFO results as an annotations.tsv DataFrame
annot_df = detector.to_data_frame(format='bids')
print(annot_df.head())
  0%|          | 0/50 [00:00<?, ?it/s]
 32%|███▏      | 16/50 [00:00<00:00, 156.21it/s]
 64%|██████▍   | 32/50 [00:00<00:00, 137.09it/s]
 92%|█████████▏| 46/50 [00:00<00:00, 94.32it/s]
100%|██████████| 50/50 [00:00<00:00, 113.39it/s]
  onset  ...   sfreq
0   0.0  ...  2000.0
1   0.0  ...  2000.0
2   0.0  ...  2000.0
3   0.0  ...  2000.0
4   0.0  ...  2000.0

[5 rows x 6 columns]
   onset  ...   sfreq
0    0.0  ...  2000.0
1    0.0  ...  2000.0
2    0.0  ...  2000.0
3    0.0  ...  2000.0
4    0.0  ...  2000.0

[5 rows x 6 columns]

Convert HFO events to annotations#

Detectors output HFO events detected as a DataFrame fashioned after the *_events.tsv files in BIDS-iEEG. Instead, HFO events are indeed Derivatives of the Raw data, that are estimated/detected using mne-hfo. The correct way to store them is in terms of an *_annotations.tsv, according to the BIDS-Derivatives specification.

# alternatively save annotation dataframe to disc
annot_path = bids_path.copy().update(suffix='annotations',
                                     root=root / 'derivatives',
                                     extension='.tsv',
                                     check=False)

intended_for = raw.filenames[0]
write_annotations(annot_df, fname=annot_path,
                  intended_for=intended_for, root=root)
print(annot_df.head())
inside write... sub-01_task-interictalsleep_run-01_ieeg.vhdr
   onset  ...   sfreq
0    0.0  ...  2000.0
1    0.0  ...  2000.0
2    0.0  ...  2000.0
3    0.0  ...  2000.0
4    0.0  ...  2000.0

[5 rows x 6 columns]

Read data back in#

The data will match what was written. In addition, you can check for overlapping HFOs.

annot_df = read_annotations(annot_path)

print(annot_df.head())
sub-01_task-interictalsleep_run-01_ieeg.vhdr
raw fpath:  ../mne_hfo/tests/data/sub-01/ieeg/sub-01_task-interictalsleep_run-01_ieeg.vhdr
Extracting parameters from ../mne_hfo/tests/data/sub-01/ieeg/sub-01_task-interictalsleep_run-01_ieeg.vhdr...
Setting channel info structure...
Reading events from ../mne_hfo/tests/data/sub-01/ieeg/sub-01_task-interictalsleep_run-01_events.tsv.
Reading channel info from ../mne_hfo/tests/data/sub-01/ieeg/sub-01_task-interictalsleep_run-01_channels.tsv.
   onset  ...   sfreq
0    0.0  ...  2000.0
1    0.0  ...  2000.0
2    0.0  ...  2000.0
3    0.0  ...  2000.0
4    0.0  ...  2000.0

[5 rows x 6 columns]

Total running time of the script: (0 minutes 2.416 seconds)

Estimated memory usage: 14 MB

Gallery generated by Sphinx-Gallery