bugzilla@gpiantoni.com
to the CC list in the bugreport.
Integrate FieldTrip and MNE-Python
Introduction
FieldTrip and MNE-Python offer tools to analyze electrophysiological activity. MNE-Python, with code available at github.com, facilitates the access to the FIFF files and integrates with the MNE suite, written in C (FieldTrip can also use some of the functions in the MNE suite, as explained in the minimum-norm estimate tutorial). In addition, MNE-Python allows for a variety of tools for the analysis of electrophysiological data, as demonstrated in the example gallery.
Primary use cases for the integration of FieldTrip and MNE-Python are
- the ability for MNE users do channel-level time-frequency analysis and sensor-level statistics in FieldTrip.
- the ability for FieldTrip users to do source reconstruction in MNE.
Background
FieldTrip and MNE-Python have similar but not identical processing pipelines. A common pipeline in FieldTrip is to create trials by reading the data directly from disk (in order to have a ft_datatype_raw) and then use this preprocessed data to create ERP (ft_datatype_timelock). In MNE-Python, the whole continuous recording is imported (with the Raw class), then trials are extracted with the Epochs class and finally trials are averaged into the Evoked class. To recap, this is the correspondence between datatypes in the two packages:
Conceptual | FieldTrip | MNE-Python |
---|---|---|
one continuous segment of data | ft_datatype_raw | Raw |
multiple segments of data, e.g. trials | ft_datatype_raw | Epochs 1) |
averaged ERFs for one or multiple conditions | ft_datatype_timelock | Evoked |
Therefore, we will need to import and export Raw, Epochs, and Evoked datatypes.
The aim is to pass the channel=level data between FieldTrip and MNE. Reading is implemented through the ft_read_header and ft_read_data functions. Writing is implemented through the ad-hoc fieldtrip2fiff function.
Procedure
datatype_raw (one trial) <-> Raw
For these examples, we'll use the example data of dataset 10. Download TactileStimulusDipolefit.zip and extract the .ds
folder in a convenient location.
Export to Raw
First, we read the data, as usual:
cfg = []; cfg.dataset = 'MarkusBraille.ds'; cfg.trialdef.triallength = Inf; cfg = ft_definetrial(cfg); cfg.continuous = 'yes'; cfg.channel = {'MEG', '-MLP31', '-MLO12'}; data = ft_preprocessing(cfg);
Then, we export them
fiff_file = 'ctf_raw.fif'; fieldtrip2fiff(fiff_file, data)
This function will also attempt to create an event file, called ctf_raw-eve.fif
. Because the fiff format is less flexible than the Matlab files, events might be recoded using numbers.
You can then read the file into Python (MNE-Python 0.8):
from mne.io import Raw raw = Raw('ctf_raw.fif') print(raw) print(raw.info) from mne import read_events events = read_events('ctf_raw-eve.fif') print(events)
Import Raw
Once you have the data in Python as Raw, you can use the save
method.
raw.save('mne_python_raw.fif')
Then use FieldTrip to read the files:
fiff_file = 'mne_python_raw.fif'; cfg = [] cfg.dataset = fiff_file; data1 = ft_preprocessing(cfg); ft_datatype(data1) % returns 'raw' event = mne_read_events('ctf_raw-eve.fif')
So, data1
is of type datatype_raw
with one trial.
datatype_raw (many trials) <-> Epochs
Export to Epochs
And then in Python, you can read the Epochs
with:
from mne import read_epochs epochs = read_epochs('ctf-epo.fif') print(type(epochs))
Import Epochs
If we have the data as Raw
in MNE-Python, we can create epochs, using the Epochs
class:
from mne import read_events, Epochs from mne.fiff import Raw raw = Raw('ctf_raw.fif') events = read_events('ctf_raw-eve.fif') print(events) # create events based on the index in the third column of events event_ids = {'eventA': 4, 'eventB': 8} tmin = -0.5 tmax = 1 epochs = Epochs(raw, events, event_ids, tmin, tmax, baseline=(None, 0)) epochs.save('mne_python-epo.fif') mne.write_events('mne_python-eve.fif', epochs.events)
And then in Matlab:
fiff_file = 'mne_python-epo.fif'; events_file = 'mne_python-eve.fif'; cfg = []; cfg.dataset = fiff_file; data1 = ft_preprocessing(cfg); event_file = mne_read_events(events_file); data1.trialinfo = event_file(:,3); data1.cfg.trl(:,4) = event_file(:,3); ft_datatype(data1) % returns 'raw'
where data1
contains the data organized in multiple trials.
Better, one could also use the inbuilt-function ft_definetrial:
fiff_file = 'mne_python-epo.fif'; cfg = []; cfg.dataset = fiff_file_epo; cfg.trialdef.eventtype = 'trial'; cfg.trialfun = 'ft_trialfun_general'; cfg = ft_definetrial(cfg);
where data1
contains the data organized in multiple trials including condition labelling.
datatype_timelock <-> Evoked
Export to Evoked
Create evoked in FieldTrip:
cfg = []; cfg.dataset = 'MarkusBraille.ds'; cfg.trialdef.eventtype = 'backpanel trigger'; cfg.trialdef.prestim = 1; cfg.trialdef.poststim = 2; cfg.trialdef.eventvalue = 3; % event value of FIC cfg = ft_definetrial(cfg); cfg.channel = {'MEG', '-MLP31', '-MLO12'}; % read all MEG channels except MLP31 and MLO12 data = ft_preprocessing(cfg); cfg = []; avg = ft_timelockanalysis(cfg, data); fiff_file = 'ctf-ave.fif'; fieldtrip2fiff(fiff_file, avg)
Now we can read it in MNE-Python:
from mne.fiff import read_evoked evoked = read_evoked('ctf-ave.fif') print(type(evoked))
Import Evoked
We just continue using the instance epochs
that was defined before. We then create an instance of class Evoked
using the method average
:
evoked = epochs.average() print(type(evoked)) # returns mne.fiff.evoked.Evoked evoked.save('mne_python-ave.fif')
And then in Matlab, we can read the data:
fiff_file = 'mne_python-ave.fif'; cfg = []; cfg.dataset = fiff_file; data1 = ft_preprocessing(cfg); avg1 = ft_timelockanalysis([], data1); ft_datatype(avg1) % returns 'timelock'
In addition, we can read multiple conditions too, if there are present in the evoked
fif file:
cfg = []; cfg.dataset = fiff_file; data1 = ft_preprocessing(cfg); % E.g. with 3 conditions -> mapped to 3 trials cfg = []; cfg.trials = 1; avg1 = ft_timelockanalysis(cfg, data1); cfg.trials = 2; avg2 = ft_timelockanalysis(cfg, data1); cfg.trials = 3; avg3 = ft_timelockanalysis(cfg, data1);