├── 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 | " | Measurement date | \n",
151 | " \n",
152 | " January 01, 1900 00:00:00 GMT | \n",
153 | " \n",
154 | "
\n",
155 | " \n",
156 | " | Experimenter | \n",
157 | " \n",
158 | " Unknown | \n",
159 | " \n",
160 | "
\n",
161 | " Participant | \n",
162 | " \n",
163 | " Unknown | \n",
164 | " \n",
165 | " \n",
166 | " \n",
167 | " | Digitized points | \n",
168 | " \n",
169 | " 0 points | \n",
170 | " \n",
171 | "
\n",
172 | " \n",
173 | " | Good channels | \n",
174 | " 103 sEEG | \n",
175 | "
\n",
176 | " \n",
177 | " | Bad channels | \n",
178 | " None | \n",
179 | "
\n",
180 | " \n",
181 | " | EOG channels | \n",
182 | " Not available | \n",
183 | "
\n",
184 | " \n",
185 | " | ECG channels | \n",
186 | " Not available | \n",
187 | " \n",
188 | "
\n",
189 | " | Sampling frequency | \n",
190 | " 2048.00 Hz | \n",
191 | "
\n",
192 | " \n",
193 | " \n",
194 | " \n",
195 | " | Highpass | \n",
196 | " 0.00 Hz | \n",
197 | "
\n",
198 | " \n",
199 | " \n",
200 | " \n",
201 | " | Lowpass | \n",
202 | " 1024.00 Hz | \n",
203 | "
\n",
204 | " \n",
205 | " \n",
206 | " \n",
207 | " \n",
208 | " | Filenames | \n",
209 | " sub-01_ses-iemu_task-film_acq-clinical_run-1_ieeg.eeg | \n",
210 | "
\n",
211 | " \n",
212 | " \n",
213 | " | Duration | \n",
214 | " 00:07:00 (HH:MM:SS) | \n",
215 | "
\n",
216 | "
"
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 | " | Measurement date | \n",
271 | " \n",
272 | " January 01, 1900 00:00:00 GMT | \n",
273 | " \n",
274 | "
\n",
275 | " \n",
276 | " | Experimenter | \n",
277 | " \n",
278 | " Unknown | \n",
279 | " \n",
280 | "
\n",
281 | " Participant | \n",
282 | " \n",
283 | " Unknown | \n",
284 | " \n",
285 | " \n",
286 | " \n",
287 | " | Digitized points | \n",
288 | " \n",
289 | " 0 points | \n",
290 | " \n",
291 | "
\n",
292 | " \n",
293 | " | Good channels | \n",
294 | " 103 sEEG | \n",
295 | "
\n",
296 | " \n",
297 | " | Bad channels | \n",
298 | " None | \n",
299 | "
\n",
300 | " \n",
301 | " | EOG channels | \n",
302 | " Not available | \n",
303 | "
\n",
304 | " \n",
305 | " | ECG channels | \n",
306 | " Not available | \n",
307 | " \n",
308 | "
\n",
309 | " | Sampling frequency | \n",
310 | " 2048.00 Hz | \n",
311 | "
\n",
312 | " \n",
313 | " \n",
314 | " \n",
315 | " | Highpass | \n",
316 | " 0.00 Hz | \n",
317 | "
\n",
318 | " \n",
319 | " \n",
320 | " \n",
321 | " | Lowpass | \n",
322 | " 1024.00 Hz | \n",
323 | "
\n",
324 | " \n",
325 | " \n",
326 | " \n",
327 | " \n",
328 | " | Filenames | \n",
329 | " sub-01_ses-iemu_task-film_acq-clinical_run-1_ieeg.eeg | \n",
330 | "
\n",
331 | " \n",
332 | " \n",
333 | " | Duration | \n",
334 | " 00:07:00 (HH:MM:SS) | \n",
335 | "
\n",
336 | "
"
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 | " | Measurement date | \n",
151 | " \n",
152 | " January 01, 1900 00:00:00 GMT | \n",
153 | " \n",
154 | "
\n",
155 | " \n",
156 | " | Experimenter | \n",
157 | " \n",
158 | " Unknown | \n",
159 | " \n",
160 | "
\n",
161 | " Participant | \n",
162 | " \n",
163 | " Unknown | \n",
164 | " \n",
165 | " \n",
166 | " \n",
167 | " | Digitized points | \n",
168 | " \n",
169 | " 0 points | \n",
170 | " \n",
171 | "
\n",
172 | " \n",
173 | " | Good channels | \n",
174 | " 103 sEEG | \n",
175 | "
\n",
176 | " \n",
177 | " | Bad channels | \n",
178 | " None | \n",
179 | "
\n",
180 | " \n",
181 | " | EOG channels | \n",
182 | " Not available | \n",
183 | "
\n",
184 | " \n",
185 | " | ECG channels | \n",
186 | " Not available | \n",
187 | " \n",
188 | "
\n",
189 | " | Sampling frequency | \n",
190 | " 2048.00 Hz | \n",
191 | "
\n",
192 | " \n",
193 | " \n",
194 | " \n",
195 | " | Highpass | \n",
196 | " 0.00 Hz | \n",
197 | "
\n",
198 | " \n",
199 | " \n",
200 | " \n",
201 | " | Lowpass | \n",
202 | " 1024.00 Hz | \n",
203 | "
\n",
204 | " \n",
205 | " \n",
206 | " \n",
207 | " \n",
208 | " | Filenames | \n",
209 | " sub-01_ses-iemu_task-film_acq-clinical_run-1_ieeg.eeg | \n",
210 | "
\n",
211 | " \n",
212 | " \n",
213 | " | Duration | \n",
214 | " 00:07:00 (HH:MM:SS) | \n",
215 | "
\n",
216 | "
"
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 | " | Measurement date | \n",
271 | " \n",
272 | " January 01, 1900 00:00:00 GMT | \n",
273 | " \n",
274 | "
\n",
275 | " \n",
276 | " | Experimenter | \n",
277 | " \n",
278 | " Unknown | \n",
279 | " \n",
280 | "
\n",
281 | " Participant | \n",
282 | " \n",
283 | " Unknown | \n",
284 | " \n",
285 | " \n",
286 | " \n",
287 | " | Digitized points | \n",
288 | " \n",
289 | " 0 points | \n",
290 | " \n",
291 | "
\n",
292 | " \n",
293 | " | Good channels | \n",
294 | " 103 sEEG | \n",
295 | "
\n",
296 | " \n",
297 | " | Bad channels | \n",
298 | " None | \n",
299 | "
\n",
300 | " \n",
301 | " | EOG channels | \n",
302 | " Not available | \n",
303 | "
\n",
304 | " \n",
305 | " | ECG channels | \n",
306 | " Not available | \n",
307 | " \n",
308 | "
\n",
309 | " | Sampling frequency | \n",
310 | " 2048.00 Hz | \n",
311 | "
\n",
312 | " \n",
313 | " \n",
314 | " \n",
315 | " | Highpass | \n",
316 | " 0.00 Hz | \n",
317 | "
\n",
318 | " \n",
319 | " \n",
320 | " \n",
321 | " | Lowpass | \n",
322 | " 1024.00 Hz | \n",
323 | "
\n",
324 | " \n",
325 | " \n",
326 | " \n",
327 | " \n",
328 | " | Filenames | \n",
329 | " sub-01_ses-iemu_task-film_acq-clinical_run-1_ieeg.eeg | \n",
330 | "
\n",
331 | " \n",
332 | " \n",
333 | " | Duration | \n",
334 | " 00:07:00 (HH:MM:SS) | \n",
335 | "
\n",
336 | "
"
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 |
--------------------------------------------------------------------------------