EEG motor dataset, cannot see the expected reslts

:red_question_mark: If you have a question or issue with MNE-Python, please include the following info:

  • MNE version: 11.0
  • operating system: Windows 11

So I tried analyzing data for all 109 participants in this dataset EEG Motor Movement/Imagery Dataset v1.0.0, and made C4 and C3 plots for the alpha and beta frequency bands for the left hand activity. I attached the plots below, please take a look. I’m not sure if this is the expected pattern I should see. I was expecting a stronger difference in the alpha band (C3 is stronger), but instead I saw this effect in the beta band.

In the meantime, I found this paper which I think is relavant: The Cortical Physiology of Ipsilateral Limb Movements - PMC . According to this paper, it says that ipsilerateral brain activity in both beta and alpha is also there during movement, which seems to align with what I found. However, I haven’t found any papers of the unique roles of alpha vs beta in hand movement. Can you please clarify what is expected, and any papers you have read related to this?


As an additional step, I looked at the numerical power values with each of the plots with this code (this is just one of the analyses for LEFT hand ALPHA. I did the same code for all frequencies of interest and both hands). This is to confirm that I get the desired power effects despite the plot not showing it.

print(grand_power_left_alpha.ch_names.index("C3"))
print(grand_power_left_alpha.ch_names.index("C4")) #this tells the numerical index for the location of c3 and c4

c3_idx = grand_power_left_alpha.ch_names.index("C3")
c4_idx = grand_power_left_alpha.ch_names.index("C4")

c3_power = grand_power_left_alpha.data\[c3_idx\]
c4_power = grand_power_left_alpha.data\[c4_idx\]

c3_alpha = c3_power.mean(axis=0)
c4_alpha = c4_power.mean(axis=0)

time_mask = (grand_power_left_alpha.times >= 0) & (grand_power_left_alpha.times <= 0.8)

print("C3 alpha:", c3_alpha\[time_mask\].mean())
print("C4 alpha:", c4_alpha\[time_mask\].mean())

and got this:

C3 alpha: 5.715649001507285e-09
C4 alpha: 7.653899077490554e-09

→ as expected the C4 is larger. I got the same pattern for LEFT BETA as well

However for RIGHT BETA, C4 is larger, which doesn’t seem right.

c3_idx_right = grand_power_right_beta.ch_names.index("C3")

c4_idx_right = grand_power_right_beta.ch_names.index("C4")

c3_power_right = grand_power_right_beta.data\[c3_idx_right\]

c4_power_right = grand_power_right_beta.data\[c4_idx_right\]

c3_beta_right = c3_power_right.mean(axis=0)

c4_beta_right = c4_power_right.mean(axis=0)

time_mask_right = (grand_power_right_beta.times >= 0) & (grand_power_right_beta.times <= 0.8) #"Give me only C3 alpha values during movement (0–0.8 seconds)."

print("C3 beta:", c3_beta_right\[time_mask_right\].mean())#make sure to use the new mask at the top!!

print("C4 beta:", c4_beta_right\[time_mask_right\].mean())
C3 beta: 1.5978303070695456e-09
C4 beta: 2.2528216151065487e-09

Why don’t I get the correct results? I would appreciate your guidance.

Hi,

Could you format your code snippet inside triple-backticks? Ideally, also post the code that builds grand_power_left_alpha, it could be related to epoching, baseline, or averaging.

I’m not sure what “the correct results” means in this context. Are you trying to replicate a specific published work or a general expectation about contralateral lateralisation?

Cheers,

Carina

Thank you for your reply. Here is my above code with backticks added.

Here’s my code for grand_power_left_alpha:

power_list_left_alpha = \[ \]

for subject, raws in all_data.items():
raw_resampled = raws\[0\]

events, event_id = mne.events_from_annotations(raw)
epochs = mne.Epochs(raw_resampled, events, event_id, tmin=-0.5, tmax=2, preload=True)#we have to get a bigger range for alpha because it has longer wavelengths

left_epochs = epochs[“T1”]

power = mne.time_frequency.tfr_morlet(
left_epochs,
freqs=np.arange(8, 12),
n_cycles=7,
return_itc=False
)

power_list_left_alpha.append(power)

grand_power_left_alpha = mne.grand_average(power_list_left_alpha)

print(‘done’)


My expected result is having greater power in mu band (which i thought was the same as alpha band) in the contralateral hemisphere, but I realized I understood it wrong. Instead, it's supposed to be mu suppression. I think the below link has the expected results. Sorry for the confusion, I'm still figuring this out.

https://www.bci2000.org/mediawiki/index.php/User_Tutorial:Introduction_to_the_Mu_Rhythm

Hi,

Yes, your correction about mu suppression is the right direction. Looking at the code, I would check a few implementation details before interpreting the C3/C4 difference.

First, the events and epochs appear to use different objects:

raw_resampled = raws[0]
events, event_id = mne.events_from_annotations(raw)
epochs = mne.Epochs(raw_resampled, events, event_id, ...)

Apart from raw possibly referring to a different recording, event sample indices may no longer match after resampling. I would either create the epochs before resampling or resample the events together with the data:

events, event_id = mne.events_from_annotations(raw)
raw_resampled, events_resampled = raw.copy().resample(
    new_sfreq, events=events
)
epochs = mne.Epochs(
    raw_resampled,
    events_resampled,
    event_id,
    tmin=-1.5,
    tmax=2,
    preload=True,
)

Second, if raws contains several runs, raws[0] uses only the first one. It is worth checking which run this is. In EEGMMIDB, the meanings of T1 and T2 depend on the run: they represent left/right fist in runs 3, 4, 7, 8, 11 and 12, but both fists/both feet in runs 5, 6, 9, 10, 13 and 14. Executed and imagined movement should also be analysed separately.

Finally, I would apply baseline correction to each subject’s TFR before the grand average, for example:

power.apply_baseline(baseline=(-1.0, 0), mode="percent")

With percent baseline correction, more negative values represent stronger suppression. I would then calculate the within-subject contralateral-versus-ipsilateral difference before averaging across participants, rather than comparing the absolute C3 and C4 power values after the grand average.

The MNE ERDS example follows this general approach:

Ok, thanks. Can this above code be done with time frequency plots using tfr morlet? I am trying to apply what i learned from an eeg course i did on udemy, and I don’t want to overcomplicate everything fast. Is it necessary to use ERD for this purpose?

I would like your guidance on how to apply tgis for time frequency plots.

Yes — you can use Morlet wavelets for this. Morlet TFR and ERD are not two competing approaches.

The Morlet transform estimates how spectral power changes across time and frequency. ERD/ERS describes those same power changes relative to a pre-movement baseline. Therefore, you do not need a separate “ERD function”; you can compute a Morlet TFR and then apply baseline normalization:

freqs = np.arange(6, 31)

power = epochs.compute_tfr(
    method="morlet",
    freqs=freqs,
    n_cycles=freqs / 2,
    return_itc=False,
    average=False,
    decim=2,
)

power.apply_baseline(
    baseline=(-1.0, 0),
    mode="percent",
)

After this correction, negative values indicate power suppression relative to baseline (ERD), while positive values indicate increased power (ERS). You can then average the trials for each condition and plot C3 and C4.

For your lateralisation question, baseline-normalized power will usually be more informative than absolute power because absolute C3/C4 values can differ for reasons unrelated to the movement condition.

I would first test this on one subject and one correctly identified run. The event/resampling and T1/T2 issues mentioned above still need to be resolved before interpreting the group result.

```(power_beta.apply_baseline(baseline=(-1.0, 0), mode="percent")``` So I tried doing this before the grand average and it says the baseline interval is greater than the epochs data, which makes sense. My epochs range is this; tmin=-0.2, tmax=0.8, which I chose because that's what was shown to me in the tutorial in my course. Do I change the epochs range or the baseline range? Which do you reccomend and why?

Yes, I would extend the epoch rather than shorten the baseline to (-0.2, 0).

With your current epochs, MNE is correct: the interval (-1, 0) is not fully present in the data. Also, 200 ms is very short for a stable spectral baseline, particularly if you apply the same approach to the 8–12 Hz range. At 8 Hz, it contains fewer than two cycles.

For example:

epochs = mne.Epochs(
    raw_resampled,
    events_resampled,
    event_id,
    tmin=-1.5,
    tmax=2.0,
    baseline=None,
    preload=True,
)

# Select the relevant condition after confirming
# what T1/T2 mean in this particular run.
condition_epochs = epochs["T1"]

power_beta = mne.time_frequency.tfr_morlet(
    condition_epochs,
    freqs=np.arange(13, 31),
    n_cycles=7,
    return_itc=False,
)

power_beta.apply_baseline(
    baseline=(-1.0, 0.0),
    mode="percent",
)

# Optional: create a separate object showing only the movement interval
power_beta_plot = power_beta.copy().crop(tmin=0.0, tmax=0.8)

Apply the baseline to each subject’s TFR before calculating the grand average.

This assumes that -1…0 s is genuinely a resting pre-movement interval. If a cue or another part of the task already starts before time zero, the baseline should instead be chosen before that cue.

Ok thanks. Also, which result should I be expecting if I’m using TFR, given that there is mu suppression in the opposite hemisphere to the hand movement? Will it show as low power? Please let me know.want to know what to expect after baseline correction. Ideally, blue should represent low power/negative values.

Yes. With mode="percent":

  • 0 means no change from baseline;
  • negative values mean lower power, or ERD/mu suppression;
  • positive values mean higher power, or ERS.

For right-hand movement, you would typically expect a more negative mu-band change over C3 than C4. For left-hand movement, the pattern is usually reversed.

For example, if C3 is -0.30 and C4 is -0.05 during right-hand movement, that means approximately a 30% decrease over C3 versus a 5% decrease over C4 — stronger contralateral suppression over C3.

Blue represents suppression only if your chosen colormap maps negative values to blue. Always check the colorbar and use a diverging scale centered on zero. Also, not every participant will show equally clear lateralisation, so keep executed and imagined movement separate.

I’m only looking at real movement in this data file. Here is the code I wrote for epoching one participant’s data before making a plot, incorporating baseline correction

```events, event_id = mne.events_from_annotations(subject1)
epochs = mne.Epochs(subject1, events, event_id, tmin=-1.5, tmax=2, preload=True)#we have to get a bigger range for alpha because it has longer wavelengths

left_epochs = epochs[“T1”]

power_mu = mne.time_frequency.tfr_morlet(
left_epochs,
freqs=np.arange(8, 12),
n_cycles=7,
return_itc=False
)
power_mu.apply_baseline(baseline=(-1, 0), mode=“percent”)```

Here is what I got for left and right hemisphere activity for LEFT hand movement in one participant after plotting:

I realized the scale on the colour bar is slightly different between these two graphs. However, it is centered on zero as you suggested it should be. These results are still inconclusive to me, as I expected more dark blue (more negative values) in the contralateral hemisphere. Can you please let me know if there is anything to fix?

Should i use my old approach with the time mask to look at the numerical values of power? please let me know if i should use this approach again.

Edit:Using the old approach i got these values, which still don’t give the expected results of mu suppression. Can you please help me understand why this is that case?

C3: -0.04203356897831294
C4: 0.1567672136040133

Hi @viranovskaya, did you see my previous question? Please let me know.

Hi, yes, I saw it — sorry for the delay.

Your calculation shows that this participant does not have the expected contralateral mu suppression in the selected 0–0.8 s window: for left-hand movement, C3 changes by about −4.2%, while C4 increases by about 15.7%. This is not necessarily a coding error, since a clear lateralised pattern is not guaranteed in every participant.

Before interpreting it, I would check a few things:

  1. Add baseline=None when creating the epochs. Otherwise, MNE applies a time-domain baseline correction before the TFR baseline correction:
epochs = mne.Epochs(
    subject1,
    events,
    event_id,
    tmin=-1.5,
    tmax=2.0,
    baseline=None,
    preload=True,
)
  1. Confirm that T1 means executed left-fist movement in every run you included. In this dataset, the meaning of T1 and T2 depends on the run, so execution, imagery, bilateral-fist and feet runs should not be combined under the same label.

  2. Use exactly the same color limits for the C3 and C4 plots. In the screenshot, the two color bars have very different ranges, so their colors cannot be compared directly.

  3. Try a later window as well, for example 0.5–2.0 s. With seven cycles in the 8–11 Hz range, the estimate is temporally smoothed around movement onset.

The time-mask approach is fine for a numerical summary, but I would first run these checks and then examine the effect across participants rather than deciding from one participant alone.