Repository: mne-tools/mne-python

Issue:
Remove n_pca_components from ICA.__init__
Following up the changes in #8351, I noted that because `n_pca_components` is only used in `ICA.apply` it should be removed from `ICA.__init__`. This would make ICA usage a lot easier and clearer, because right now one of the questions I frequently need to answer is about the two parameters `n_components` and `n_pca_components`. I'd prefer to have only `n_components` in `ICA.__init__` and `n_pca_components` only in `ICA.apply`. @hoechenberger @larsoner @agramfort 


Discussion:
x-ref https://github.com/mne-tools/mne-python/issues/8337#issuecomment-703244103
> I noted that because `n_pca_components` is only used in `ICA.apply` it should be removed from `ICA.__init__`. This would make ICA usage a lot easier and clearer

I don't feel strongly here, but if you believe by removing the param from `__init__()` we can make MNE easier to use, I'm +1 for it!
@cbrnr did you look at the updated docs for these parameters in the PR?

https://22659-1301584-gh.circle-artifacts.com/0/dev/generated/mne.preprocessing.ICA.html#mne.preprocessing.ICA

I tried to make it clearer that `n_pca_components` in `__init__` is really now just a *default* PCA reconstruction value. See the link @hoechenberger posted above for some rationale, but the TL;DR is that keeping it the way it is after #8351 allows you to set a "default" amount of PCA denoising. I can live with it either way...
> I tried to make it clearer that n_pca_components in __init__ is really now just a default PCA reconstruction value. See the link @hoechenberger posted above for some rationale, but the TL;DR is that keeping it the way it is after #8351 allows you to set a "default" amount of PCA denoising. I can live with it either way...

Yes, I saw that, and it's definitely clearer than before. However, many users don't read the whole docstring (even though they should, but that's my point), so not having this parameter would benefit usability. And BTW, having this parameter in `__init__` to provide a default is also not a good argument, because we already have that default directly in `apply`.
> And BTW, having this parameter in __init__ to provide a default is also not a good argument, because we already have that default directly in apply.

It sounds like you're talking about the default value of the `n_pca_components` being the same (`None`) in `__init__` and `apply`? That's not quite the idea. The point is if the user wants to change it from this `None` default to some other default for their apply operations for their instance. For example if you have 10 channels and do:
```
ica = ICA(n_pca_components=8)
```
Then when you do `ica.apply(raw)` (even with a save-load round trip of the ICA instance in between) it will use 8 components for this operation because there was `n_pca_components=8` in the `__init__`, unless you override this instance's default like `ica.appy(raw, n_pca_components=9)` or whatever. This is the sense in which it "provides a default".

Make more sense?
@larsoner I get the idea, but I don't see why providing this in `__init__` is useful. It seems that if users wanted e.g. `n_pca_components=8` in all subsequent `apply` calls all this does is save a few characters, because they can use `.apply()` instead of `.apply(n_pca_components=8)`, right? Usually, I'd apply only once anyway, but even if I wanted to play around with some values I think that a clearer API (i.e. no `n_pca_components` arg in `__init__`) would be worth the extra characters in repeated `apply` calls.

@hoechenberger I didn't have any recent coffee and it's too late for today, so I'm not sure how caffeine would change my view on this 🤣 .
@cbrnr never mind, I deleted this comment again, as it was posted under the influence of transient caffeine intoxication 😅💩

Resolving patch:
diff --git a/mne/preprocessing/ica.py b/mne/preprocessing/ica.py
--- a/mne/preprocessing/ica.py
+++ b/mne/preprocessing/ica.py
@@ -157,10 +157,10 @@ class ICA(ContainsMixin):
             requested threshold of 80%% explained variance can be exceeded. The
             third component, on the other hand, would be excluded.
         - ``None``
-            ``n_pca_components`` or ``0.999999`` will be used, whichever
-            results in fewer components. This is done to avoid numerical
-            stability problems when whitening, particularly when working
-            with rank-deficient data.
+            ``n_pca_components`` (deprecated) or ``0.999999`` (will become the
+            default in 0.23) will be used, whichever results in fewer
+            components. This is done to avoid numerical stability problems when
+            whitening, particularly when working with rank-deficient data.
 
         Defaults to ``None``. The actual number used when executing the
         :meth:`ICA.fit` method will be stored in the attribute
@@ -172,24 +172,11 @@ class ICA(ContainsMixin):
            equal to* it. The default (None) will also take into account the
            rank deficiency of the data.
     max_pca_components : int | None
-        This parameter is deprecated and will be removed in 0.23. Use
-        ``n_pca_components`` instead.
+        This parameter is deprecated and will be removed in 0.23. Use the
+        ``n_pca_components`` parameter in :meth:`apply` instead.
     n_pca_components : int | float | None
-        The default total number of components (ICA + PCA) used for signal
-        reconstruction in :meth:`ICA.apply`. At minimum, at least
-        ``n_components`` must be
-        used (unless modified by ``ICA.include`` or ``ICA.exclude``). If
-        ``n_pca_components > n_components``, additional PCA components will be
-        incorporated. If :class:`float` between 0 and 1, the number is chosen
-        as the number of components with cumulative explained variance in
-        the original data If :class:`int` or :class:`float`,
-        ``n_components_ ≤ n_pca_components`` must hold.
-        If ``None``, all components (i.e., the number of channels) will be
-        used. Defaults to ``None``.
-
-        The value provided during class construction serves as a default value.
-        Different values can be provided in the :meth:`apply` method to test
-        different levels of PCA-based denoising.
+        This parameter is deprecated and will be removed in 0.23. Use the
+        ``n_pca_components`` parameter in :meth:`apply` instead.
 
         .. versionchanged:: 0.22
            For a :class:`python:float`, the number of components will account
@@ -314,10 +301,10 @@ class ICA(ContainsMixin):
     rank of the reconstructed data to 40, which is typically undesirable.
 
     If you are migrating from EEGLAB and intend to reduce dimensionality via
-    PCA, similarly to EEGLAB's ``runica(..., 'pca', n)`` functionality, simply
-    pass ``n_pca_components=n``, while leaving ``n_components`` at its default
-    value (None). The resulting reconstructed data after :meth:`apply` will
-    have rank ``n``.
+    PCA, similarly to EEGLAB's ``runica(..., 'pca', n)`` functionality,
+    pass ``n_components=n`` during initialization and then
+    ``n_pca_components=n`` during :meth:`apply`. The resulting reconstructed
+    data after :meth:`apply` will have rank ``n``.
 
     .. note:: Commonly used for reasons of i) computational efficiency and
               ii) additional noise reduction, it is a matter of current debate
@@ -431,6 +418,9 @@ def __init__(self, n_components=None, *, max_pca_components=None,
         self.n_pca_components = n_pca_components
         self.ch_names = None
         self.random_state = random_state
+        if n_pca_components is not None:
+            warn('n_pca_components is deprecated and will be removed in 0.23, '
+                 'use it in apply() instead', DeprecationWarning)
 
         if fit_params is None:
             fit_params = {}
@@ -2370,6 +2360,7 @@ def read_ica(fname, verbose=None):
     fid.close()
 
     ica_init, ica_misc = [_deserialize(k) for k in (ica_init, ica_misc)]
+    n_pca_components = ica_init.pop('n_pca_components')
     current_fit = ica_init.pop('current_fit')
     max_pca_components = ica_init.pop('max_pca_components')
     method = ica_misc.get('method', 'fastica')
@@ -2389,6 +2380,10 @@ def f(x):
     ica = ICA(**ica_init)
     ica.current_fit = current_fit
     ica.ch_names = ch_names.split(':')
+    if n_pca_components is not None and \
+            not isinstance(n_pca_components, int_like):
+        n_pca_components = np.float64(n_pca_components)
+    ica.n_pca_components = n_pca_components
     ica.pre_whitener_ = f(pre_whitener)
     ica.pca_mean_ = f(pca_mean)
     ica.pca_components_ = f(pca_components)
diff --git a/mne/utils/docs.py b/mne/utils/docs.py
--- a/mne/utils/docs.py
+++ b/mne/utils/docs.py
@@ -713,7 +713,8 @@
 n_pca_components : int | float | None
     The number of PCA components to be kept, either absolute (int)
     or fraction of the explained variance (float). If None (default),
-    the ``ica.n_pca_components`` from initialization will be used.
+    the ``ica.n_pca_components`` from initialization will be used in 0.22;
+    in 0.23 all components will be used.
 """
 
 # Maxwell filtering
diff --git a/tutorials/preprocessing/plot_40_artifact_correction_ica.py b/tutorials/preprocessing/plot_40_artifact_correction_ica.py
--- a/tutorials/preprocessing/plot_40_artifact_correction_ica.py
+++ b/tutorials/preprocessing/plot_40_artifact_correction_ica.py
@@ -78,14 +78,15 @@
 #     PCs are sent to the ICA algorithm (yielding 50 ICs), and during
 #     reconstruction :meth:`~mne.preprocessing.ICA.apply` will use the 50 ICs
 #     plus PCs number 51-300 (the full PCA residual). If instead you specify
-#     ``n_pca_components=120`` then :meth:`~mne.preprocessing.ICA.apply` will
+#     ``n_pca_components=120`` in :meth:`~mne.preprocessing.ICA.apply`, it will
 #     reconstruct using the 50 ICs plus the first 70 PCs in the PCA residual
 #     (numbers 51-120), thus discarding the smallest 180 components.
 #
 #     **If you have previously been using EEGLAB**'s ``runica()`` and are
 #     looking for the equivalent of its ``'pca', n`` option to reduce
-#     dimensionality via PCA before the ICA step, set ``n_pca_components=n``,
-#     while leaving ``n_components`` at its default (i.e., ``None``).
+#     dimensionality via PCA before the ICA step, set ``n_components=n``
+#     during initialization and pass ``n_pca_components=n`` to
+#     :meth:`~mne.preprocessing.ICA.apply`.
 #
 # MNE-Python implements three different ICA algorithms: ``fastica`` (the
 # default), ``picard``, and ``infomax``. FastICA and Infomax are both in fairly
@@ -120,9 +121,11 @@
 # 2. The pre-whitened data are then decomposed using PCA.
 #
 # From the resulting principal components (PCs), the first ``n_components`` are
-# then passed to the ICA algorithm. ``n_components`` may be an integer number
-# of components to use, or a fraction of explained variance that the
-# ``n_pca_components`` components capture.
+# then passed to the ICA algorithm if ``n_components`` is an integer number.
+# It can also be a float between 0 and 1, specifying the **fraction** of
+# explained variance that the PCs should capture; the appropriate number of
+# PCs (i.e., just as many PCs as are required to explain the given fraction
+# of total variance) is then passed to the ICA.
 #
 # After visualizing the Independent Components (ICs) and excluding any that
 # capture artifacts you want to repair, the sensor signal can be reconstructed


Test patch:
diff --git a/mne/preprocessing/tests/test_ica.py b/mne/preprocessing/tests/test_ica.py
--- a/mne/preprocessing/tests/test_ica.py
+++ b/mne/preprocessing/tests/test_ica.py
@@ -93,13 +93,13 @@ def test_ica_full_data_recovery(method):
         stuff = [(2, n_channels, True), (2, n_channels // 2, False)]
         for n_components, n_pca_components, ok in stuff:
             ica = ICA(n_components=n_components, random_state=0,
-                      n_pca_components=n_pca_components,
                       method=method, max_iter=1)
+            kwargs = dict(exclude=[], n_pca_components=n_pca_components)
             picks = list(range(n_channels))
             with pytest.warns(UserWarning, match=None):  # sometimes warns
                 ica.fit(raw, picks=picks)
             _assert_ica_attributes(ica, raw.get_data(picks))
-            raw2 = ica.apply(raw.copy(), exclude=[])
+            raw2 = ica.apply(raw.copy(), **kwargs)
             if ok:
                 assert_allclose(data[:n_channels], raw2._data[:n_channels],
                                 rtol=1e-10, atol=1e-15)
@@ -108,11 +108,11 @@ def test_ica_full_data_recovery(method):
                 assert (np.max(diff) > 1e-14)
 
             ica = ICA(n_components=n_components, method=method,
-                      n_pca_components=n_pca_components, random_state=0)
+                      random_state=0)
             with pytest.warns(None):  # sometimes warns
                 ica.fit(epochs, picks=picks)
             _assert_ica_attributes(ica, epochs.get_data(picks))
-            epochs2 = ica.apply(epochs.copy(), exclude=[])
+            epochs2 = ica.apply(epochs.copy(), **kwargs)
             data2 = epochs2.get_data()[:, :n_channels]
             if ok:
                 assert_allclose(data_epochs[:, :n_channels], data2,
@@ -121,7 +121,7 @@ def test_ica_full_data_recovery(method):
                 diff = np.abs(data_epochs[:, :n_channels] - data2)
                 assert (np.max(diff) > 1e-14)
 
-            evoked2 = ica.apply(evoked.copy(), exclude=[])
+            evoked2 = ica.apply(evoked.copy(), **kwargs)
             data2 = evoked2.data[:n_channels]
             if ok:
                 assert_allclose(data_evoked[:n_channels], data2,
@@ -179,7 +179,8 @@ def test_ica_noop(n_components, n_pca_components, tmpdir):
         with pytest.raises(ValueError, match='n_components.*must be smalle.*'):
             ICA(**kwargs)
         return
-    ica = ICA(**kwargs)
+    with pytest.deprecated_call():
+        ica = ICA(**kwargs)
     if n_components == 10 and n_pca_components == 0.9999:
         with pytest.raises(RuntimeError, match='.*requires.*PCA.*'):
             ica.fit(raw)
@@ -318,7 +319,7 @@ def test_ica_projs(n_pca_components, proj, cov, meg, eeg):
         noise_cov = None
     # infomax here just so we don't require sklearn
     ica = ICA(max_iter=1, noise_cov=noise_cov, method='infomax',
-              n_pca_components=n_pca_components, n_components=10)
+              n_components=10)
     with pytest.warns(None):  # convergence
         ica.fit(raw_fit)
     if cov:
@@ -326,7 +327,8 @@ def test_ica_projs(n_pca_components, proj, cov, meg, eeg):
     else:
         assert ica.pre_whitener_.shape == (len(raw.ch_names), 1)
     with catch_logging() as log:
-        raw_apply = ica.apply(raw_fit.copy(), verbose=True)
+        raw_apply = ica.apply(
+            raw_fit.copy(), n_pca_components=n_pca_components, verbose=True)
     log = log.getvalue()
     print(log)  # very useful for debugging, might as well leave it in
     if proj:
@@ -407,83 +409,82 @@ def test_ica_core(method, n_components, noise_cov, n_pca_components):
         ICA(n_components=2.3, n_pca_components=3)
 
     # test essential core functionality
-    for _ in range(1):  # just to avoid a bad diff
-        # Test ICA raw
-        ica = ICA(noise_cov=noise_cov, n_components=n_components,
-                  n_pca_components=n_pca_components, method=method, max_iter=1)
-        with pytest.raises(ValueError, match='Cannot check for channels of t'):
-            'meg' in ica
-
-        print(ica)  # to test repr
-
-        # test fit checker
-        with pytest.raises(RuntimeError, match='No fit available'):
-            ica.get_sources(raw)
-        with pytest.raises(RuntimeError, match='No fit available'):
-            ica.get_sources(epochs)
-
-        # Test error upon empty epochs fitting
-        with pytest.raises(RuntimeError, match='none were found'):
-            ica.fit(epochs[0:0])
-
-        # test decomposition
-        with pytest.warns(UserWarning, match='did not converge'):
-            ica.fit(raw)
-        repr(ica)  # to test repr
-        assert ('mag' in ica)  # should now work without error
 
-        # test re-fit
-        unmixing1 = ica.unmixing_matrix_
-        with pytest.warns(UserWarning, match='did not converge'):
-            ica.fit(raw)
-        assert_array_almost_equal(unmixing1, ica.unmixing_matrix_)
-
-        raw_sources = ica.get_sources(raw)
-        # test for #3804
-        assert_equal(raw_sources._filenames, [None])
-        print(raw_sources)
-
-        # test for gh-6271 (scaling of ICA traces)
-        fig = raw_sources.plot()
-        assert len(fig.axes[0].lines) in (5, 9)
-        for line in fig.axes[0].lines:
-            y = line.get_ydata()
-            if len(y) > 2:  # actual data, not markers
-                assert np.ptp(y) < 15
-        plt.close('all')
-
-        sources = raw_sources[:, :][0]
-        assert (sources.shape[0] == ica.n_components_)
-
-        # test preload filter
-        raw3 = raw.copy()
-        raw3.preload = False
-        pytest.raises(RuntimeError, ica.apply, raw3,
-                      include=[1, 2])
-
-        #######################################################################
-        # test epochs decomposition
-        ica = ICA(noise_cov=noise_cov, n_components=n_components,
-                  n_pca_components=n_pca_components, method=method)
-        with pytest.warns(None):  # sometimes warns
-            ica.fit(epochs)
-        _assert_ica_attributes(ica, epochs.get_data(), limits=(0.2, 20))
-        data = epochs.get_data()[:, 0, :]
-        n_samples = np.prod(data.shape)
-        assert_equal(ica.n_samples_, n_samples)
-        print(ica)  # to test repr
+    # Test ICA raw
+    ica = ICA(noise_cov=noise_cov, n_components=n_components,
+              method=method, max_iter=1)
+    with pytest.raises(ValueError, match='Cannot check for channels of t'):
+        'meg' in ica
 
-        sources = ica.get_sources(epochs).get_data()
-        assert (sources.shape[1] == ica.n_components_)
+    print(ica)  # to test repr
+
+    # test fit checker
+    with pytest.raises(RuntimeError, match='No fit available'):
+        ica.get_sources(raw)
+    with pytest.raises(RuntimeError, match='No fit available'):
+        ica.get_sources(epochs)
+
+    # Test error upon empty epochs fitting
+    with pytest.raises(RuntimeError, match='none were found'):
+        ica.fit(epochs[0:0])
+
+    # test decomposition
+    with pytest.warns(UserWarning, match='did not converge'):
+        ica.fit(raw)
+    repr(ica)  # to test repr
+    assert ('mag' in ica)  # should now work without error
+
+    # test re-fit
+    unmixing1 = ica.unmixing_matrix_
+    with pytest.warns(UserWarning, match='did not converge'):
+        ica.fit(raw)
+    assert_array_almost_equal(unmixing1, ica.unmixing_matrix_)
+
+    raw_sources = ica.get_sources(raw)
+    # test for #3804
+    assert_equal(raw_sources._filenames, [None])
+    print(raw_sources)
+
+    # test for gh-6271 (scaling of ICA traces)
+    fig = raw_sources.plot()
+    assert len(fig.axes[0].lines) in (5, 9)
+    for line in fig.axes[0].lines:
+        y = line.get_ydata()
+        if len(y) > 2:  # actual data, not markers
+            assert np.ptp(y) < 15
+    plt.close('all')
+
+    sources = raw_sources[:, :][0]
+    assert (sources.shape[0] == ica.n_components_)
+
+    # test preload filter
+    raw3 = raw.copy()
+    raw3.preload = False
+    with pytest.raises(RuntimeError, match='to be loaded'):
+        ica.apply(raw3)
+
+    #######################################################################
+    # test epochs decomposition
+    ica = ICA(noise_cov=noise_cov, n_components=n_components, method=method)
+    with pytest.warns(None):  # sometimes warns
+        ica.fit(epochs)
+    _assert_ica_attributes(ica, epochs.get_data(), limits=(0.2, 20))
+    data = epochs.get_data()[:, 0, :]
+    n_samples = np.prod(data.shape)
+    assert_equal(ica.n_samples_, n_samples)
+    print(ica)  # to test repr
 
-        with pytest.raises(ValueError, match='target do not have the same nu'):
-            ica.score_sources(epochs, target=np.arange(1))
+    sources = ica.get_sources(epochs).get_data()
+    assert (sources.shape[1] == ica.n_components_)
 
-        # test preload filter
-        epochs3 = epochs.copy()
-        epochs3.preload = False
-        with pytest.raises(RuntimeError, match='requires epochs data to be l'):
-            ica.apply(epochs3, include=[1, 2])
+    with pytest.raises(ValueError, match='target do not have the same nu'):
+        ica.score_sources(epochs, target=np.arange(1))
+
+    # test preload filter
+    epochs3 = epochs.copy()
+    epochs3.preload = False
+    with pytest.raises(RuntimeError, match='requires epochs data to be l'):
+        ica.apply(epochs3)
 
     # test for bug with whitener updating
     _pre_whitener = ica.pre_whitener_.copy()
@@ -550,8 +551,7 @@ def test_ica_additional(method, tmpdir):
     del picks2
 
     test_cov2 = test_cov.copy()
-    ica = ICA(noise_cov=test_cov2, n_components=3, n_pca_components=4,
-              method=method)
+    ica = ICA(noise_cov=test_cov2, n_components=3, method=method)
     assert (ica.info is None)
     with pytest.warns(RuntimeWarning, match='normalize_proj'):
         ica.fit(raw, picks[:5])
@@ -559,7 +559,7 @@ def test_ica_additional(method, tmpdir):
     assert (isinstance(ica.info, Info))
     assert (ica.n_components_ < 5)
 
-    ica = ICA(n_components=3, n_pca_components=4, method=method, max_iter=1)
+    ica = ICA(n_components=3, method=method, max_iter=1)
     with pytest.raises(RuntimeError, match='No fit'):
         ica.save('')
 
@@ -633,7 +633,7 @@ def test_ica_additional(method, tmpdir):
         read_ica(ica_badname)
 
     # test decim
-    ica = ICA(n_components=3, n_pca_components=4, method=method, max_iter=1)
+    ica = ICA(n_components=3, method=method, max_iter=1)
     raw_ = raw.copy()
     for _ in range(3):
         raw_.append(raw_)
@@ -648,7 +648,7 @@ def test_ica_additional(method, tmpdir):
         ICA(n_components=1., method=method)
     with pytest.raises(ValueError, match="Selecting one component"):
         ICA(n_components=1, method=method)
-    ica = ICA(n_pca_components=4, method=method, max_iter=1)
+    ica = ICA(n_components=4, method=method, max_iter=1)
     with pytest.warns(UserWarning, match='did not converge'):
         ica.fit(raw, picks=None, decim=3)
     _assert_ica_attributes(ica)
@@ -667,9 +667,9 @@ def test_ica_additional(method, tmpdir):
     pytest.raises(RuntimeError, ica.get_sources, epochs)
     # test reading and writing
     test_ica_fname = tmpdir.join('test-ica.fif')
+    kwargs = dict(n_pca_components=4)
     for cov in (None, test_cov):
-        ica = ICA(noise_cov=cov, n_components=2, n_pca_components=4,
-                  method=method, max_iter=1)
+        ica = ICA(noise_cov=cov, n_components=2, method=method, max_iter=1)
         with pytest.warns(None):  # ICA does not converge
             ica.fit(raw, picks=picks[:10], start=start, stop=stop2)
         _assert_ica_attributes(ica)
@@ -686,13 +686,13 @@ def test_ica_additional(method, tmpdir):
             ica_read = read_ica(test_ica_fname)
             assert (list(ica.exclude) == ica_read.exclude)
             assert_equal(ica.labels_, ica_read.labels_)
-            ica.apply(raw.copy())
+            ica.apply(raw.copy(), **kwargs)
             ica.exclude = []
-            ica.apply(raw.copy(), exclude=[1])
+            ica.apply(raw.copy(), exclude=[1], **kwargs)
             assert (ica.exclude == [])
 
             ica.exclude = [0, 1]
-            ica.apply(raw.copy(), exclude=[1])
+            ica.apply(raw.copy(), exclude=[1], **kwargs)
             assert (ica.exclude == [0, 1])
 
             ica_raw = ica.get_sources(raw)
@@ -933,7 +933,7 @@ def test_ica_reject_buffer(method):
     picks = pick_types(raw.info, meg=True, stim=False, ecg=False,
                        eog=False, exclude='bads')
     raw._data[2, 1000:1005] = 5e-12
-    ica = ICA(n_components=3, n_pca_components=4, method=method)
+    ica = ICA(n_components=3, method=method)
     with catch_logging() as drop_log:
         ica.fit(raw, picks[:5], reject=dict(mag=2.5e-12), decim=2,
                 tstep=0.01, verbose=True, reject_by_annotation=False)
@@ -953,13 +953,11 @@ def test_ica_twice(method):
     picks = pick_types(raw.info, meg='grad', exclude='bads')
     n_components = 0.9
     n_pca_components = 0.9999
-    ica1 = ICA(n_components=n_components, method=method,
-               n_pca_components=n_pca_components)
+    ica1 = ICA(n_components=n_components, method=method)
 
     ica1.fit(raw, picks=picks, decim=3)
     raw_new = ica1.apply(raw, n_pca_components=n_pca_components)
-    ica2 = ICA(n_components=n_components, method=method,
-               n_pca_components=0.9999)
+    ica2 = ICA(n_components=n_components, method=method)
     ica2.fit(raw_new, picks=picks, decim=3)
     assert_equal(ica1.n_components_, ica2.n_components_)
 
@@ -1124,8 +1122,9 @@ def test_n_components_none(method, tmpdir):
     random_state = 12345
 
     output_fname = tmpdir.join('test_ica-ica.fif')
-    ica = ICA(n_pca_components=n_pca_components, method=method,
-              n_components=n_components, random_state=random_state)
+    with pytest.deprecated_call():
+        ica = ICA(n_pca_components=n_pca_components, method=method,
+                  n_components=n_components, random_state=random_state)
     with pytest.warns(None):
         ica.fit(epochs)
     _assert_ica_attributes(ica)
@@ -1149,13 +1148,8 @@ def test_n_components_and_max_pca_components_none(method, tmpdir):
     epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks,
                     baseline=(None, 0), preload=True)
 
-    max_pca_components = None
-    n_components = None
-    random_state = 12345
-
     output_fname = tmpdir.join('test_ica-ica.fif')
-    ica = ICA(max_pca_components=max_pca_components, method=method,
-              n_components=n_components, random_state=random_state)
+    ica = ICA(method=method)
     with pytest.warns(None):  # convergence
         ica.fit(epochs)
     ica.save(output_fname)
diff --git a/mne/viz/tests/test_ica.py b/mne/viz/tests/test_ica.py
--- a/mne/viz/tests/test_ica.py
+++ b/mne/viz/tests/test_ica.py
@@ -58,8 +58,7 @@ def test_plot_ica_components():
     res = 8
     fast_test = {"res": res, "contours": 0, "sensors": False}
     raw = _get_raw()
-    ica = ICA(noise_cov=read_cov(cov_fname), n_components=2,
-              n_pca_components=3)
+    ica = ICA(noise_cov=read_cov(cov_fname), n_components=2)
     ica_picks = _get_picks(raw)
     with pytest.warns(RuntimeWarning, match='projection'):
         ica.fit(raw, picks=ica_picks)
@@ -123,7 +122,7 @@ def test_plot_ica_properties():
                     baseline=(None, 0), preload=True)
 
     ica = ICA(noise_cov=read_cov(cov_fname), n_components=2, max_iter=1,
-              n_pca_components=2, random_state=0)
+              random_state=0)
     with pytest.warns(RuntimeWarning, match='projection'):
         ica.fit(raw)
 
@@ -206,7 +205,7 @@ def test_plot_ica_sources():
     raw.pick_channels([raw.ch_names[k] for k in picks])
     ica_picks = pick_types(raw.info, meg=True, eeg=False, stim=False,
                            ecg=False, eog=False, exclude='bads')
-    ica = ICA(n_components=2, n_pca_components=3)
+    ica = ICA(n_components=2)
     ica.fit(raw, picks=ica_picks)
     ica.exclude = [1]
     fig = ica.plot_sources(raw)
@@ -269,8 +268,7 @@ def test_plot_ica_overlay():
     """Test plotting of ICA cleaning."""
     raw = _get_raw(preload=True)
     picks = _get_picks(raw)
-    ica = ICA(noise_cov=read_cov(cov_fname), n_components=2,
-              n_pca_components=3, random_state=0)
+    ica = ICA(noise_cov=read_cov(cov_fname), n_components=2, random_state=0)
     # can't use info.normalize_proj here because of how and when ICA and Epochs
     # objects do picking of Raw data
     with pytest.warns(RuntimeWarning, match='projection'):
@@ -291,7 +289,7 @@ def test_plot_ica_overlay():
     raw = read_raw_fif(raw_ctf_fname)
     raw.apply_gradient_compensation(3)
     picks = pick_types(raw.info, meg=True, ref_meg=False)
-    ica = ICA(n_components=2, n_pca_components=3)
+    ica = ICA(n_components=2, )
     ica.fit(raw, picks=picks)
     with pytest.warns(RuntimeWarning, match='longer than'):
         ecg_epochs = create_ecg_epochs(raw)
@@ -304,8 +302,7 @@ def test_plot_ica_scores():
     """Test plotting of ICA scores."""
     raw = _get_raw()
     picks = _get_picks(raw)
-    ica = ICA(noise_cov=read_cov(cov_fname), n_components=2,
-              n_pca_components=3)
+    ica = ICA(noise_cov=read_cov(cov_fname), n_components=2)
     with pytest.warns(RuntimeWarning, match='projection'):
         ica.fit(raw, picks=picks)
     ica.plot_scores([0.3, 0.2], axhline=[0.1, -0.1], figsize=(6.4, 2.7))
@@ -348,8 +345,7 @@ def test_plot_instance_components():
     """Test plotting of components as instances of raw and epochs."""
     raw = _get_raw()
     picks = _get_picks(raw)
-    ica = ICA(noise_cov=read_cov(cov_fname), n_components=2,
-              n_pca_components=3)
+    ica = ICA(noise_cov=read_cov(cov_fname), n_components=2)
     with pytest.warns(RuntimeWarning, match='projection'):
         ica.fit(raw, picks=picks)
     ica.exclude = [0]