Hi,
I am trying to visualize sEEG electrodes on the ‘fsaverage’ brain surface (following the “working with SEEG data” tutorial.).
I am stuck figuring out what coordinate frame transforms I need to apply to the montage – if at all – given that I have electrode locations already in the MNI space (which I believe is different from the tutorial).
Specifically, for each participant, I have a .csv
file which contains the MNI coordinates (x, y, z) for each electrode on the sEEG shafts (Neuralynx seeg data). I do not have access to the individual subject’s recon-all
data (electrode localization was done in a different lab). Example coordinate data looks like this (I am assuming these values must be millimeters):
print(coords) # just a dataframe loaded via pd.read_csv
>>>
Channels MNI_1 MNI_2 MNI_3
0 LAMu -22.425952 -4.686374 -16.528827
1 LAM1 -25.003134 -4.285802 -19.544462
2 LAM2 -28.077597 -3.557858 -21.753622
3 LAM3 -33.196102 -1.944738 -21.954092
4 LAM4 -38.982658 -1.034873 -24.233653
.. ... ... ... ...
103 RPINS4 32.841654 -3.428255 18.764148
104 RPINS5 31.769347 -1.041556 26.172012
105 RPINS6 31.037502 0.839024 33.411429
106 RPINS7 29.981158 3.350836 42.209800
107 RPINS8 29.024138 5.230155 49.399291
[108 rows x 4 columns]
Conceptually, given that my coordinates are already in the MNI space, I thought that the part of the tutorial that transforms the montage from the “head” → “mri” → “mni” coordinate systems would not be needed in my case.
So, I thought I would be able to create a montage from these values in the csv file (montage = mne.channels.create_dig_montage(coords_dict, "mni_tal"); epochs.set_montage(montage, on_missing='warn')
) and plot on ‘fsaverage’ (full code below). But I am clearly missing something as the locations are misaligned and possibly also not correctly mapped left/right:
Plotting the montage itself (montage.plot()
, looks more meaningful (at least the 3 shafts that have electrodes whose labels start with L* are on indeed on the left side):
The above suggest my electrode coordinate system is off. Any pointers on how to start troubleshooting this would be much appreciated! I don’t think I can share a MWE due to the nature of the data, but happy to provide more details if anything is unclear.
Full code snippet:
import mne
from mne.io import read_raw_fif
from mne.datasets import fetch_fsaverage
import pandas as pd
# input data
subjects_dir = "*/mne_data/MNE-fsaverage-data"
anat_csv = "/path/to/csv/file/with/mni/coordinates/coords_mni.csv"
raw = read_raw_fif("/path/to/seeg/sub-009_preproc_ieeg.fif") # preprocessed seeg data
# epoch at start of audio playback
epochs = mne.Epochs(raw, event_id={"wav_playback"}, detrend=1, baseline=None)
# load the coordinate values
coords = pd.read_csv(anat_csv, sep="\t")
# only retain labels and x,y,z values
coords = coords[["Channels", "MNI_1", "MNI_2", "MNI_3"]]
# convert channel coordinate values to meters
coords[["MNI_1", "MNI_2", "MNI_3"]] /= 1000
# drop micro channels (labels start with `u`), not interested in these
coords = coords.loc[~coords["Channels"].str.contains("u")]
# create a dict for mne.channels.make_dig_montage()
ch_pos = dict(
zip(
coords["Channels"],
coords[["MNI_1", "MNI_2", "MNI_3"]].to_numpy()
)
)
# create montage
montage = mne.channels.make_dig_montage(ch_pos=ch_pos, coord_frame="mni_tal")
epochs.set_montage(montage, on_missing="warn")
brain = mne.viz.Brain(
"fsaverage",
subjects_dir=subjects_dir,
background="white",
units="m",
)
brain.add_sensors(epochs.info, 'fsaverage')
mne.sys_info()
Platform Linux-5.10.102.1-microsoft-standard-WSL2-x86_64-with-glibc2.31
Python 3.11.8 | packaged by conda-forge | (main, Feb 16 2024, 20:53:32) [GCC 12.3.0]
Executable /home/kriarm/miniconda3/envs/core/bin/python
CPU x86_64 (20 cores)
Memory 31.2 GB
Core
├☒ mne 1.7.0.dev158+g925f52282 (outdated, release 1.7.0 is available!)
├☑ numpy 1.26.4 (MKL 2022.1-Product with 10 threads)
├☑ scipy 1.12.0
└☑ matplotlib 3.8.3 (backend=module://matplotlib_inline.backend_inline)
Numerical (optional)
├☑ sklearn 1.4.1.post1
├☑ numba 0.59.0
├☑ nibabel 5.2.0
├☑ nilearn 0.10.2
├☑ dipy 1.9.0
├☑ openmeeg 2.5.7
├☑ pandas 2.2.1
├☑ h5io 0.1.9
├☑ h5py 3.10.0
└☐ unavailable cupy
Visualization (optional)
├☑ pyvista 0.42.3 (OpenGL 4.5 (Core Profile) Mesa 20.2.6 via llvmpipe (LLVM 11.0.0, 256 bits))
├☑ pyvistaqt 0.11.0
├☑ vtk 9.2.6
├☑ qtpy 2.4.1 (PyQt5=5.15.8)
├☑ ipympl 0.9.3
├☑ pyqtgraph 0.13.3
├☑ mne-qt-browser 0.6.1
├☑ ipywidgets 8.1.1
├☑ trame_client 2.12.6
├☑ trame_server 2.12.1
├☑ trame_vtk 2.6.1
└☑ trame_vuetify 2.3.1
Ecosystem (optional)
├☑ mne-bids 0.14
├☑ neo 0.13.0
├☑ eeglabio 0.0.2-4
├☑ edfio 0.4.0
├☑ mffpy 0.8.0
├☑ pybv 0.7.5
└☐ unavailable mne-nirs, mne-features, mne-connectivity, mne-icalabel, mne-bids-pipeline
To update to the latest supported release version to get bugfixes and improvements, visit https://mne.tools/stable/install/updating.html