Note
Click here to download the full example code
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].
Run a few
mne_hfo.base.Detector
instances to detect HFOsFormat the detected HFOs as a
pandas.DataFrame
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.
show the contents of the BIDS dataset
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.
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)