mne-python icon indicating copy to clipboard operation
mne-python copied to clipboard

Montage in MRI space converted to head when saving to epoch.fif

Open AlexLepauvre opened this issue 3 years ago • 6 comments

Describe the bug

Montage in MRI space gets transformed to head space when saving to an epochs .fif file. The issue seems to be due to the saving and not the loading, but not 100% clear. See here

Steps to reproduce

import mne
import numpy as np
from numpy.random import normal
import tempfile
import os


# Create random montage:
montage = mne.channels.make_dig_montage(ch_pos={"ch_1": np.array([1, 2, 3]), "ch_2": np.array([4, 5, 6]),
                                                "ch_3": np.array([7, 8, 9])}, coord_frame="mri")

# Create random data:
info = mne.create_info(ch_names=['ch_1', 'ch_2', 'ch_3'],
                       ch_types=['ecog'] * 3,
                       sfreq=100)
data = np.array([[normal(loc=0, scale=2, size=100), normal(loc=0, scale=2, size=100),
                  normal(loc=0, scale=2, size=100)],
                 [normal(loc=0, scale=2, size=100), normal(loc=0, scale=2, size=100),
                  normal(loc=0, scale=2, size=100)]])
epochs = mne.EpochsArray(data, info, tmin=-0.2, verbose="ERROR")
epochs.set_montage(montage, verbose="ERROR")

# Printing the epochs montage info:
print("Coordinate frames before saving:")
print(epochs.get_montage().dig[0]["coord_frame"])

# Creating a temporary directory
temp_dir = tempfile.mkdtemp()
# Generate a file name
fname = temp_dir + os.sep + "-epo.fif"
epochs.save(fname)

loaded_epochs = mne.read_epochs(fname, verbose="ERROR")
print("Coordinate frames after saving:")
print(loaded_epochs.get_montage().dig[0]["coord_frame"])

Expected results

Coordinate frames before saving: 5 (FIFFV_COORD_MRI) 5 (FIFFV_COORD_MRI)

Actual results

Coordinate frames before saving: 5 (FIFFV_COORD_MRI) 4 (FIFFV_COORD_HEAD)

Additional information

Platform: Windows-10-10.0.19044-SP0 Python: 3.9.7 | packaged by conda-forge | (default, Sep 29 2021, 19:15:42) [MSC v.1916 64 bit (AMD64)] Executable: C:\Users\alexander.lepauvre\Anaconda3\envs\mne_24\python.exe CPU: Intel64 Family 6 Model 142 Stepping 10, GenuineIntel: 8 cores Memory: 15.9 GB mne: 0.24.0 numpy: 1.21.4 {blas=NO_ATLAS_INFO, lapack=lapack} scipy: 1.7.2 matplotlib: 3.4.3 {backend=Qt5Agg} sklearn: 1.0.1 numba: 0.53.1 nibabel: 3.2.1 nilearn: 0.8.1 dipy: 1.4.1 cupy: Not found pandas: 1.3.4 mayavi: 4.7.2 pyvista: 0.32.1 {OpenGL 4.5.0 - Build 26.20.100.6860 via Intel(R) UHD Graphics 620} pyvistaqt: 0.5.0 ipyvtklink: Not found vtk: 9.0.3 PyQt5: 5.12.3 ipympl: Not found mne_qt_browser: Not found

AlexLepauvre avatar Jul 22 '22 09:07 AlexLepauvre

ok I looked a bit into it. The problem happens on write (not on read). Basically when we write dig points on epochs.save we just ignore the coord frame. We call write_dig_points without a coord_frame parameter. So on read it defaults to head...

I think it's something we can tackle during our sprint late August unless @larsoner is eager to fix it before.

agramfort avatar Jul 22 '22 17:07 agramfort

Thanks @agramfort. In the mean time, is there any way I change the coordinate frame of the epochs object manually to override this issue? I am thinking something like:

for ch in montage.dig:
   montage.dig[ch] = "5 (FIFFV_COORD_MRI)"

Kind regards,

Alex

AlexLepauvre avatar Jul 25 '22 07:07 AlexLepauvre

you can hack it like this:

from mne.io.constants import FIFF for d in loaded_epochs.info["dig"]: d['coord_frame'] = FIFF.FIFFV_COORD_MRI

Message ID: @.***>

agramfort avatar Jul 27 '22 13:07 agramfort

Converting to head space is actually intended behavior:

MNE-Python prefers to have EEG channel locations in head space, always. So .apply_montage converts the montage to head space (if you get rid of the verbose='ERROR' you can see the warning message saying there are no fiducials so an identity transform is assumed). We probably want to keep this. If we allow electrodes to be in all kinds of coordinate spaces, we have to verify the coordinate space every time we use channel locations.

What is the reason for wanting to store digitized channel locations in MRI space? It may be simpler not to try and fight MNE-Python on this.

wmvanvliet avatar Aug 23 '22 16:08 wmvanvliet

Ahh, this is ECOG data, I see.

wmvanvliet avatar Aug 26 '22 11:08 wmvanvliet

Reopening as this issue will exist until make a fix in MNE-BIDS

larsoner avatar Aug 29 '22 11:08 larsoner