Repository: mne-tools/mne-python

Issue:
ENH: speed up ica.plot_properties
I currently have to wait some time after clicking a component in `ica.plot_components` window and the time seems to be mostly from waiting for the multitaper psd estimation to complete. I think that we should use something much simpler like welch or even fft as the default. The plotted spectrum is for informational reasons, not for analysis. I can compare timings on one of my datasets.


Discussion:

Resolving patch:
diff --git a/mne/stats/parametric.py b/mne/stats/parametric.py
--- a/mne/stats/parametric.py
+++ b/mne/stats/parametric.py
@@ -383,10 +383,4 @@ def _parametric_ci(arr, ci=.95):
         return mean, sigma
     from scipy import stats
     sigma = stats.sem(arr, 0)
-    # This is highly convoluted to support 17th century Scipy
-    # XXX Fix when Scipy 0.12 support is dropped!
-    # then it becomes just:
-    # return stats.t.interval(ci, loc=mean, scale=sigma, df=arr.shape[0])
-    return np.asarray([stats.t.interval(ci, arr.shape[0],
-                       loc=mean_, scale=sigma_)
-                       for mean_, sigma_ in zip(mean, sigma)]).T
+    return stats.t.interval(ci, loc=mean, scale=sigma, df=arr.shape[0])
diff --git a/mne/viz/evoked.py b/mne/viz/evoked.py
--- a/mne/viz/evoked.py
+++ b/mne/viz/evoked.py
@@ -1828,7 +1828,7 @@ def _get_data_and_ci(evoked, combine, combine_func, picks, scaling=1,
     return (data,) if ci_fun is None else (data, ci)
 
 
-def _get_ci_function_pce(ci):
+def _get_ci_function_pce(ci, do_topo=False):
     """Get confidence interval function for plot_compare_evokeds."""
     if ci is None:
         return None
@@ -1840,7 +1840,8 @@ def _get_ci_function_pce(ci):
         ci = 0.95
     if isinstance(ci, float):
         from ..stats import _ci
-        return partial(_ci, ci=ci, method='bootstrap')
+        method = 'parametric' if do_topo else 'bootstrap'
+        return partial(_ci, ci=ci, method=method)
     else:
         raise TypeError('"ci" must be None, bool, float or callable, got {}'
                         .format(type(ci).__name__))
@@ -1967,7 +1968,8 @@ def plot_compare_evokeds(evokeds, picks=None, gfp=None, colors=None,
     ci : float | bool | callable | None
         Confidence band around each ERP/F time series. If ``False`` or ``None``
         no confidence band is drawn. If :class:`float`, ``ci`` must be between
-        0 and 1, and will set the threshold for a bootstrap estimation of the
+        0 and 1, and will set the threshold for a bootstrap
+        (single plot)/parametric (when ``axes=='topo'``)  estimation of the
         confidence band; ``True`` is equivalent to setting a threshold of 0.95
         (i.e., the 95%% confidence band is drawn). If a callable, it must take
         a single array (n_observations × n_times) as input and return upper and
@@ -2274,7 +2276,7 @@ def click_func(
         for cond in conditions:
             this_evokeds = evokeds[cond]
             # skip CIs when possible; assign ci_fun first to get arg checking
-            ci_fun = _get_ci_function_pce(ci)
+            ci_fun = _get_ci_function_pce(ci, do_topo=do_topo)
             ci_fun = ci_fun if len(this_evokeds) > 1 else None
             res = _get_data_and_ci(this_evokeds, combine, c_func, picks=_picks,
                                    scaling=scalings, ci_fun=ci_fun)
diff --git a/mne/viz/ica.py b/mne/viz/ica.py
--- a/mne/viz/ica.py
+++ b/mne/viz/ica.py
@@ -280,10 +280,15 @@ def plot_ica_properties(ica, inst, picks=None, axes=None, dB=True,
     dB: bool
         Whether to plot spectrum in dB. Defaults to True.
     plot_std: bool | float
-        Whether to plot standard deviation in ERP/ERF and spectrum plots.
-        Defaults to True, which plots one standard deviation above/below.
-        If set to float allows to control how many standard deviations are
-        plotted. For example 2.5 will plot 2.5 standard deviation above/below.
+        Whether to plot standard deviation/confidence intervals in ERP/ERF and
+        spectrum plots.
+        Defaults to True, which plots one standard deviation above/below for
+        the spectrum. If set to float allows to control how many standard
+        deviations are plotted for the spectrum. For example 2.5 will plot 2.5
+        standard deviation above/below.
+        For the ERP/ERF, by default, plot the 95 percent parametric confidence
+        interval is calculated. To change this, use ``ci`` in ``ts_args`` in
+        ``image_args`` (see below).
     topomap_args : dict | None
         Dictionary of arguments to ``plot_topomap``. If None, doesn't pass any
         additional arguments. Defaults to None.
@@ -344,10 +349,17 @@ def plot_ica_properties(ica, inst, picks=None, axes=None, dB=True,
         from .utils import _validate_if_list_of_axes
         _validate_if_list_of_axes(axes, obligatory_len=5)
         fig = axes[0].get_figure()
+
     psd_args = dict() if psd_args is None else psd_args
     topomap_args = dict() if topomap_args is None else topomap_args
     image_args = dict() if image_args is None else image_args
     image_args["ts_args"] = dict(truncate_xaxis=False, show_sensors=False)
+    if plot_std:
+        from ..stats.parametric import _parametric_ci
+        image_args["ts_args"]["ci"] = _parametric_ci
+    elif "ts_args" not in image_args or "ci" not in image_args["ts_args"]:
+        image_args["ts_args"]["ci"] = False
+
     for item_name, item in (("psd_args", psd_args),
                             ("topomap_args", topomap_args),
                             ("image_args", image_args)):


Test patch:
diff --git a/mne/viz/tests/test_evoked.py b/mne/viz/tests/test_evoked.py
--- a/mne/viz/tests/test_evoked.py
+++ b/mne/viz/tests/test_evoked.py
@@ -26,6 +26,7 @@
 from mne.viz.utils import _fake_click
 from mne.datasets import testing
 from mne.io.constants import FIFF
+from mne.stats.parametric import _parametric_ci
 
 base_dir = op.join(op.dirname(__file__), '..', '..', 'io', 'tests', 'data')
 evoked_fname = op.join(base_dir, 'test-ave.fif')
@@ -323,8 +324,10 @@ def test_plot_compare_evokeds():
         assert len(fig.axes[0].lines) == len(evoked_dict)
     # old tests
     red.info['chs'][0]['loc'][:2] = 0  # test plotting channel at zero
-    plot_compare_evokeds(red, picks=[0],
+    plot_compare_evokeds([red, blue], picks=[0],
                          ci=lambda x: [x.std(axis=0), -x.std(axis=0)])
+    plot_compare_evokeds([list(evoked_dict.values())], picks=[0],
+                         ci=_parametric_ci)
     # smoke test for tmin >= 0 (from mailing list)
     red.crop(0.01, None)
     assert len(red.times) > 2