├── ieeg_quickstart └── python │ ├── __init__.py │ ├── .ipynb_checkpoints │ ├── preprocess_iemu-checkpoint.ipynb │ └── visualize_coverage-checkpoint.ipynb │ ├── utils.py │ └── visualize_coverage.ipynb ├── requirements ├── .gitignore └── README.md /ieeg_quickstart/python/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements: -------------------------------------------------------------------------------- 1 | mne 2 | mne-bids 3 | python>3.6 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | __pycache__ 3 | preprocess_iemu.m 4 | visualize_coverage.m 5 | -------------------------------------------------------------------------------- /ieeg_quickstart/python/.ipynb_checkpoints/preprocess_iemu-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [], 3 | "metadata": {}, 4 | "nbformat": 4, 5 | "nbformat_minor": 5 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Quickstart code for the iEEG-fMRI dataset 2 | 3 | [Open multimodal iEEG-fMRI dataset from naturalistic stimulation with a short audiovisual film](https://www.biorxiv.org/content/10.1101/2021.06.09.447733) 4 | 5 | Contains code for 6 | * electrode visualization on the brain 7 | * basics of data loading and preprocessing with [MNE](https://mne.tools/dev/index.html) 8 | 9 | TODO: 10 | * add matlab version of the code 11 | -------------------------------------------------------------------------------- /ieeg_quickstart/python/utils.py: -------------------------------------------------------------------------------- 1 | import re 2 | from fractions import Fraction 3 | from scipy.signal import resample_poly 4 | import numpy as np 5 | 6 | def sort_nicely(l): 7 | """ Sort the given list in the way that humans expect. 8 | """ 9 | convert = lambda text: int(text) if text.isdigit() else text 10 | alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 11 | l.sort( key=alphanum_key ) 12 | 13 | def resample(x, sr1, sr2, axis=0): 14 | '''sr1: target, sr2: source''' 15 | a, b = Fraction(sr1, sr2)._numerator, Fraction(sr1, sr2)._denominator 16 | return resample_poly(x, a, b, axis).astype(np.float32) 17 | 18 | def smooth_signal(y, n): 19 | box = np.ones(n)/n 20 | ys = np.convolve(y, box, mode='same') 21 | return ys 22 | 23 | def zscore(x): 24 | return (x - np.mean(x, 0, keepdims=True)) / np.std(x, 0, keepdims=True) -------------------------------------------------------------------------------- /ieeg_quickstart/python/visualize_coverage.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "parental-suspension", 6 | "metadata": {}, 7 | "source": [ 8 | "### Visualization of the electrode coverage using MNE tools" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "id": "laden-birmingham", 15 | "metadata": {}, 16 | "outputs": [ 17 | { 18 | "name": "stdout", 19 | "output_type": "stream", 20 | "text": [ 21 | "Using notebook 3d backend.\n", 22 | "\n" 23 | ] 24 | } 25 | ], 26 | "source": [ 27 | "import numpy as np\n", 28 | "import mne\n", 29 | "import pandas as pd\n", 30 | "import os\n", 31 | "import mne_bids\n", 32 | "import nibabel\n", 33 | "\n", 34 | "\n", 35 | "mne.viz.set_3d_backend('notebook')\n", 36 | "%matplotlib qt" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "id": "designing-breeding", 42 | "metadata": {}, 43 | "source": [ 44 | "### Specify info about the subject, recording session, datatype, acquisition, task and freesurfer reconstruction directory\n", 45 | "\n", 46 | "Most of this info can be derived from the BIDs filenames and metadata. Check https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/04-intracranial-electroencephalography.html\n", 47 | "\n", 48 | "To visualize electrode coverage on the native brain you will need to obtain freesurfer reconstruction of the native anatomy. For this, you will need to install Freesurfer (https://surfer.nmr.mgh.harvard.edu/) and run the following in the terminal, set up variables SUBJECTS_DIR and FS_HOME_DIR and run cortical reconstruction in the terminal: \n", 49 | "\n", 50 | "``` recon-all -subject sub-01 -i sub-01/ses-mri3t/anat/sub-01_ses-mri3t_run-1_T1w.nii -cw256 -all ```" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 2, 56 | "id": "stupid-scholar", 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "bids_dir='/Fridge/users/julia/project_chill_dataset_paper/data/BIDS2'\n", 61 | "subjects = mne_bids.get_entity_vals(bids_dir, 'subject')\n", 62 | "\n", 63 | "subject = '01'\n", 64 | "session = 'iemu'\n", 65 | "datatype = 'ieeg'\n", 66 | "task = 'film'\n", 67 | "acquisition = 'clinical'\n", 68 | "fs_dir = '/Fridge/users/julia/project_chill_dataset_paper/data/freesurfer2/sub-01'" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "id": "boring-contrast", 74 | "metadata": {}, 75 | "source": [ 76 | "### Load electrodes info" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 3, 82 | "id": "swiss-count", 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "electrodes_path = mne_bids.BIDSPath(subject=subject,\n", 87 | " session=session,\n", 88 | " suffix='electrodes',\n", 89 | " extension='tsv',\n", 90 | " datatype=datatype,\n", 91 | " acquisition=acquisition,\n", 92 | " root=bids_dir)\n", 93 | "electrodes = pd.read_csv(str(electrodes_path), sep='\\t', header=0, index_col=None)\n", 94 | "coords = electrodes[['x', 'y', 'z']].values" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "id": "unique-audio", 100 | "metadata": {}, 101 | "source": [ 102 | "### Load channels info" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 4, 108 | "id": "molecular-wilson", 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [ 112 | "channels_path = mne_bids.BIDSPath(subject=subject,\n", 113 | " session=session,\n", 114 | " suffix='channels',\n", 115 | " extension='tsv',\n", 116 | " datatype=datatype,\n", 117 | " task=task,\n", 118 | " acquisition=acquisition,\n", 119 | " root=bids_dir)\n", 120 | "channels = pd.read_csv(str(channels_path.match()[0]), sep='\\t', header=0, index_col=None)" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "id": "stock-transmission", 126 | "metadata": {}, 127 | "source": [ 128 | "### Load iEEG data info, set channel types and drop all irrelevant channels (not iEEG)" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 5, 134 | "id": "complicated-spread", 135 | "metadata": {}, 136 | "outputs": [ 137 | { 138 | "name": "stdout", 139 | "output_type": "stream", 140 | "text": [ 141 | "Extracting parameters from /Fridge/users/julia/project_chill_dataset_paper/data/BIDS2/sub-01/ses-iemu/ieeg/sub-01_ses-iemu_task-film_acq-clinical_run-1_ieeg.vhdr...\n", 142 | "Setting channel info structure...\n" 143 | ] 144 | }, 145 | { 146 | "data": { 147 | "text/html": [ 148 | "\n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | "
Measurement dateJanuary 01, 1900 00:00:00 GMT
ExperimenterUnknown
ParticipantUnknown
Digitized points0 points
Good channels103 sEEG
Bad channelsNone
EOG channelsNot available
ECG channelsNot available
Sampling frequency2048.00 Hz
Highpass0.00 Hz
Lowpass1024.00 Hz
Filenamessub-01_ses-iemu_task-film_acq-clinical_run-1_ieeg.eeg
Duration00:07:00 (HH:MM:SS)
" 217 | ], 218 | "text/plain": [ 219 | "" 220 | ] 221 | }, 222 | "execution_count": 5, 223 | "metadata": {}, 224 | "output_type": "execute_result" 225 | } 226 | ], 227 | "source": [ 228 | "data_path = mne_bids.BIDSPath(subject=subject,\n", 229 | " session=session,\n", 230 | " suffix='ieeg',\n", 231 | " extension='vhdr',\n", 232 | " datatype=datatype,\n", 233 | " task=task,\n", 234 | " acquisition=acquisition,\n", 235 | " root=bids_dir)\n", 236 | "raw = mne.io.read_raw_brainvision(str(data_path.match()[0]), scale=1.0, preload=False, verbose=True)\n", 237 | "raw.set_channel_types({ch_name: str(x).lower()\n", 238 | " if str(x).lower() in ['ecog', 'seeg'] else 'misc'\n", 239 | " for ch_name, x in zip(raw.ch_names, channels['type'].values)})\n", 240 | "raw.drop_channels([raw.ch_names[i] for i, j in enumerate(raw.get_channel_types()) if j == 'misc'])" 241 | ] 242 | }, 243 | { 244 | "cell_type": "markdown", 245 | "id": "tribal-canon", 246 | "metadata": {}, 247 | "source": [ 248 | "### Transform electrode coordinate to the freesurfer RAS space to visualize them on the surface" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": 6, 254 | "id": "tamil-serial", 255 | "metadata": {}, 256 | "outputs": [ 257 | { 258 | "name": "stderr", 259 | "output_type": "stream", 260 | "text": [ 261 | "/tmp/ipykernel_3730404/702744162.py:7: RuntimeWarning: Fiducial point nasion not found, assuming identity unknown to head transformation\n", 262 | " raw.set_montage(montage)\n" 263 | ] 264 | }, 265 | { 266 | "data": { 267 | "text/html": [ 268 | "\n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | "
Measurement dateJanuary 01, 1900 00:00:00 GMT
ExperimenterUnknown
ParticipantUnknown
Digitized points0 points
Good channels103 sEEG
Bad channelsNone
EOG channelsNot available
ECG channelsNot available
Sampling frequency2048.00 Hz
Highpass0.00 Hz
Lowpass1024.00 Hz
Filenamessub-01_ses-iemu_task-film_acq-clinical_run-1_ieeg.eeg
Duration00:07:00 (HH:MM:SS)
" 337 | ], 338 | "text/plain": [ 339 | "" 340 | ] 341 | }, 342 | "execution_count": 6, 343 | "metadata": {}, 344 | "output_type": "execute_result" 345 | } 346 | ], 347 | "source": [ 348 | "x = nibabel.load(os.path.join(fs_dir, 'mri', 'orig.mgz'))\n", 349 | "vox_coords = np.round(mne.transforms.apply_trans(np.linalg.inv(x.affine), coords)).astype(int)\n", 350 | "ras_coords = mne.transforms.apply_trans(x.header.get_vox2ras_tkr(), vox_coords)\n", 351 | "ras_coords = ras_coords / 1000\n", 352 | "\n", 353 | "montage = mne.channels.make_dig_montage(ch_pos=dict(zip(raw.ch_names, ras_coords)), coord_frame='mri')\n", 354 | "raw.set_montage(montage)" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "id": "worst-collar", 360 | "metadata": {}, 361 | "source": [ 362 | "### Visualize electrodes\n", 363 | "\n", 364 | "*By default, if SEEG channels are present, MNE will make the visualization transparent" 365 | ] 366 | }, 367 | { 368 | "cell_type": "code", 369 | "execution_count": 8, 370 | "id": "eastern-geology", 371 | "metadata": {}, 372 | "outputs": [ 373 | { 374 | "name": "stdout", 375 | "output_type": "stream", 376 | "text": [ 377 | "Channel types::\tseeg: 103\n" 378 | ] 379 | }, 380 | { 381 | "data": { 382 | "application/vnd.jupyter.widget-view+json": { 383 | "model_id": "ac9d1c1403dc4d8abcf2a00f224cff31", 384 | "version_major": 2, 385 | "version_minor": 0 386 | }, 387 | "text/plain": [ 388 | "HBox(children=(Text(value='', layout=Layout(margin='2px 0px 2px 0px', min_width='0px'), placeholder='Type a fi…" 389 | ] 390 | }, 391 | "metadata": {}, 392 | "output_type": "display_data" 393 | }, 394 | { 395 | "data": { 396 | "application/vnd.jupyter.widget-view+json": { 397 | "model_id": "fd38814bef7347af8ac53b37cb31baa4", 398 | "version_major": 2, 399 | "version_minor": 0 400 | }, 401 | "text/plain": [ 402 | "HBox(children=(ViewInteractiveWidget(height=800, layout=Layout(height='auto'), width=800),))" 403 | ] 404 | }, 405 | "metadata": {}, 406 | "output_type": "display_data" 407 | } 408 | ], 409 | "source": [ 410 | "from packaging import version\n", 411 | "\n", 412 | "if version.parse(mne.__version__) <= version.parse('0.22.0'):\n", 413 | " fig = mne.viz.plot_alignment(raw.info,\n", 414 | " subject='sub-' + subject,\n", 415 | " subjects_dir=os.path.dirname(fs_dir),\n", 416 | " surfaces=['pial'],\n", 417 | " coord_frame='mri')\n", 418 | "else:\n", 419 | " # trans argument became mandatory\n", 420 | " identity_trans = mne.transforms.Transform('head', 'mri')\n", 421 | " fig = mne.viz.plot_alignment(raw.info, trans=identity_trans,\n", 422 | " subject='sub-' + subject,\n", 423 | " subjects_dir=os.path.dirname(fs_dir),\n", 424 | " surfaces=['pial'],\n", 425 | " coord_frame='mri')\n", 426 | "mne.viz.set_3d_view(fig, 180, 70, distance=.5)" 427 | ] 428 | } 429 | ], 430 | "metadata": { 431 | "kernelspec": { 432 | "display_name": "mne_pip", 433 | "language": "python", 434 | "name": "mne_pip" 435 | }, 436 | "language_info": { 437 | "codemirror_mode": { 438 | "name": "ipython", 439 | "version": 3 440 | }, 441 | "file_extension": ".py", 442 | "mimetype": "text/x-python", 443 | "name": "python", 444 | "nbconvert_exporter": "python", 445 | "pygments_lexer": "ipython3", 446 | "version": "3.10.4" 447 | } 448 | }, 449 | "nbformat": 4, 450 | "nbformat_minor": 5 451 | } 452 | -------------------------------------------------------------------------------- /ieeg_quickstart/python/.ipynb_checkpoints/visualize_coverage-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "parental-suspension", 6 | "metadata": {}, 7 | "source": [ 8 | "### Visualization of the electrode coverage using MNE tools" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "id": "laden-birmingham", 15 | "metadata": {}, 16 | "outputs": [ 17 | { 18 | "name": "stdout", 19 | "output_type": "stream", 20 | "text": [ 21 | "Using notebook 3d backend.\n", 22 | "\n" 23 | ] 24 | } 25 | ], 26 | "source": [ 27 | "import numpy as np\n", 28 | "import mne\n", 29 | "import pandas as pd\n", 30 | "import os\n", 31 | "import mne_bids\n", 32 | "import nibabel\n", 33 | "\n", 34 | "\n", 35 | "mne.viz.set_3d_backend('notebook')\n", 36 | "%matplotlib qt" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "id": "designing-breeding", 42 | "metadata": {}, 43 | "source": [ 44 | "### Specify info about the subject, recording session, datatype, acquisition, task and freesurfer reconstruction directory\n", 45 | "\n", 46 | "Most of this info can be derived from the BIDs filenames and metadata. Check https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/04-intracranial-electroencephalography.html\n", 47 | "\n", 48 | "To visualize electrode coverage on the native brain you will need to obtain freesurfer reconstruction of the native anatomy. For this, you will need to install Freesurfer (https://surfer.nmr.mgh.harvard.edu/) and run the following in the terminal, set up variables SUBJECTS_DIR and FS_HOME_DIR and run cortical reconstruction in the terminal: \n", 49 | "\n", 50 | "``` recon-all -subject sub-01 -i sub-01/ses-mri3t/anat/sub-01_ses-mri3t_run-1_T1w.nii -cw256 -all ```" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 2, 56 | "id": "stupid-scholar", 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "bids_dir='/Fridge/users/julia/project_chill_dataset_paper/data/BIDS2'\n", 61 | "subjects = mne_bids.get_entity_vals(bids_dir, 'subject')\n", 62 | "\n", 63 | "subject = '01'\n", 64 | "session = 'iemu'\n", 65 | "datatype = 'ieeg'\n", 66 | "task = 'film'\n", 67 | "acquisition = 'clinical'\n", 68 | "fs_dir = '/Fridge/users/julia/project_chill_dataset_paper/data/freesurfer2/sub-01'" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "id": "boring-contrast", 74 | "metadata": {}, 75 | "source": [ 76 | "### Load electrodes info" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 3, 82 | "id": "swiss-count", 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "electrodes_path = mne_bids.BIDSPath(subject=subject,\n", 87 | " session=session,\n", 88 | " suffix='electrodes',\n", 89 | " extension='tsv',\n", 90 | " datatype=datatype,\n", 91 | " acquisition=acquisition,\n", 92 | " root=bids_dir)\n", 93 | "electrodes = pd.read_csv(str(electrodes_path), sep='\\t', header=0, index_col=None)\n", 94 | "coords = electrodes[['x', 'y', 'z']].values" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "id": "unique-audio", 100 | "metadata": {}, 101 | "source": [ 102 | "### Load channels info" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 4, 108 | "id": "molecular-wilson", 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [ 112 | "channels_path = mne_bids.BIDSPath(subject=subject,\n", 113 | " session=session,\n", 114 | " suffix='channels',\n", 115 | " extension='tsv',\n", 116 | " datatype=datatype,\n", 117 | " task=task,\n", 118 | " acquisition=acquisition,\n", 119 | " root=bids_dir)\n", 120 | "channels = pd.read_csv(str(channels_path.match()[0]), sep='\\t', header=0, index_col=None)" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "id": "stock-transmission", 126 | "metadata": {}, 127 | "source": [ 128 | "### Load iEEG data info, set channel types and drop all irrelevant channels (not iEEG)" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 5, 134 | "id": "complicated-spread", 135 | "metadata": {}, 136 | "outputs": [ 137 | { 138 | "name": "stdout", 139 | "output_type": "stream", 140 | "text": [ 141 | "Extracting parameters from /Fridge/users/julia/project_chill_dataset_paper/data/BIDS2/sub-01/ses-iemu/ieeg/sub-01_ses-iemu_task-film_acq-clinical_run-1_ieeg.vhdr...\n", 142 | "Setting channel info structure...\n" 143 | ] 144 | }, 145 | { 146 | "data": { 147 | "text/html": [ 148 | "\n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | "
Measurement dateJanuary 01, 1900 00:00:00 GMT
ExperimenterUnknown
ParticipantUnknown
Digitized points0 points
Good channels103 sEEG
Bad channelsNone
EOG channelsNot available
ECG channelsNot available
Sampling frequency2048.00 Hz
Highpass0.00 Hz
Lowpass1024.00 Hz
Filenamessub-01_ses-iemu_task-film_acq-clinical_run-1_ieeg.eeg
Duration00:07:00 (HH:MM:SS)
" 217 | ], 218 | "text/plain": [ 219 | "" 220 | ] 221 | }, 222 | "execution_count": 5, 223 | "metadata": {}, 224 | "output_type": "execute_result" 225 | } 226 | ], 227 | "source": [ 228 | "data_path = mne_bids.BIDSPath(subject=subject,\n", 229 | " session=session,\n", 230 | " suffix='ieeg',\n", 231 | " extension='vhdr',\n", 232 | " datatype=datatype,\n", 233 | " task=task,\n", 234 | " acquisition=acquisition,\n", 235 | " root=bids_dir)\n", 236 | "raw = mne.io.read_raw_brainvision(str(data_path.match()[0]), scale=1.0, preload=False, verbose=True)\n", 237 | "raw.set_channel_types({ch_name: str(x).lower()\n", 238 | " if str(x).lower() in ['ecog', 'seeg'] else 'misc'\n", 239 | " for ch_name, x in zip(raw.ch_names, channels['type'].values)})\n", 240 | "raw.drop_channels([raw.ch_names[i] for i, j in enumerate(raw.get_channel_types()) if j == 'misc'])" 241 | ] 242 | }, 243 | { 244 | "cell_type": "markdown", 245 | "id": "tribal-canon", 246 | "metadata": {}, 247 | "source": [ 248 | "### Transform electrode coordinate to the freesurfer RAS space to visualize them on the surface" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": 6, 254 | "id": "tamil-serial", 255 | "metadata": {}, 256 | "outputs": [ 257 | { 258 | "name": "stderr", 259 | "output_type": "stream", 260 | "text": [ 261 | "/tmp/ipykernel_3730404/702744162.py:7: RuntimeWarning: Fiducial point nasion not found, assuming identity unknown to head transformation\n", 262 | " raw.set_montage(montage)\n" 263 | ] 264 | }, 265 | { 266 | "data": { 267 | "text/html": [ 268 | "\n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | "
Measurement dateJanuary 01, 1900 00:00:00 GMT
ExperimenterUnknown
ParticipantUnknown
Digitized points0 points
Good channels103 sEEG
Bad channelsNone
EOG channelsNot available
ECG channelsNot available
Sampling frequency2048.00 Hz
Highpass0.00 Hz
Lowpass1024.00 Hz
Filenamessub-01_ses-iemu_task-film_acq-clinical_run-1_ieeg.eeg
Duration00:07:00 (HH:MM:SS)
" 337 | ], 338 | "text/plain": [ 339 | "" 340 | ] 341 | }, 342 | "execution_count": 6, 343 | "metadata": {}, 344 | "output_type": "execute_result" 345 | } 346 | ], 347 | "source": [ 348 | "x = nibabel.load(os.path.join(fs_dir, 'mri', 'orig.mgz'))\n", 349 | "vox_coords = np.round(mne.transforms.apply_trans(np.linalg.inv(x.affine), coords)).astype(int)\n", 350 | "ras_coords = mne.transforms.apply_trans(x.header.get_vox2ras_tkr(), vox_coords)\n", 351 | "ras_coords = ras_coords / 1000\n", 352 | "\n", 353 | "montage = mne.channels.make_dig_montage(ch_pos=dict(zip(raw.ch_names, ras_coords)), coord_frame='mri')\n", 354 | "raw.set_montage(montage)" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "id": "worst-collar", 360 | "metadata": {}, 361 | "source": [ 362 | "### Visualize electrodes\n", 363 | "\n", 364 | "*By default, if SEEG channels are present, MNE will make the visualization transparent" 365 | ] 366 | }, 367 | { 368 | "cell_type": "code", 369 | "execution_count": 8, 370 | "id": "eastern-geology", 371 | "metadata": {}, 372 | "outputs": [ 373 | { 374 | "name": "stdout", 375 | "output_type": "stream", 376 | "text": [ 377 | "Channel types::\tseeg: 103\n" 378 | ] 379 | }, 380 | { 381 | "data": { 382 | "application/vnd.jupyter.widget-view+json": { 383 | "model_id": "ac9d1c1403dc4d8abcf2a00f224cff31", 384 | "version_major": 2, 385 | "version_minor": 0 386 | }, 387 | "text/plain": [ 388 | "HBox(children=(Text(value='', layout=Layout(margin='2px 0px 2px 0px', min_width='0px'), placeholder='Type a fi…" 389 | ] 390 | }, 391 | "metadata": {}, 392 | "output_type": "display_data" 393 | }, 394 | { 395 | "data": { 396 | "application/vnd.jupyter.widget-view+json": { 397 | "model_id": "fd38814bef7347af8ac53b37cb31baa4", 398 | "version_major": 2, 399 | "version_minor": 0 400 | }, 401 | "text/plain": [ 402 | "HBox(children=(ViewInteractiveWidget(height=800, layout=Layout(height='auto'), width=800),))" 403 | ] 404 | }, 405 | "metadata": {}, 406 | "output_type": "display_data" 407 | } 408 | ], 409 | "source": [ 410 | "from packaging import version\n", 411 | "\n", 412 | "if version.parse(mne.__version__) <= version.parse('0.22.0'):\n", 413 | " fig = mne.viz.plot_alignment(raw.info,\n", 414 | " subject='sub-' + subject,\n", 415 | " subjects_dir=os.path.dirname(fs_dir),\n", 416 | " surfaces=['pial'],\n", 417 | " coord_frame='mri')\n", 418 | "else:\n", 419 | " # trans argument became mandatory\n", 420 | " identity_trans = mne.transforms.Transform('head', 'mri')\n", 421 | " fig = mne.viz.plot_alignment(raw.info, trans=identity_trans,\n", 422 | " subject='sub-' + subject,\n", 423 | " subjects_dir=os.path.dirname(fs_dir),\n", 424 | " surfaces=['pial'],\n", 425 | " coord_frame='mri')\n", 426 | "mne.viz.set_3d_view(fig, 180, 70, distance=.5)" 427 | ] 428 | } 429 | ], 430 | "metadata": { 431 | "kernelspec": { 432 | "display_name": "mne_pip", 433 | "language": "python", 434 | "name": "mne_pip" 435 | }, 436 | "language_info": { 437 | "codemirror_mode": { 438 | "name": "ipython", 439 | "version": 3 440 | }, 441 | "file_extension": ".py", 442 | "mimetype": "text/x-python", 443 | "name": "python", 444 | "nbconvert_exporter": "python", 445 | "pygments_lexer": "ipython3", 446 | "version": "3.10.4" 447 | } 448 | }, 449 | "nbformat": 4, 450 | "nbformat_minor": 5 451 | } 452 | --------------------------------------------------------------------------------