Repository: mne-tools/mne-python

Issue:
RFC: result of connectivity=None to clustering functions may be misleading
Summarizing a discussion I just had offline with @larsoner:

In `mne.stats.spatio_temporal_cluster{_1samp}_test`, the input array `X` takes shape (n_observations, n_times, n_vertices). Normally, the vertices come from an STC object, and a (sparse) matrix encoding the connectivity is easily obtained from the associated source space.

However, it is allowed to pass `connectivity=None`, which will default to using `scipy.ndimage.generate_binary_structure(2, 1)` to define a 2D regular lattice connectivity. The problem with that is that the 2D lattice connectivity may or may not be appropriate, because (again) the input shape is (n_observations, n_times, n_vertices), so it's only useful if your n_vertices dimension is in fact spatially one-dimensional.  But when would a neuroscience application be dealing with a series of spatial points that actually have one-dimensional connectivity?

It seems like supporting `connectivity=None` is a case of YAGNI, and might lead to unexpected results for users who, by analogy with the usage with STCs, think "OK, I have this 2D array, I need to ravel it, but I don't need to compute connectivity because it says the default is to use regular lattice connectivity, which is what I want".  

I think `permutation_cluster{_1samp}_test` has the same problem: it [flattens out the last dimension](https://github.com/mne-tools/mne-python/blob/master/mne/stats/cluster_level.py#L837-L838) prior to eventually [running the default lattice connectivity code](https://github.com/mne-tools/mne-python/blob/master/mne/stats/cluster_level.py#L492-L493).

My recommendation is to simply remove `connectivity=None` as a valid option to those functions. @agramfort WDYT?

crossref #4859


Discussion:
By the way, we could add (to the `Notes` section of those functions, or to a tutorial/example) advice about how to compute regular lattice connectivity for yourself (`sklearn.feature_extraction.image.grid_to_graph` seems to be the easiest way)
(n_observations, n_times, n_vertices) could be (n_observations, n_times,
n_frequencies)
where a grid would make sense. I think we had an example about this at some
point.

still think it's a YAGNI?

did you get feedback from users doing a mess without noticing?

>

> (n_observations, n_times, n_vertices) could be (n_observations, n_times, n_frequencies) where a grid would make sense.

Good point, that seems like a valid use case.

> did you get feedback from users doing a mess without noticing?

I noticed this myself when trying to do a simulation with a 2D numpy array in place of an stc.

I'll leave this open for now and push a small docstring improvement to close it.

works for me

>

In the process of updating the docs, I re-realized that there is a problem here: if I pass a series of TF images to `permutation_cluster_1samp_test`, then my input array `X` is shape (n_obs, n_times, n_freqs). If I also pass `connectivity=None`, expecting a regular lattice connectivity structure to be imposed on my TF image, that's not what I'll get, because [the time and freq dimensions get unrolled](https://github.com/mne-tools/mne-python/blob/master/mne/stats/cluster_level.py#L837-L839) *before* the lattice connectivity is computed (code path is [here](https://github.com/mne-tools/mne-python/blob/master/mne/stats/cluster_level.py#L837-L839) to [here](https://github.com/mne-tools/mne-python/blob/master/mne/stats/cluster_level.py#L429-L431) to [here](https://github.com/mne-tools/mne-python/blob/master/mne/stats/cluster_level.py#L474-L475) to [here](https://github.com/mne-tools/mne-python/blob/master/mne/stats/cluster_level.py#L492-L493)).

So I think there is a legitimate problem with how `connectivity=None` works, that can't be fixed with a better docstring.

Resolving patch:
diff --git a/mne/stats/cluster_level.py b/mne/stats/cluster_level.py
--- a/mne/stats/cluster_level.py
+++ b/mne/stats/cluster_level.py
@@ -1042,81 +1042,36 @@ def permutation_cluster_test(
     multiple comparisons using permutations and cluster level correction.
     Each element of the list X contains the data for one group of
     observations. Randomized data are generated with random partitions
-    of the data.
+    of the data. See :footcite:`MarisOostenveld2007` for details.
 
     Parameters
     ----------
-    X : list
-        List of nd-arrays containing the data. Each element of X contains
-        the samples for one group. First dimension of each element is the
-        number of samples/observations in this group. The other dimensions
-        are for the size of the observations. For example if X = [X1, X2]
-        with X1.shape = (20, 50, 4) and X2.shape = (17, 50, 4) one has
-        2 groups with respectively 20 and 17 observations in each.
-        Each data point is of shape (50, 4).
-    threshold : float | dict | None
-        If threshold is None, it will choose an F-threshold equivalent to
-        p < 0.05 for the given number of observations (only valid when
-        using an F-statistic). If a dict is used, then threshold-free
-        cluster enhancement (TFCE) will be used, and it must have keys
-        ``'start'`` and ``'step'`` to specify the integration parameters,
-        see the :ref:`TFCE example <tfce_example>`.
-    n_permutations : int
-        The number of permutations to compute.
-    tail : -1 or 0 or 1 (default = 0)
-        If tail is 0, the statistic is thresholded on both sides of
-        the distribution.
-        If tail is 1, the statistic is thresholded above threshold.
-        If tail is -1, the statistic is thresholded below threshold, and
-        the values in ``threshold`` must correspondingly be negative.
-    stat_fun : callable | None
-        Function called to calculate statistics, must accept 1d-arrays as
-        arguments (default None uses :func:`mne.stats.f_oneway`).
-    connectivity : scipy.sparse.spmatrix
-        Defines connectivity between features. The matrix is assumed to
-        be symmetric and only the upper triangular half is used.
-        Default is None, i.e, a regular lattice connectivity.
-        Can also be False to assume no connectivity.
+    X : list of array, shape (n_observations, p[, q])
+        The data to be clustered. Each array in ``X`` should contain the
+        observations for one group. The first dimension of each array is the
+        number of observations from that group; remaining dimensions comprise
+        the size of a single observation. For example if ``X = [X1, X2]``
+        with ``X1.shape = (20, 50, 4)`` and ``X2.shape = (17, 50, 4)``, then
+        ``X`` has 2 groups with respectively 20 and 17 observations in each,
+        and each data point is of shape ``(50, 4)``.
+    %(clust_thresh_f)s
+    %(clust_nperm_int)s
+    %(clust_tail)s
+    %(clust_stat_f)s
+    %(clust_con_n)s
     %(n_jobs)s
     %(seed)s
-    max_step : int
-        When connectivity is a n_vertices x n_vertices matrix, specify the
-        maximum number of steps between vertices along the second dimension
-        (typically time) to be considered connected. This is not used for full
-        or None connectivity matrices.
+    %(clust_maxstep)s
     exclude : bool array or None
         Mask to apply to the data to exclude certain points from clustering
         (e.g., medial wall vertices). Should be the same shape as X. If None,
         no points are excluded.
-    step_down_p : float
-        To perform a step-down-in-jumps test, pass a p-value for clusters to
-        exclude from each successive iteration. Default is zero, perform no
-        step-down test (since no clusters will be smaller than this value).
-        Setting this to a reasonable value, e.g. 0.05, can increase sensitivity
-        but costs computation time.
-    t_power : float
-        Power to raise the statistical values (usually F-values) by before
-        summing (sign will be retained). Note that t_power == 0 will give a
-        count of nodes in each cluster, t_power == 1 will weight each node by
-        its statistical score.
-    out_type : str
-        For arrays with connectivity, this sets the output format for clusters.
-        If 'mask', it will pass back a list of boolean mask arrays.
-        If 'indices', it will pass back a list of lists, where each list is the
-        set of vertices in a given cluster. Note that the latter may use far
-        less memory for large datasets.
-    check_disjoint : bool
-        If True, the connectivity matrix (or list) will be examined to
-        determine of it can be separated into disjoint sets. In some cases
-        (usually with connectivity as a list and many "time" points), this
-        can lead to faster clustering, but results should be identical.
-    buffer_size : int or None
-        The statistics will be computed for blocks of variables of size
-        "buffer_size" at a time. This is option significantly reduces the
-        memory requirements when n_jobs > 1 and memory sharing between
-        processes is enabled (see set_cache_dir()), as X will be shared
-        between processes and each process only needs to allocate space
-        for a small block of variables.
+    %(clust_stepdown)s
+    %(clust_power_f)s
+    %(clust_out)s
+        Default is ``'mask'``.
+    %(clust_disjoint)s
+    %(clust_buffer)s
     %(verbose)s
 
     Returns
@@ -1132,9 +1087,7 @@ def permutation_cluster_test(
 
     References
     ----------
-    .. [1] Maris/Oostenveld (2007), "Nonparametric statistical testing of
-       EEG- and MEG-data" Journal of Neuroscience Methods,
-       Vol. 164, No. 1., pp. 177-190. doi:10.1016/j.jneumeth.2007.03.024.
+    .. footbibliography::
     """
     stat_fun, threshold = _check_fun(X, stat_fun, threshold, tail, 'between')
     return _permutation_cluster_test(
@@ -1155,78 +1108,33 @@ def permutation_cluster_1samp_test(
 
     Parameters
     ----------
-    X : array, shape=(n_samples, p[, q])
-        Array where the first dimension corresponds to the
-        difference in paired samples (observations) in two conditions.
-        ``X[k]`` can be a 1D or 2D array (time series
-        or TF image) associated to the kth observation.
-    threshold : float | dict | None
-        If threshold is None, it will choose a t-threshold equivalent to
-        p < 0.05 for the given number of observations (only valid when
-        using an t-statistic). If a dict is used, then threshold-free
-        cluster enhancement (TFCE) will be used, and it must have keys
-        ``'start'`` and ``'step'`` to specify the integration parameters,
-        see the :ref:`TFCE example <tfce_example>`.
-    n_permutations : int | 'all'
-        The maximum number of permutations to compute. Can be 'all'
-        to perform an exact test.
-    tail : -1 or 0 or 1 (default = 0)
-        If tail is 1, the statistic is thresholded above threshold.
-        If tail is -1, the statistic is thresholded below threshold.
-        If tail is 0, the statistic is thresholded on both sides of
-        the distribution.
-    stat_fun : callable | None
-        Function used to compute the statistical map (default None will use
-        :func:`mne.stats.ttest_1samp_no_p`).
-    connectivity : scipy.sparse.spmatrix | None | False
-        Defines connectivity between features. The matrix is assumed to
-        be symmetric and only the upper triangular half is used.
-        This matrix must be square with dimension (n_vertices * n_times) or
-        (n_vertices). Default is None, i.e, a regular lattice connectivity.
-        Use square n_vertices matrix for datasets with a large temporal
-        extent to save on memory and computation time. Can also be False
-        to assume no connectivity.
+    X : array, shape (n_observations, p[, q])
+        The data to be clustered. The first dimension should correspond to the
+        difference between paired samples (observations) in two conditions.
+        The subarrays ``X[k]`` can be 1D (e.g., time series) or 2D (e.g.,
+        time-frequency image) associated with the kth observation. For
+        spatiotemporal data, see also
+        :func:`mne.stats.spatio_temporal_cluster_1samp_test`.
+    %(clust_thresh_t)s
+    %(clust_nperm_all)s
+    %(clust_tail)s
+    %(clust_stat_t)s
+    %(clust_con_1)s
     %(verbose)s
     %(n_jobs)s
     %(seed)s
-    max_step : int
-        When connectivity is a n_vertices x n_vertices matrix, specify the
-        maximum number of steps between vertices along the second dimension
-        (typically time) to be considered connected. This is not used for full
-        or None connectivity matrices.
+    %(clust_maxstep)s
     exclude : bool array or None
         Mask to apply to the data to exclude certain points from clustering
         (e.g., medial wall vertices). Should be the same shape as X. If None,
         no points are excluded.
-    step_down_p : float
-        To perform a step-down-in-jumps test, pass a p-value for clusters to
-        exclude from each successive iteration. Default is zero, perform no
-        step-down test (since no clusters will be smaller than this value).
-        Setting this to a reasonable value, e.g. 0.05, can increase sensitivity
-        but costs computation time.
-    t_power : float
-        Power to raise the statistical values (usually t-values) by before
-        summing (sign will be retained). Note that t_power == 0 will give a
-        count of nodes in each cluster, t_power == 1 will weight each node by
-        its statistical score.
-    out_type : str
-        For arrays with connectivity, this sets the output format for clusters.
-        If 'mask', it will pass back a list of boolean mask arrays.
-        If 'indices', it will pass back a list of lists, where each list is the
-        set of vertices in a given cluster. Note that the latter may use far
-        less memory for large datasets.
-    check_disjoint : bool
-        If True, the connectivity matrix (or list) will be examined to
-        determine of it can be separated into disjoint sets. In some cases
-        (usually with connectivity as a list and many "time" points), this
-        can lead to faster clustering, but results should be identical.
-    buffer_size : int or None
-        The statistics will be computed for blocks of variables of size
-        "buffer_size" at a time. This is option significantly reduces the
-        memory requirements when n_jobs > 1 and memory sharing between
-        processes is enabled (see set_cache_dir()), as X will be shared
-        between processes and each process only needs to allocate space
-        for a small block of variables.
+    %(clust_stepdown)s
+    %(clust_power_t)s
+    %(clust_out)s
+        Default is ``'mask'``.
+    %(clust_disjoint)s
+    %(clust_buffer)s
+    %(verbose)s
 
     Returns
     -------
@@ -1246,7 +1154,8 @@ def permutation_cluster_1samp_test(
     distributions in the two conditions are significantly different.
     The procedure uses a cluster analysis with permutation test
     for calculating corrected p-values. Randomized data are generated with
-    random sign flips. See [1]_ for more information.
+    random sign flips. See :footcite:`MarisOostenveld2007` for more
+    information.
 
     Because a 1-sample t-test on the difference in observations is
     mathematically equivalent to a paired t-test, internally this function
@@ -1264,9 +1173,7 @@ def permutation_cluster_1samp_test(
 
     References
     ----------
-    .. [1] Maris/Oostenveld (2007), "Nonparametric statistical testing of
-       EEG- and MEG-data" Journal of Neuroscience Methods,
-       Vol. 164, No. 1., pp. 177-190. doi:10.1016/j.jneumeth.2007.03.024.
+    .. footbibliography::
     """
     stat_fun, threshold = _check_fun(X, stat_fun, threshold, tail)
     return _permutation_cluster_test(
@@ -1286,78 +1193,33 @@ def spatio_temporal_cluster_1samp_test(
         verbose=None):
     """Non-parametric cluster-level paired t-test for spatio-temporal data.
 
-    This function provides a convenient wrapper for data organized in the form
-    (observations x time x space) to use
-    :func:`mne.stats.permutation_cluster_1samp_test`, which contains more
-    complete documentation.
+    This function provides a convenient wrapper for
+    :func:`mne.stats.permutation_cluster_1samp_test`, for use with data
+    organized in the form (observations × time × space). See
+    :footcite:`MarisOostenveld2007` for details.
 
     Parameters
     ----------
     X : array, shape (n_observations, n_times, n_vertices)
-        Array data of the difference between two conditions.
-    threshold : float | dict | None
-        If threshold is None, it will choose a t-threshold equivalent to
-        p < 0.05 for the given number of observations (only valid when
-        using an t-statistic). If a dict is used, then threshold-free
-        cluster enhancement (TFCE) will be used, and it must have keys
-        ``'start'`` and ``'step'`` to specify the integration parameters,
-        see the :ref:`TFCE example <tfce_example>`.
-    n_permutations : int | 'all'
-        The number of permutations to compute. Can be "all" to perform
-        an exact test.
-    tail : -1 or 0 or 1 (default = 0)
-        If tail is 1, the statistic is thresholded above threshold.
-        If tail is -1, the statistic is thresholded below threshold.
-        If tail is 0, the statistic is thresholded on both sides of
-        the distribution.
-    stat_fun : callable | None
-        Function used to compute the statistical map (default None will use
-        :func:`mne.stats.ttest_1samp_no_p`).
-    connectivity : scipy.sparse.spmatrix or None
-        Defines connectivity between features. The matrix is assumed to
-        be symmetric and only the upper triangular half is used.
-        This matrix must be square with dimension (n_vertices * n_times) or
-        (n_vertices). Default is None, i.e, a regular lattice connectivity.
-        Use square n_vertices matrix for datasets with a large temporal
-        extent to save on memory and computation time.
+        The data to be clustered. The first dimension should correspond to the
+        difference between paired samples (observations) in two conditions.
+    %(clust_thresh_t)s
+    %(clust_nperm_all)s
+    %(clust_tail)s
+    %(clust_stat_t)s
+    %(clust_con_st1)s
     %(n_jobs)s
     %(seed)s
-    max_step : int
-        When connectivity is a n_vertices x n_vertices matrix, specify the
-        maximum number of steps between vertices along the second dimension
-        (typically time) to be considered connected. This is not used for full
-        or None connectivity matrices.
+    %(clust_maxstep)s
     spatial_exclude : list of int or None
         List of spatial indices to exclude from clustering.
-    step_down_p : float
-        To perform a step-down-in-jumps test, pass a p-value for clusters to
-        exclude from each successive iteration. Default is zero, perform no
-        step-down test (since no clusters will be smaller than this value).
-        Setting this to a reasonable value, e.g. 0.05, can increase sensitivity
-        but costs computation time.
-    t_power : float
-        Power to raise the statistical values (usually t-values) by before
-        summing (sign will be retained). Note that t_power == 0 will give a
-        count of nodes in each cluster, t_power == 1 will weight each node by
-        its statistical score.
-    out_type : str
-        For arrays with connectivity, this sets the output format for clusters.
-        If 'mask', it will pass back a list of boolean mask arrays.
-        If 'indices', it will pass back a list of lists, where each list is the
-        set of vertices in a given cluster. Note that the latter may use far
-        less memory for large datasets.
-    check_disjoint : bool
-        If True, the connectivity matrix (or list) will be examined to
-        determine of it can be separated into disjoint sets. In some cases
-        (usually with connectivity as a list and many "time" points), this
-        can lead to faster clustering, but results should be identical.
-    buffer_size : int or None
-        The statistics will be computed for blocks of variables of size
-        "buffer_size" at a time. This is option significantly reduces the
-        memory requirements when n_jobs > 1 and memory sharing between
-        processes is enabled (see set_cache_dir()), as X will be shared
-        between processes and each process only needs to allocate space
-        for a small block of variables.
+    %(clust_stepdown)s
+    %(clust_power_t)s
+    %(clust_out)s
+        Default is ``'indices'``.
+    %(clust_disjoint)s
+    %(clust_buffer)s
+    %(verbose)s
     %(verbose)s
 
     Returns
@@ -1373,12 +1235,7 @@ def spatio_temporal_cluster_1samp_test(
 
     References
     ----------
-    .. [1] Maris/Oostenveld, "Nonparametric statistical testing of
-       EEG- and MEG-data" Journal of Neuroscience Methods,
-       Vol. 164, No. 1., pp. 177-190. doi:10.1016/j.jneumeth.2007.03.024
-    .. [2] Smith/Nichols (2009), "Threshold-free cluster enhancement:
-       Addressing problems of smoothing, threshold dependence, and
-       localisation in cluster inference", NeuroImage 44 (2009) 83-98.
+    .. footbibliography::
     """
     n_samples, n_times, n_vertices = X.shape
     # convert spatial_exclude before passing on if necessary
@@ -1403,73 +1260,36 @@ def spatio_temporal_cluster_test(
         check_disjoint=False, buffer_size=1000):
     """Non-parametric cluster-level test for spatio-temporal data.
 
-    This function provides a convenient wrapper for data organized in the form
-    (observations x time x space) to use
-    :func:`mne.stats.permutation_cluster_test`. See [1]_ for more information.
+    This function provides a convenient wrapper for
+    :func:`mne.stats.permutation_cluster_test`, for use with data
+    organized in the form (observations × time × space).
+    See :footcite:`MarisOostenveld2007` for more information.
 
     Parameters
     ----------
-    X : list of array
-        List of data arrays, shape ``(n_observations, n_times, n_vertices)``
-        in each group.
-    threshold : float | dict | None
-        If threshold is None, it will choose an F-threshold equivalent to
-        p < 0.05 for the given number of observations (only valid when
-        using an F-statistic). If a dict is used, then threshold-free
-        cluster enhancement (TFCE) will be used, and it must have keys
-        ``'start'`` and ``'step'`` to specify the integration parameters,
-        see the :ref:`TFCE example <tfce_example>`.
-    n_permutations : int
-        See permutation_cluster_test.
-    tail : -1 or 0 or 1 (default = 0)
-        See permutation_cluster_test.
-    stat_fun : callable | None
-        Function called to calculate statistics, must accept 1d-arrays as
-        arguments (default None uses :func:`mne.stats.f_oneway`). It
-        should also return a 1-d array.
-    connectivity : scipy.sparse.spmatrix or None
-        Defines connectivity between features. The matrix is assumed to
-        be symmetric and only the upper triangular half is used.
-        Default is None, i.e, a regular lattice connectivity.
+    X : list of array, shape (n_observations, n_times, n_vertices)
+        The data to be clustered. Each array in ``X`` should contain the
+        observations for one group. The first dimension of each array is the
+        number of observations from that group (and may vary between groups);
+        the remaining dimensions (times and vertices) should match across all
+        groups.
+    %(clust_thresh_f)s
+    %(clust_nperm_int)s
+    %(clust_tail)s
+    %(clust_stat_f)s
+    %(clust_con_stn)s
     %(verbose)s
     %(n_jobs)s
     %(seed)s
-    max_step : int
-        When connectivity is a n_vertices x n_vertices matrix, specify the
-        maximum number of steps between vertices along the second dimension
-        (typically time) to be considered connected. This is not used for full
-        or None connectivity matrices.
+    %(clust_maxstep)s
     spatial_exclude : list of int or None
         List of spatial indices to exclude from clustering.
-    step_down_p : float
-        To perform a step-down-in-jumps test, pass a p-value for clusters to
-        exclude from each successive iteration. Default is zero, perform no
-        step-down test (since no clusters will be smaller than this value).
-        Setting this to a reasonable value, e.g. 0.05, can increase sensitivity
-        but costs computation time.
-    t_power : float
-        Power to raise the statistical values (usually F-values) by before
-        summing (sign will be retained). Note that t_power == 0 will give a
-        count of nodes in each cluster, t_power == 1 will weight each node by
-        its statistical score.
-    out_type : str
-        For arrays with connectivity, this sets the output format for clusters.
-        If 'mask', it will pass back a list of boolean mask arrays.
-        If 'indices', it will pass back a list of lists, where each list is the
-        set of vertices in a given cluster. Note that the latter may use far
-        less memory for large datasets.
-    check_disjoint : bool
-        If True, the connectivity matrix (or list) will be examined to
-        determine of it can be separated into disjoint sets. In some cases
-        (usually with connectivity as a list and many "time" points), this
-        can lead to faster clustering, but results should be identical.
-    buffer_size : int or None
-        The statistics will be computed for blocks of variables of size
-        "buffer_size" at a time. This is option significantly reduces the
-        memory requirements when n_jobs > 1 and memory sharing between
-        processes is enabled (see set_cache_dir()), as X will be shared
-        between processes and each process only needs to allocate space
-        for a small block of variables.
+    %(clust_stepdown)s
+    %(clust_power_f)s
+    %(clust_out)s
+        Default is ``'indices'``.
+    %(clust_disjoint)s
+    %(clust_buffer)s
 
     Returns
     -------
@@ -1484,9 +1304,7 @@ def spatio_temporal_cluster_test(
 
     References
     ----------
-    .. [1] Maris/Oostenveld (2007), "Nonparametric statistical testing of
-       EEG- and MEG-data", Journal of Neuroscience Methods,
-       Vol. 164, No. 1., pp. 177-190. doi:10.1016/j.jneumeth.2007.03.024.
+    .. footbibliography::
     """
     n_samples, n_times, n_vertices = X[0].shape
     # convert spatial_exclude before passing on if necessary
diff --git a/mne/utils/docs.py b/mne/utils/docs.py
--- a/mne/utils/docs.py
+++ b/mne/utils/docs.py
@@ -771,6 +771,117 @@
     similar STCs does not result in 180° direction/phase changes.
 """
 
+# Clustering
+docdict['clust_thresh'] = """
+threshold : float | dict | None
+    If numeric, vertices with data values more extreme than ``threshold`` will
+    be used to form clusters. If threshold is ``None``, {} will be chosen
+    automatically that corresponds to a p-value of 0.05 for the given number of
+    observations (only valid when using {}). If ``threshold`` is a
+    :class:`dict` (with keys ``'start'`` and ``'step'``) then threshold-free
+    cluster enhancement (TFCE) will be used (see the
+    :ref:`TFCE example <tfce_example>` and :footcite:`SmithNichols2009`).
+"""
+f_test = ('an F-threshold', 'an F-statistic')
+t_test = ('a t-threshold', 'a t-statistic')
+docdict['clust_thresh_f'] = docdict['clust_thresh'].format(*f_test)
+docdict['clust_thresh_t'] = docdict['clust_thresh'].format(*t_test)
+docdict['clust_nperm'] = """
+n_permutations : int{}
+    The number of permutations to compute.{}
+"""
+nperm_all = (" | 'all'", " Can be 'all' to perform an exact test.")
+docdict['clust_nperm_all'] = docdict['clust_nperm'].format(*nperm_all)
+docdict['clust_nperm_int'] = docdict['clust_nperm'].format('', '')
+docdict['clust_tail'] = """
+tail : int
+    If tail is 1, the statistic is thresholded above threshold.
+    If tail is -1, the statistic is thresholded below threshold.
+    If tail is 0, the statistic is thresholded on both sides of
+    the distribution.
+"""
+docdict['clust_stat'] = """
+stat_fun : callable | None
+    Function called to calculate the test statistic. Must accept 1D-array as
+    input and return a 1D array. If ``None`` (the default), uses
+    :func:`mne.stats.{}`.
+"""
+docdict['clust_stat_f'] = docdict['clust_stat'].format('f_oneway')
+docdict['clust_stat_t'] = docdict['clust_stat'].format('ttest_1samp_no_p')
+docdict['clust_con'] = """
+connectivity : scipy.sparse.spmatrix | None | False
+    Defines connectivity between locations in the data, where "locations" can
+    be spatial vertices, frequency bins, etc. If ``False``, assumes no
+    connectivity (each location is treated as independent and unconnected).
+    If ``None``, a regular lattice connectivity is assumed, connecting
+    each {sp} location to its neighbor(s) along the last dimension
+    of {{eachgrp}} ``{{x}}``{lastdim}.
+    If ``connectivity`` is a matrix, it is assumed to be symmetric (only the
+    upper triangular half is used) and must be square with dimension equal to
+    ``{{x}}.shape[-1]`` {parone} or ``{{x}}.shape[-1] * {{x}}.shape[-2]``
+    {partwo}.{memory}
+"""
+mem = (' If spatial connectivity is uniform in time, it is recommended to use '
+       'a square matrix with dimension ``{x}.shape[-1]`` (n_vertices) to save '
+       'memory and computation, and to use ``max_step`` to define the extent '
+       'of temporal adjacency to consider when clustering.')
+st = dict(sp='spatial', lastdim='', parone='(n_vertices)',
+          partwo='(n_times * n_vertices)', memory=mem)
+tf = dict(sp='', lastdim=' (or the last two dimensions if ``{x}`` is 2D)',
+          parone='', partwo='', memory='')
+nogroups = dict(eachgrp='', x='X')
+groups = dict(eachgrp='each group ', x='X[k]')
+docdict['clust_con_st1'] = docdict['clust_con'].format(**st).format(**nogroups)
+docdict['clust_con_stn'] = docdict['clust_con'].format(**st).format(**groups)
+docdict['clust_con_1'] = docdict['clust_con'].format(**tf).format(**nogroups)
+docdict['clust_con_n'] = docdict['clust_con'].format(**tf).format(**groups)
+docdict['clust_maxstep'] = """
+max_step : int
+    Maximum distance along the second dimension (typically this is the "time"
+    axis) between samples that are considered "connected". Only used
+    when ``connectivity`` has shape (n_vertices, n_vertices).
+"""
+docdict['clust_stepdown'] = """
+step_down_p : float
+    To perform a step-down-in-jumps test, pass a p-value for clusters to
+    exclude from each successive iteration. Default is zero, perform no
+    step-down test (since no clusters will be smaller than this value).
+    Setting this to a reasonable value, e.g. 0.05, can increase sensitivity
+    but costs computation time.
+"""
+docdict['clust_power'] = """
+t_power : float
+    Power to raise the statistical values (usually {}-values) by before
+    summing (sign will be retained). Note that ``t_power=0`` will give a
+    count of locations in each cluster, ``t_power=1`` will weight each location
+    by its statistical score.
+"""
+docdict['clust_power_t'] = docdict['clust_power'].format('t')
+docdict['clust_power_f'] = docdict['clust_power'].format('F')
+docdict['clust_out'] = """
+out_type : 'mask' | 'indices'
+    Output format of clusters. If ``'mask'``, returns boolean arrays the same
+    shape as the input data, with ``True`` values indicating locations that are
+    part of a cluster. If ``'indices'``, returns a list of lists, where each
+    sublist contains the indices of locations that together form a cluster.
+    Note that for large datasets, ``'indices'`` may use far less memory than
+    ``'mask'``.
+"""
+docdict['clust_disjoint'] = """
+check_disjoint : bool
+    Whether to check if the connectivity matrix can be separated into disjoint
+    sets before clustering. This may lead to faster clustering, especially if
+    the second dimension of ``X`` (usually the "time" dimension) is large.
+"""
+docdict['clust_buffer'] = """
+buffer_size : int | None
+    Block size to use when computing test statistics. This can significantly
+    reduce memory usage when n_jobs > 1 and memory sharing between processes is
+    enabled (see :func:`mne.set_cache_dir`), because ``X`` will be shared
+    between processes and each process only needs to allocate space for a small
+    block of locations at a time.
+"""
+
 # DataFrames
 docdict['df_scaling_time_deprecated'] = """
 scaling_time : None


Test patch: