Repository: mne-tools/mne-python

Issue:
speed up iter_evoked?
I (mis)use epochs.iter_evokeds for confidence intervals from plot_compare_evokeds a lot. That is really slow. Is there some trivial way for speeding up iter_evokeds? (Instead of doing the sensible thing and speeding up plot_compare_evokeds itself ...)

I don't see one, it seems the problem is it's calling Epochs.__next__ and creating 100s of Evokeds via EvokedArray, which is simply inherently slow.
speed up iter_evoked?
I (mis)use epochs.iter_evokeds for confidence intervals from plot_compare_evokeds a lot. That is really slow. Is there some trivial way for speeding up iter_evokeds? (Instead of doing the sensible thing and speeding up plot_compare_evokeds itself ...)

I don't see one, it seems the problem is it's calling Epochs.__next__ and creating 100s of Evokeds via EvokedArray, which is simply inherently slow.


Discussion:
I don't know how `iter_evokeds` works exactly but I assume it could create the Evoked object only once and only change the `.data` then (if it doesn't do this already).
it's very possible it does a copy of the info which can take time. one
option would be to add a parameter to iter_evokeds method to avoid as many
copies as possible

Thanks, might be worth doing. I will self assign, although this is low priority I think because I'm abusing things here.
I don't know how `iter_evokeds` works exactly but I assume it could create the Evoked object only once and only change the `.data` then (if it doesn't do this already).
it's very possible it does a copy of the info which can take time. one
option would be to add a parameter to iter_evokeds method to avoid as many
copies as possible

Thanks, might be worth doing. I will self assign, although this is low priority I think because I'm abusing things here.

Resolving patch:
diff --git a/mne/epochs.py b/mne/epochs.py
--- a/mne/epochs.py
+++ b/mne/epochs.py
@@ -786,13 +786,19 @@ def _detrend_offset_decim(self, epoch, verbose=None):
         epoch = epoch[:, self._decim_slice]
         return epoch
 
-    def iter_evoked(self):
+    def iter_evoked(self, copy=False):
         """Iterate over epochs as a sequence of Evoked objects.
 
         The Evoked objects yielded will each contain a single epoch (i.e., no
         averaging is performed).
 
         This method resets the object iteration state to the first epoch.
+
+        Parameters
+        ----------
+        copy : bool
+            If False copies of data and measurement info will be omitted
+            to save time.
         """
         self._current = 0
 
@@ -803,7 +809,10 @@ def iter_evoked(self):
                 break
             data, event_id = out
             tmin = self.times[0]
-            info = deepcopy(self.info)
+            info = self.info
+            if copy:
+                info = deepcopy(self.info)
+                data = data.copy()
 
             yield EvokedArray(data, info, tmin, comment=str(event_id))
 
diff --git a/mne/viz/epochs.py b/mne/viz/epochs.py
--- a/mne/viz/epochs.py
+++ b/mne/viz/epochs.py
@@ -544,7 +544,7 @@ def _plot_epochs_image(image, style_axes=True, epochs=None, picks=None,
         from . import plot_compare_evokeds
         pass_combine = (combine if combine_given else None)
         _picks = [0] if len(picks) == 1 else None  # prevent applying GFP
-        plot_compare_evokeds({'cond': list(epochs.iter_evoked())},
+        plot_compare_evokeds({'cond': list(epochs.iter_evoked(copy=False))},
                              picks=_picks, axes=ax['evoked'],
                              combine=pass_combine, **ts_args)
         ax['evoked'].set_xlim(tmin, tmax)  # don't multiply by 1e3 here


Test patch: