mne-bids structure - one subject is different

Hello,

I am a new user of mne-bids and am getting set up to convert raw .fif files to the mne-bids format. After that I will try out the mne-bids-pipeline for preprocessing and beyond.

I have 18 subjects, each with 6 task .fif files collected in 1 session. For just 1 of 18 subjects, 1 of 6 task files was recorded in two parts (data recording accidently stopped then restarted during acquisition). My question is how to accommodate these 2 files during the bids conversion and into the mne-bids-pipeline? At what stage should I concatenate the files?

My initial thought was to read in the two .fif files as separate runs during bids conversion and then concatenate. Then I would have 1 task file as for all other tasks and all other subjects to take forward to the mne-bids-pipeline. But I’m not sure this is appropriate and I’m also unclear how I would name the concatenated raw file.

Alternatively ought the two files remain separate during conversion, into the mne-bids-pipeline and through the preprocessing (i.e. for maxfiltering, filtering, ICA etc)?

Regarding the file naming, if the two files are identified by run number (run-01, run-02), do all subjects need to have run specified for that task(i.e. run-01 for the equivalent single task file)? Do I need to include run number (run-01) for the other tasks?

With many thanks for advice so I adopt best practices.

Lucy

Hello @lucy.macgregor, and welcome to the forum!

Strictly speaking, I’d think that these are then two acquisition runs, hence should be treated as two separate runs. But practically speaking, I think it would make sense to concatenate these two runs. Problem is that this introduces an “edge” in the data, but MNE-Python marks it as such via an annotation. When writing to BIDS, you must ensure that this annotation is preserved (it must end up in events.tsv), and ideally you document that the data was concatenated. If you use MNE-BIDS, the edge annotation should be written to events.tsv automatically, but please double-check this.

Just name it like a normal run.

This is possible too – the pipeline should handle varying numbers of runs for each participant.

For consistency, I’d add the run entity to the filenames for all participants, yes.

Also tagging @sappelhoff, creator of MNE-BIDS.

Best wishes,
Richard

Hello @richard and thanks so much for your helpful reply!

I’m going to try concatenation before writing to BIDS and will check details in the events.tsv as you suggest.

Best wishes,
Lucy

Hello again @richard, and following your lead of also tagging @sappelhoff.

I concatenated the two files but then when I tried to write to bids I got the following error:

ValueError: The raw data you want to write contains more time points than the raw data on disk. It is possible that you concatenated your data, which write_raw_bids() won’t accept. If you believe you have a valid use case that should be supported, please reach out to the developers at Issues · mne-tools/mne-bids · GitHub

Based on your experience, do you think I have a valid use case?! Thank you for your advice.

Hello @lucy.macgregor,

the MNE-BIDS error message isn’t very helpful and we should improve it.

I suggest you preload the data and write it while passing the parameters allow_preload=True, format='FIF' to write_raw_bids(). Here’s a minimal example that demonstrates this:

# %%
import mne
import mne_bids

sample_dir = mne.datasets.sample.data_path()
sample_fname = sample_dir / 'MEG' / 'sample' / 'sample_audvis_raw.fif'

raw = mne.io.read_raw_fif(sample_fname)
raw_concat = mne.concatenate_raws([raw.copy(), raw])

bp = mne_bids.BIDSPath(
    subject='sample',
    task='sample',
    suffix='meg',
    extension='.fif',
    datatype='meg',
    root='/tmp/bids-root'
)
mne_bids.write_raw_bids(
    raw_concat,
    bids_path=bp,
    overwrite=True,
    allow_preload=True,
    format='FIF'
)

Best wishes,
Richard

1 Like

Thank you @richard. This worked smoothly and the bids files have been written.

However, looking at the events.tsv file it seems that the edge annotation you described earlier has not been automatically written. Please can you advise how to deal with this?

Best, Lucy

1 Like

Thanks for the update!

@sappelhoff We may have a bug here, care to investigate?

Lucy, can you perhaps provide a minimal working example (MWE) to replicate your problem, using one of the datasets shipped with MNE-Python, preferably the one called sample?

I cannot reproduce:

# %%
import pandas as pd
import mne
import mne_bids

sample_dir = mne.datasets.sample.data_path()
sample_fname = sample_dir / 'MEG' / 'sample' / 'sample_audvis_raw.fif'

raw = mne.io.read_raw_fif(sample_fname)
raw_concat = mne.concatenate_raws([raw.copy(), raw])
print(raw_concat.annotations)

# <Annotations | 2 segments: BAD boundary (1), EDGE boundary (1)>

# %%
bp = mne_bids.BIDSPath(
    subject='sample',
    task='sample',
    suffix='meg',
    extension='.fif',
    datatype='meg',
    root='/tmp/bids-root'
)
mne_bids.write_raw_bids(
    raw_concat,
    bids_path=bp,
    overwrite=True,
    allow_preload=True,
    format='FIF'
)

# %%
events_tsv_path = (
    bp
    .copy()
    .update(suffix='events', extension='.tsv')
)
events_tsv = pd.read_csv(events_tsv_path, sep='\t')
print(events_tsv)

#         onset  duration     trial_type  value  sample
# 0  277.715346       0.0   BAD boundary      1  166800
# 1  277.715346       0.0  EDGE boundary      2  166800

Dear @richard, thanks for all your help so far.

I can get the annotations to the _events.tsv if I use your minimal code but have not managed to get the combination of actual events / trigger codes and annotations. I tried to include the events of interest in the following way:

events_id = {'auditory/left': 1, 'auditory/right': 2, 'visual/left': 3,
              'visual/right': 4, 'smiley': 5, 'buttonpress': 32}

events = mne.find_events(raw_concat, stim_channel = 'STI 014', min_duration = 0.008)
events = events[np.isin(events[:,2], list(event_id.values())), :]

bp = BIDSPath(
    subject='sample',
    task='sample',
    suffix='meg',
    extension = 'fif',
    datatype='meg',
    root = '/tmp/bids_root'
    )

write_raw_bids(
    raw_concat,
    bids_path = bp,
    overwrite = True,
    events_data = events,
    event_id = events_id,
    allow_preload=True,
    format= 'FIF'
)

events_tsv_path = (
    bp.copy()
    .update(suffix = 'events', extension = 'tsv')
)

events_tsv = pd.read_csv(events_tsv_path, sep = '\t')
print(events_tsv)

Thanks for your advice on how to proceed. Bw, Lucy

Hello again @richard. Unfortunately I still haven’t been able to get the annotations (from concatenation) to show alongside the events in the _tsv file so I wonder if you could please help?

Perhaps I’m missing something simple or maybe I’m reading the events (triggers) incorrectly (see minimal example using sample data). As I said earlier, the annotations show if I’m not also detailing the events defined by triggers. Thanks for any advice or pointers.

import os.path as op
import shutil
import numpy as np
import pandas as pd

import mne
from mne_bids import (write_raw_bids, read_raw_bids, write_meg_calibration, 
                      write_meg_crosstalk, BIDSPath, print_dir_tree, make_report, inspect_dataset, mark_channels)
from mne_bids.stats import count_events

sample_dir=mne.datasets.sample.data_path()
sample_fname = sample_dir / 'MEG' / 'sample' /'sample_audvis_raw.fif'

raw = mne.io.read_raw_fif(sample_fname)
raw_concat=mne.concatenate_raws([raw.copy(), raw])
print(raw_concat.annotations)


events_id = {'auditory/left': 1, 'auditory/right': 2, 'visual/left': 3,
              'visual/right': 4, 'smiley': 5, 'buttonpress': 32}

events = mne.find_events(raw_concat, stim_channel = 'STI 014', min_duration = 0.008)
events = events[np.isin(events[:,2], list(event_id.values())), :]

bp = BIDSPath(
    subject='sample',
    task='sample',
    suffix='meg',
    extension = 'fif',
    datatype='meg',
    root = '/tmp/bids_root'
    )

write_raw_bids(
    raw_concat,
    bids_path = bp,
    overwrite = True,
    events_data = events,
    event_id = events_id,
    allow_preload=True,
    format= 'FIF'
)

events_tsv_path = (
    bp.copy()
    .update(suffix = 'events', extension = 'tsv')
)

events_tsv = pd.read_csv(events_tsv_path, sep = '\t')
print(events_tsv)

Best wishes, Lucy

@lucy.macgregor Thanks for pinging me again, I had forgotten about this topic – was busy with too many other things!

I can now reproduce your problem, and I believe we have a bug in MNE-BIDS.

@sappelhoff:

# %%
import pandas as pd
import mne
import mne_bids

sample_dir = mne.datasets.sample.data_path()
sample_fname = sample_dir / 'MEG' / 'sample' / 'sample_audvis_raw.fif'

raw = mne.io.read_raw_fif(sample_fname)
raw_concat = mne.concatenate_raws([raw.copy(), raw])
events = mne.find_events(raw_concat)
event_id = {
    'Auditory/Left': 1,
    'Auditory/Right': 2,
    'Visual/Left': 3,
    'Visual/Right': 4,
    'Smiley': 5,
    'Button': 32
}

# %%
bp = mne_bids.BIDSPath(
    subject='sample',
    task='sample',
    suffix='meg',
    extension='.fif',
    datatype='meg',
    root='/tmp/bids-root'
)
mne_bids.write_raw_bids(
    raw_concat,
    bids_path=bp,
    events=events,
    event_id=event_id,
    overwrite=True,
    allow_preload=True,
    format='FIF'
)

# %%
events_tsv_path = (
    bp
    .copy()
    .update(suffix='events', extension='.tsv')
)
events_tsv = pd.read_csv(events_tsv_path, sep='\t')
print(events_tsv['trial_type'].unique())

produces

array(['Auditory/Right', 'Visual/Left', 'Auditory/Left', 'Visual/Right',
       'Smiley', 'Button'], dtype=object)

But this means that the edge annotations are gone. Apparently MNE-BIDS doesn’t correctly merge events and raw.annotations when writing.

I found the bug and I’m working on a fix.

1 Like

It’s complicated. We’re tracking the issue here:

Thanks for your patience!

2 Likes