mne-python
mne-python copied to clipboard
Montage in MRI space converted to head when saving to epoch.fif
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
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.
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
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: @.***>
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.
Ahh, this is ECOG data, I see.
Reopening as this issue will exist until make a fix in MNE-BIDS