# Spatiotemporal permutation F-test - No sign. Clusters found

**URL:** <https://mne.discourse.group/t/spatiotemporal-permutation-f-test-no-sign-clusters-found/10974>\
**Category:** Support & Discussions\
**Tags:** eeg\
**Created:** [March 19, 2025, 2:18pm UTC](https://mne.discourse.group/t/spatiotemporal-permutation-f-test-no-sign-clusters-found/10974 "2025-03-19T14:18:56Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![TimteTim](https://avatars.discourse-cdn.com/v4/letter/t/50afbb/32.png) [@TimteTim](https://mne.discourse.group/u/TimteTim)\
**Post date:** [March 19, 2025, 2:18pm UTC](https://mne.discourse.group/t/spatiotemporal-permutation-f-test-no-sign-clusters-found/10974/1 "2025-03-19T14:18:56Z")

</div>

_- MNE version: 1.9_  
_- operating system: Windows 11_  
_- 64 electrodes used (data already preprocessed: ICA, Bandpass filtered, Re-referenced.)_

Dear MNE family,

I have been exploring the spatio-temporal permutation F-test in MNE-Python, following the well-written tutorial. I am using EEG data from a previous experiment with two conditions: standing and walking. In the experiment, participants stood for 1 minute to establish a baseline, then walked. I created 30 events for each condition, spaced 2 seconds apart, with each event lasting 1.5 seconds. I then extracted epochs for these conditions and applied the spatio-temporal permutation F-test as outlined in the tutorial.

```python
montage = mne.channels.make_standard_montage("easycap-M1")
raw.set_montage(montage)
sfreq = raw.info['sfreq'] 
events, event_id = mne.events_from_annotations(raw)

start_standing = event_id['Photosensor 255']
start_walking = event_id['Photosensor 2']

event_samples = events[:, 0]
event_types = events[:, 2] 

marker_sample_start_standing = event_samples[event_types == start_standing][0]
marker_sample_start_walking = event_samples[event_types == start_walking][0]

marker_time_standing = marker_sample_start_standing / sfreq
marker_time_walking = marker_sample_start_walking / sfreq

n_annotations = 30
spacing = 2 

def create_annotations(timepoint, label):
    onsets = np.array([timepoint + i * spacing for i in range(n_annotations)])
    durations = np.zeros(n_annotations) 
    descriptions = [label] * n_annotations
    return mne.Annotations(onset=onsets, duration=durations, description=descriptions)

annotations_standing = create_annotations(marker_time_standing, 'Standing')
annotations_walking = create_annotations(marker_time_walking, 'Walking')

combined_annotations = annotations_standing + annotations_walking

raw.set_annotations(combined_annotations)

events, event_id = mne.events_from_annotations(raw)

tmin = 0.0
tmax = 1.5 

epochs = mne.Epochs(raw, 
                        events,
                        event_id,
                        tmin=tmin,
                        tmax=tmax,
                        baseline=None,
                        preload=True,
                        picks='eeg')

```

Until here everything works fine.

```python

X = [epochs[event_name].get_data(copy=False) for event_name in event_id]
X = [np.transpose(x, (0, 2, 1)) for x in X]

adjacency, ch_names = find_ch_adjacency(epochs.info, ch_type="eeg")
mne.viz.plot_ch_adjacency(epochs.info, adjacency, ch_names, kind="3d")

alpha_cluster_forming = 0.05
tail = 1

n_conditions = len(event_id)
n_observations = len(X[0])
dfn = n_conditions - 1
dfd = n_observations - n_conditions

f_thresh = scipy.stats.f.ppf(1 - alpha_cluster_forming, dfn=dfn, dfd=dfd)

cluster_stats = spatio_temporal_cluster_test(
    X,
    n_permutations=1000,
    threshold=f_thresh,
    tail=tail,
    n_jobs=None,
    buffer_size=None,
    adjacency=adjacency,
)
F_obs, clusters, p_values, _ = cluster_stats

```

X is a list, containing two arrays with a size of 30, 751, 65. Looking fine and being in line with the documentation. Adjacency also looks regular.

The permutations are done, and everything seems to be working. I am finding 377 clusters. But I’m puzzled by the p-values. They are consistently either 1 or very close to 1 (e.g., 0.999). I’m new to this field of data analysis, but I would expect some differences between the standing and walking conditions. I have experimented with various values regarding thresholds, number of permutations, one-sided vs. two-sided tails, different `tmin` and `tmax` settings for the epochs and varying the number of epochs, but still no significant p-values.

Where could I have gone wrong, or what might I be missing?

Thank you! 🙂

Cheers,  
Tim

---

<div class="post-metadata">

**Author:** ![wmvanvliet](https://yyz2.discourse-cdn.com/free1/user_avatar/mne.discourse.group/wmvanvliet/32/100_2.png) [@wmvanvliet](https://mne.discourse.group/u/wmvanvliet)\
**Post date:** [March 19, 2025, 3:38pm UTC](https://mne.discourse.group/t/spatiotemporal-permutation-f-test-no-sign-clusters-found/10974/2 "2025-03-19T15:38:59Z")

</div>

The way to proceed is to plot the raw f-values. If you can somehow get a matrix of size (channels x times) filled with the f-values across your conditions, you can load it into an [`EvokedArray`](https://mne.tools/stable/generated/mne.EvokedArray.html) object and plot it:

```python
fvalues = scipy.stats.f_oneway(X) # check that is (channels x times)
f_evoked = mne.EvokedArray(fvalues, info=epochs.info, tmin=epochs.times[0])
f_evoked.plot_topo()

```

…and see if these f-values makes sense to you: high values where you indeed expect differences and low value here you don’t expect any differences.

---

<div class="post-metadata">

**Author:** ![TimteTim](https://avatars.discourse-cdn.com/v4/letter/t/50afbb/32.png) [@TimteTim](https://mne.discourse.group/u/TimteTim)\
**Post date:** [April 2, 2025, 2:05pm UTC](https://mne.discourse.group/t/spatiotemporal-permutation-f-test-no-sign-clusters-found/10974/3 "2025-04-02T14:05:59Z")

</div>

Dear Marijn,

thank you for your reply and sorry for my late response.  
I did check the raw f-values as you mentioned.

```python
fvalues = scipy.stats.f_oneway(*X)
X_reshaped = [x.transpose(0, 2, 1) for x in X] # Now (epochs, channels, timepoints)
fvalues = np.array([scipy.stats.f_oneway(*[X_reshaped[c][:, ch, :] for c in range(len(X))])[0]
                    for ch in range(X_reshaped[0].shape[1])])

f_evoked = mne.EvokedArray(fvalues, info=epochs.info, tmin=epochs.times[0])
f_evoked.plot_topo()

```

The f-values are looking quiet similiar and I would expect higher values in central regions.  
Nevertheless, if I take a look at critical F-values:

```python
f_threshold = scipy.stats.f.ppf(0.95, df_between, df_within)
print(f"F-value threshold for p < 0.05: {f_threshold}")

```

I do find several. However, not in the regions I would expect them to be.

I now tried to align the ‘Walking’ annotation to the heel strike. This at least led to significant clusters being found that would make sense. Still have to figure out, if this is only driven by artefacts. But atleast it worked somehow :-).
