Note
Click here to download the full example code
02. Convert Coordinate Frames of Electrodes¶
When working with intracranial electrophysiological data in the
iEEG-BIDS format, we usually have iEEG coordinate data either in
voxel, or real world coordinates space (xyz coordinates).
Then within xyz coordinates, it can either be RAS, or
tkRAS if one uses FreeSurfer.
In this tutorial, we show how to quickly use the Sensors
data class and quickly go back and forth between coordinate frames
using convert_elec_coords.
We assume that you have already localized the electrodes and coregistered them over to the T1w image FreeSurfer space.
# Authors: Adam Li <adam2392@gmail.com>
#
# License: BSD (3-clause)
Imports¶
We are importing everything we need for this example:
from pathlib import Path
from mne_bids import BIDSPath
from seek_localize import read_dig_bids, convert_coord_units, convert_coord_space
We will be using the testing dataset, which
is already stored in BIDS format and stored with the
seek-localize repository.
bids_root = (Path.cwd() / Path("../data/")).absolute()
subjects_dir = bids_root / "derivatives" / "freesurfer"
Now it’s time to get ready for labeling some of the data! First, we need to
create a mne_bids.BIDSPath(), which will point to the corresponding
*electrodes.tsv file.
subject = "la02"
session = "presurgery"
acquisition = "seeg"
space = "fs"
suffix = "electrodes"
extension = ".tsv"
datatype = "ieeg"
electrodes_fpath = BIDSPath(
root=bids_root,
datatype=datatype,
subject=subject,
session=session,
acquisition=acquisition,
space=space,
suffix=suffix,
extension=extension,
)
# the full file path to the electrodes.tsv file
print(electrodes_fpath.fpath)
Out:
/home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_electrodes.tsv
The necessary iEEG files are the
sub-la02_ses-presurgery_acq-seeg_space-fs_electrodes.tsv,
sub-la02_ses-presurgery_acq-seeg_space-fs_coordsystem.json files. Note
these are co-occurring files in iEEG-BIDS (one present requires the other to
be present).
Out:
/home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_coordsystem.json
Let’s load in the electrode coordinates as an instance of the
seek_localize.Sensors class. Rather then instantiating the class
directly, we use seek_localize.read_dig_bids to read in the
correct data. This will perform extra work, such as figuring
out the full path to the IntendedFor volumetric image. The
image corresponds to the coordinate space to interpret the
electrode coordinates in (e.g. a T1w image in FreeSurfer space).
sensors = read_dig_bids(electrodes_fpath, root=bids_root)
print(sensors)
Out:
SETTING COORDINATE SYSTEM AS MRI by default if coordinatesystem is "other".
<Sensors | 9 non-empty values
ch_names: L'1, L'2, L'3, L'4, L'5, L'6, L'7, L'8, L'11, L'12, L'13, L'14, ...
coord_system: mri
coord_unit: mm
coordsystem_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_coordsystem.json
elecs_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_electrodes.tsv
intended_for: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/anat/sub-la02_ses-presurgery_space-fs_T1w.nii
x: 88 items (list)
y: 88 items (list)
z: 88 items (list)
>
The data already saved was originally written in 'mm', so we can
convert to voxel space denoted by the mri coordinate frame.
This is in-line with how MNE does things
sensors_vox = convert_coord_units(sensors, to_unit="voxel")
print(sensors_vox)
Out:
Converting coordinates from mm to voxel using /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/anat/sub-la02_ses-presurgery_space-fs_T1w.nii.
<Sensors | 9 non-empty values
ch_names: L'1, L'2, L'3, L'4, L'5, L'6, L'7, L'8, L'11, L'12, L'13, L'14, ...
coord_system: mri
coord_unit: voxel
coordsystem_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_coordsystem.json
elecs_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_electrodes.tsv
intended_for: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/anat/sub-la02_ses-presurgery_space-fs_T1w.nii
x: 88 items (ndarray)
y: 88 items (ndarray)
z: 88 items (ndarray)
>
We could convert it to mm.
sensors_mm = convert_coord_units(sensors_vox, to_unit="mm")
print(sensors_mm)
Out:
../seek_localize/coordsystem.py:220: RuntimeWarning: Rounding when to_unit is mm and not voxel is not recommended.
f"Rounding when to_unit is {to_unit} " f"and not voxel is not recommended."
Converting coordinates from voxel to mm using /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/anat/sub-la02_ses-presurgery_space-fs_T1w.nii.
<Sensors | 9 non-empty values
ch_names: L'1, L'2, L'3, L'4, L'5, L'6, L'7, L'8, L'11, L'12, L'13, L'14, ...
coord_system: mri
coord_unit: mm
coordsystem_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_coordsystem.json
elecs_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_electrodes.tsv
intended_for: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/anat/sub-la02_ses-presurgery_space-fs_T1w.nii
x: 88 items (ndarray)
y: 88 items (ndarray)
z: 88 items (ndarray)
>
The data was originally saved according to the mri space, intended
for the T1.mgz image in FreeSurfer. One can also use seek_localize to
transform to standard coordinate spaces, such as tkras and mni.
# We could convert it to ``tkras``.
sensors_tkras = convert_coord_space(sensors_vox, to_frame="tkras")
print(sensors_tkras)
# We could convert it to ``mni``.
sensors_mni = convert_coord_space(
sensors_vox, to_frame="mni", subjects_dir=subjects_dir
)
print(sensors_mni)
# We could convert it to back to ``mri``.
sensors_mri = convert_coord_space(sensors_vox, to_frame="mri")
print(sensors_mri)
Out:
../seek_localize/coordsystem.py:285: RuntimeWarning: Unable to programmatically get vox2ras TKR from /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/anat/sub-la02_ses-presurgery_space-fs_T1w.nii, so setting manually.
f"Unable to programmatically get vox2ras TKR "
Using Vox2TKRAS affine: [[-1.0, 0.0, 0.0, 128.0], [0.0, 0.0, 1.0, -128.0], [0.0, -1.0, 0.0, 128.0], [0.0, 0.0, 0.0, 1.0]].
<Sensors | 9 non-empty values
ch_names: L'1, L'2, L'3, L'4, L'5, L'6, L'7, L'8, L'11, L'12, L'13, L'14, ...
coord_system: tkras
coord_unit: mm
coordsystem_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_coordsystem.json
elecs_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_electrodes.tsv
intended_for: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/anat/sub-la02_ses-presurgery_space-fs_T1w.nii
x: 88 items (ndarray)
y: 88 items (ndarray)
z: 88 items (ndarray)
>
<Sensors | 9 non-empty values
ch_names: L'1, L'2, L'3, L'4, L'5, L'6, L'7, L'8, L'11, L'12, L'13, L'14, ...
coord_system: mni
coord_unit: voxel
coordsystem_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_coordsystem.json
elecs_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_electrodes.tsv
intended_for: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/anat/sub-la02_ses-presurgery_space-fs_T1w.nii
x: 88 items (ndarray)
y: 88 items (ndarray)
z: 88 items (ndarray)
>
<Sensors | 9 non-empty values
ch_names: L'1, L'2, L'3, L'4, L'5, L'6, L'7, L'8, L'11, L'12, L'13, L'14, ...
coord_system: mri
coord_unit: voxel
coordsystem_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_coordsystem.json
elecs_fname: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/ieeg/sub-la02_ses-presurgery_acq-seeg_space-fs_electrodes.tsv
intended_for: /home/docs/checkouts/readthedocs.org/user_builds/seek-localize/checkouts/stable/examples/../data/sub-la02/ses-presurgery/anat/sub-la02_ses-presurgery_space-fs_T1w.nii
x: 88 items (ndarray)
y: 88 items (ndarray)
z: 88 items (ndarray)
>
Total running time of the script: ( 0 minutes 0.255 seconds)