Repository: mne-tools/mne-python

Issue:
Adding overlap keyword to make_fixed_length_epochs
#### Describe the new feature or enhancement
I am trying to use time-frequency analysis that is present in mne without converting to arrays first. There is no way to do this using the ``Raw`` object, and one must convert to ``Epochs``, with each epoch "representing" the window that will have tfr methods applied. E.g. I want to compute the multitaper FFT, and/or morlet wavelet transform to get an ``AverageTfr`` object for multiple frequency bands, alpha, beta, gamma, etc.

Normally, one would like some overlap of these windows. For example, if you do multitpaer FFT, then you usually use a sliding window with some overlap (e.g. 1 sec window with 0.5 sec step).

In https://mne.tools/stable/generated/mne.make_fixed_length_events.html#mne.make_fixed_length_events
there is an overlap keyword.

However, in `make_fixed_legnth_epochs` there is not. 
https://mne.tools/stable/generated/mne.make_fixed_length_epochs.html#mne.make_fixed_length_epochs

#### Describe your proposed implementation
Is it possible to add the `overlap` keyword argument here?


#### Describe possible alternatives
I'm still not quite sure what the optimal way to apply tfr analysis to a Raw object. Obviously one can always convert to arrays, but then they lose the structure present in the mne data structures. I would prefer staying with the data structures mne has (e.g. Epochs for TFR). If what I said up there is not the optimal way to construct TFR then please let me know.

#### Additional comments
I can update an existing example to show this functionality off if needed.



Discussion:
ok to add overlap param to make_fixed_length_epochs 

yet I am not sure what you aim to obtain for TFR on raw. You want a spectrogram?
Yep I'm essentially after a spectrogram.
one idea now we refactored the raw.plot would be to add plot of spectrogram
in each "horizontal" band of the plot.

I've seen this in certain software for sleep data.

did you try scipy.signal.spectrogram?

>

> one idea now we refactored the raw.plot would be to add plot of spectrogram in each "horizontal" band of the plot. 
This sounds interesting to me. Would you elaborate what the "horizontal band" mean? like a frequency band?

And do you mean we could add a compute_spectrogram function for `Raw`, where we can specify say a frequency band, and/or a list of frequencies with an `average` kwarg?

> I've seen this in certain software for sleep data. did you try scipy.signal.spectrogram?
Nope haven't tried this approach yet, since mne has the `tfr` functions that operate on arrays. I feel like the scipy spectrogram is a bit more low level and I generally do tfr analysis as a benchmark (and prefer not to have to think as much :p), so I like going pure mne API. 




my concern is that TFRs are often bigger than the initial raw data (one
signal gives an image),
so it makes sense to compute it on the fly when you need and do not store
it to disk.
A TFR for 300 MEG channels for 6 mins of sample data would be huge.

>

> my concern is that TFRs are often bigger than the initial raw data (one signal gives an image), so it makes sense to compute it on the fly when you need and do not store it to disk. A TFR for 300 MEG channels for 6 mins of sample data would be huge.
> […](#)

I agree storing the full (ch, freqs, time) array would be huge, but in many cases, one might jsut want (ch, time) for a certain frequency band, so for example, I want spectrograms for my iEEG `Raw` object for delta, theta, alpha, beta, gamma, highgamma frequency bands. Since I do post-hoc analyses, I want to then save these at least. (this would be similar in size to the original Raw object, since you're "combining" the power across the frequency axis). 

The combination scheme can be "mean", or "median" for example, or more generally a `func` (maybe one is interested in the quantile, or min, or max). 

Overall, I think the general use-case of getting one of these averaged spectrogram directly from ``Raw`` is very useful without doing roundabouts like going to array, or going to Epochs/Evoked.

Is the idea of computing a spectrogram directly from ``Raw`` even feasible rn? 
try to cook something for your needs and share it when it does the job for
you.

then we'll see what to consider for inclusion in mne

>

👨‍💻
I am working on this

Resolving patch:
diff --git a/mne/epochs.py b/mne/epochs.py
--- a/mne/epochs.py
+++ b/mne/epochs.py
@@ -3668,7 +3668,7 @@ def average_movements(epochs, head_pos=None, orig_sfreq=None, picks=None,
 
 @verbose
 def make_fixed_length_epochs(raw, duration=1., preload=False,
-                             reject_by_annotation=True, proj=True,
+                             reject_by_annotation=True, proj=True, overlap=0.,
                              verbose=None):
     """Divide continuous raw data into equal-sized consecutive epochs.
 
@@ -3685,6 +3685,11 @@ def make_fixed_length_epochs(raw, duration=1., preload=False,
     %(proj_epochs)s
 
         .. versionadded:: 0.22.0
+    overlap : float
+        The overlap between epochs, in seconds. Must be
+        ``0 <= overlap < duration``. Default is 0, i.e., no overlap.
+
+        .. versionadded:: 0.23.0
     %(verbose)s
 
     Returns
@@ -3696,7 +3701,8 @@ def make_fixed_length_epochs(raw, duration=1., preload=False,
     -----
     .. versionadded:: 0.20
     """
-    events = make_fixed_length_events(raw, 1, duration=duration)
+    events = make_fixed_length_events(raw, 1, duration=duration,
+                                      overlap=overlap)
     delta = 1. / raw.info['sfreq']
     return Epochs(raw, events, event_id=[1], tmin=0, tmax=duration - delta,
                   baseline=None, preload=preload,


Test patch:
diff --git a/mne/tests/test_epochs.py b/mne/tests/test_epochs.py
--- a/mne/tests/test_epochs.py
+++ b/mne/tests/test_epochs.py
@@ -3254,6 +3254,18 @@ def test_make_fixed_length_epochs():
     assert len(epochs_annot) > 10
     assert len(epochs) > len(epochs_annot)
 
+    # overlaps
+    epochs = make_fixed_length_epochs(raw, duration=1)
+    assert len(epochs.events) > 10
+    epochs_ol = make_fixed_length_epochs(raw, duration=1, overlap=0.5)
+    assert len(epochs_ol.events) > 20
+    epochs_ol_2 = make_fixed_length_epochs(raw, duration=1, overlap=0.9)
+    assert len(epochs_ol_2.events) > 100
+    assert_array_equal(epochs_ol_2.events[:, 0],
+                       np.unique(epochs_ol_2.events[:, 0]))
+    with pytest.raises(ValueError, match='overlap must be'):
+        make_fixed_length_epochs(raw, duration=1, overlap=1.1)
+
 
 def test_epochs_huge_events(tmpdir):
     """Test epochs with event numbers that are too large."""