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, events_to_annotations, 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('../data/')

# BIDS entities
subject = '01'
session = '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))

Out:

|data/
|--- .bidsignore
|--- README
|--- dataset_description.json
|--- participants.json
|--- participants.tsv
|--- derivatives/
|------ sub-01/
|--------- ses-interictalsleep/
|------------ ieeg/
|--------------- sub-01_ses-interictalsleep_run-01_annotations.json
|--------------- sub-01_ses-interictalsleep_run-01_annotations.tsv
|--- sub-01/
|------ ses-interictalsleep/
|--------- sub-01_ses-interictalsleep_scans.tsv
|--------- ieeg/
|------------ sub-01_ses-interictalsleep_run-01_channels.tsv
|------------ sub-01_ses-interictalsleep_run-01_events.tsv
|------------ sub-01_ses-interictalsleep_run-01_ieeg.eeg
|------------ sub-01_ses-interictalsleep_run-01_ieeg.json
|------------ sub-01_ses-interictalsleep_run-01_ieeg.vhdr
|------------ sub-01_ses-interictalsleep_run-01_ieeg.vmrk
Summarizing participants.tsv ../data/participants.tsv...
The Fedele-epilepsy-HFO-iEEG Dataset dataset was created with BIDS version 1.4.0
by Fedele T, Burnos S, Boran E, Krayenbühl N, Hilfiker P, Grunwald T, and
Sarnthein J. This report was generated with MNE-BIDS
(https://doi.org/10.21105/joss.01896). The dataset consists of 1 participants
(comprised of 1 men and 0 women; handedness were all unknown; ages ranged from
25.0 to 25.0 (mean = 25.0, std = 0.0))and 1 recording sessions: interictalsleep.
Data was recorded using a iEEG system (Elekta manufacturer) 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, session=session,
                     run=run, datatype=datatype, root=root,
                     suffix='ieeg', extension='.vhdr')
raw = read_raw_bids(bids_path)

Out:

Extracting parameters from ../data/sub-01/ses-interictalsleep/ieeg/sub-01_ses-interictalsleep_run-01_ieeg.vhdr...
Setting channel info structure...
Reading events from ../data/sub-01/ses-interictalsleep/ieeg/sub-01_ses-interictalsleep_run-01_events.tsv.
Reading channel info from ../data/sub-01/ses-interictalsleep/ieeg/sub-01_ses-interictalsleep_run-01_channels.tsv.
/Users/adam2392/Documents/mne-hfo/examples/working_with_bids.py:73: RuntimeWarning: Did not find any electrodes.tsv associated with sub-01_ses-interictalsleep_run-01.

The search_str was "../data/sub-01/**/sub-01_ses-interictalsleep*electrodes.tsv"
  raw = read_raw_bids(bids_path)
/Users/adam2392/Documents/mne-hfo/examples/working_with_bids.py:73: RuntimeWarning: Did not find any coordsystem.json associated with sub-01_ses-interictalsleep_run-01.

The search_str was "../data/sub-01/**/sub-01_ses-interictalsleep*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.hfo_df 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 events.tsv DataFrame
event_df = detector.hfo_event_df
print(event_df.head())

Out:

  0%|          | 0/50 [00:00<?, ?it/s]
 64%|######4   | 32/50 [00:00<00:00, 305.47it/s]
100%|##########| 50/50 [00:00<00:00, 200.48it/s]
    onset  duration  sample trial_type
0  4.6250    0.0625    9250   hfo_IAR2
1  1.1750    0.0625    2350   hfo_IAR3
2  2.1875    0.0750    4375   hfo_IAR3
3  2.5750    0.0750    5150   hfo_IAR3
4  1.3125    0.0625    2625   hfo_IAR4

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.

# convert event df -> annotation df
annot_df = events_to_annotations(event_df)

# 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())

Out:

    onset  duration label channels  sample
0  4.6250    0.0625   hfo     IAR2  9250.0
1  1.1750    0.0625   hfo     IAR3  2350.0
2  2.1875    0.0750   hfo     IAR3  4375.0
3  2.5750    0.0750   hfo     IAR3  5150.0
4  1.3125    0.0625   hfo     IAR4  2625.0

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())

Out:

Extracting parameters from ../data/sub-01/ses-interictalsleep/ieeg/sub-01_ses-interictalsleep_run-01_ieeg.vhdr...
Setting channel info structure...
Reading events from ../data/sub-01/ses-interictalsleep/ieeg/sub-01_ses-interictalsleep_run-01_events.tsv.
Reading channel info from ../data/sub-01/ses-interictalsleep/ieeg/sub-01_ses-interictalsleep_run-01_channels.tsv.
/Users/adam2392/Documents/mne-hfo/mne_hfo/io.py:364: RuntimeWarning: Did not find any electrodes.tsv associated with sub-01_ses-interictalsleep_run-01.

The search_str was "../data/sub-01/**/sub-01_ses-interictalsleep*electrodes.tsv"
  raw = read_raw_bids(raw_fpath)
/Users/adam2392/Documents/mne-hfo/mne_hfo/io.py:364: RuntimeWarning: Did not find any coordsystem.json associated with sub-01_ses-interictalsleep_run-01.

The search_str was "../data/sub-01/**/sub-01_ses-interictalsleep*coordsystem.json"
  raw = read_raw_bids(raw_fpath)
    onset  duration label channels  sample
0  4.6250    0.0625   hfo     IAR2  9250.0
1  1.1750    0.0625   hfo     IAR3  2350.0
2  2.1875    0.0750   hfo     IAR3  4375.0
3  2.5750    0.0750   hfo     IAR3  5150.0
4  1.3125    0.0625   hfo     IAR4  2625.0

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

Gallery generated by Sphinx-Gallery