|
21 | 21 |
|
22 | 22 | This tutorial is loosely divided into two parts:
|
23 | 23 |
|
24 |
| -1. We will first focus on producing ERP time-locked to the **visual |
| 24 | +1. We will first focus on producing ERPs time-locked to the **visual |
25 | 25 | stimulation**, conditional on response correctness and response time in
|
26 | 26 | order to familiarize ourselves with the `~mne.epochs.make_metadata`
|
27 | 27 | function.
|
|
114 | 114 | # a value of ``NaN``, simply indicating that no event latency could be
|
115 | 115 | # extracted.
|
116 | 116 | #
|
117 |
| -# Now, there's a problem here. We want investigate the visual ERPs only, |
| 117 | +# Now, there's a problem here. We want to investigate the visual ERPs |
118 | 118 | # conditional on responses. But the metadata that was just created contains
|
119 | 119 | # one row for **every** event, including responses. While we **could** create
|
120 | 120 | # epochs for all events, allowing us to pass those metadata, and later subset
|
121 |
| -# the created events, there's a more elegant way to handle things: |
| 121 | +# the created events, there's a more elegant way to handle this: |
122 | 122 | # `~mne.epochs.make_metadata` has a ``row_events`` parameter that
|
123 | 123 | # allows us to specify for which events to create metadata **rows**, while
|
124 | 124 | # still creating **columns for all events** in the ``event_id`` dictionary.
|
125 | 125 | #
|
126 | 126 | # Because the metadata, then, only pertains to a subset of our original events,
|
127 | 127 | # it's important to keep the returned ``events`` and ``event_id`` around for
|
128 |
| -# later use when we're actually going to create our epochs, to ensure that |
129 |
| -# metadata, events, and event descriptions stay in sync. |
| 128 | +# later use when we actually create our epochs, to ensure that metadata, |
| 129 | +# events, and event descriptions stay in sync. |
130 | 130 |
|
131 | 131 | row_events = ['stimulus/compatible/target_left',
|
132 | 132 | 'stimulus/compatible/target_right',
|
|
157 | 157 | # parameter. For example, in the case of the HEDs ``response/left`` and
|
158 | 158 | # ``response/right``, we could pass ``keep_first='response'`` to generate a new
|
159 | 159 | # column, ``response``, containing the latency of the respective event. This
|
160 |
| -# value pertains only the first (or, in this specific example: the only) |
| 160 | +# value represents the first (or, in this specific example: the only) |
161 | 161 | # response, regardless of side (left or right). To indicate **which** event
|
162 |
| -# type (here: response side) was matched, a second column is added: |
163 |
| -# ``first_response``. The values in this column are the event types without the |
164 |
| -# string used for matching, as it is already encoded as the column name, i.e. |
165 |
| -# in our example, we expect it to only contain ``'left'`` and ``'right'``. |
| 162 | +# type (here: response side) was matched, a second column named |
| 163 | +# ``first_response`` is added. The values in this column are the event types |
| 164 | +# without the string used for matching, as it is already encoded as the column |
| 165 | +# name, i.e. in our example, we expect it to only contain ``'left'`` and |
| 166 | +# ``'right'``. |
166 | 167 |
|
167 | 168 | keep_first = 'response'
|
168 | 169 | metadata, events, event_id = mne.epochs.make_metadata(
|
|
182 | 183 | # We're facing a similar issue with the stimulus events, and now there are not
|
183 | 184 | # only two, but **four** different types: ``stimulus/compatible/target_left``,
|
184 | 185 | # ``stimulus/compatible/target_right``, ``stimulus/incompatible/target_left``,
|
185 |
| -# and ``stimulus/incompatible/target_right``. Even more, because in the present |
186 |
| -# paradigm stimuli were presented in rapid succession, sometimes multiple |
187 |
| -# stimulus events occurred within the 1.5 second time window we're using to |
188 |
| -# generate our metadata. See for example: |
| 186 | +# and ``stimulus/incompatible/target_right``. What's more, because in the |
| 187 | +# present paradigm stimuli were presented in rapid succession, sometimes |
| 188 | +# multiple stimulus events occurred within the 1.5 second time window we used |
| 189 | +# to generate our metadata. See for example: |
189 | 190 |
|
190 | 191 | metadata.loc[metadata['stimulus/compatible/target_left'].notna() &
|
191 | 192 | metadata['stimulus/compatible/target_right'].notna(),
|
|
246 | 247 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
247 | 248 | #
|
248 | 249 | # It's finally time to create our epochs! We set the metadata directly on
|
249 |
| -# instantiation via the ``metadata`` parameter. Also it is important to |
| 250 | +# instantiation via the ``metadata`` parameter. Also, it is important to |
250 | 251 | # remember to pass ``events`` and ``event_id`` as returned from
|
251 | 252 | # `~mne.epochs.make_metadata`, as we only created metadata for a subset of
|
252 | 253 | # our original events by passing ``row_events``. Otherwise, the length
|
253 |
| -# of the metadata and the number of epochs would not match and MNE-Python |
254 |
| -# would raise an error. |
| 254 | +# of the metadata and the number of epochs would not match, which would raise |
| 255 | +# an error. |
255 | 256 |
|
256 | 257 | epochs_tmin, epochs_tmax = -0.1, 0.4 # epochs range: [-0.1, 0.4] s
|
257 | 258 | reject = {'eeg': 250e-6} # exclude epochs with strong artifacts
|
|
260 | 261 | reject=reject, preload=True)
|
261 | 262 |
|
262 | 263 | # %%
|
263 |
| -# Lastly, let's visualize the ERPs evoked by the visual stimulation, once for |
264 |
| -# all trials with correct responses, and once for all trials with correct |
| 264 | +# Lastly, let's visualize the ERPs associated with the visual stimulation, once |
| 265 | +# for all trials with correct responses, and once for all trials with correct |
265 | 266 | # responses and a response time greater than 0.5 seconds
|
266 | 267 | # (i.e., slow responses).
|
267 | 268 | vis_erp = epochs['response_correct'].average()
|
268 | 269 | vis_erp_slow = epochs['(not response_correct) & '
|
269 | 270 | '(response > 0.3)'].average()
|
270 | 271 |
|
271 |
| -fig, ax = plt.subplots(2, figsize=(6, 6)) |
| 272 | +fig, ax = plt.subplots(2, figsize=(6, 6), layout='constrained') |
272 | 273 | vis_erp.plot(gfp=True, spatial_colors=True, axes=ax[0])
|
273 | 274 | vis_erp_slow.plot(gfp=True, spatial_colors=True, axes=ax[1])
|
274 | 275 | ax[0].set_title('Visual ERPs – All Correct Responses')
|
275 | 276 | ax[1].set_title('Visual ERPs – Slow Correct Responses')
|
276 |
| -fig.tight_layout() |
277 |
| -fig |
278 | 277 |
|
279 | 278 | # %%
|
280 | 279 | # Aside from the fact that the data for the (much fewer) slow responses looks
|
|
298 | 297 | #
|
299 | 298 | # We only wish to consider the **last** stimulus and response in each time
|
300 | 299 | # window: Remember that we're dealing with rapid stimulus presentations in
|
301 |
| -# this paradigm; taking the last response – at time point zero – and the last |
302 |
| -# stimulus – the one closest to the response – ensures we actually create |
| 300 | +# this paradigm; taking the last response (at time point zero) and the last |
| 301 | +# stimulus (the one closest to the response) ensures that we actually create |
303 | 302 | # the right stimulus-response pairings. We can achieve this by passing the
|
304 |
| -# ``keep_last`` parameter, which works exactly like ``keep_first`` we got to |
305 |
| -# know above, only that it keeps the **last** occurrences of the specified |
| 303 | +# ``keep_last`` parameter, which works exactly like ``keep_first`` we used |
| 304 | +# previously, only that it keeps the **last** occurrences of the specified |
306 | 305 | # events and stores them in columns whose names start with ``last_``.
|
307 | 306 |
|
308 | 307 | metadata_tmin, metadata_tmax = -1.5, 0
|
|
316 | 315 | keep_last=keep_last)
|
317 | 316 |
|
318 | 317 | # %%
|
319 |
| -# Exactly like in the previous example, create new columns ``stimulus_side`` |
| 318 | +# Exactly like in the previous example, we create new columns ``stimulus_side`` |
320 | 319 | # and ``response_correct``.
|
321 | 320 |
|
322 | 321 | # left-side stimulation
|
|
339 | 338 |
|
340 | 339 | # %%
|
341 | 340 | # Now it's already time to epoch the data! When deciding upon the epochs
|
342 |
| -# duration for this specific analysis, we need to ensure we see quite a bit of |
343 |
| -# signal from before and after the motor response. We also must be aware of |
| 341 | +# duration for this specific analysis, we need to ensure to include quite a bit |
| 342 | +# of signal from before and after the motor response. We also must be aware of |
344 | 343 | # the fact that motor-/muscle-related signals will most likely be present
|
345 | 344 | # **before** the response button trigger pulse appears in our data, so the time
|
346 | 345 | # period close to the response event should not be used for baseline
|
|
0 commit comments