We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
plot_stat_map (and probably plot_*) fails when display_mode axis has singleton dimension
Fuzzing the plotting code, I find the following testcase fails

```
    for axis, direction in enumerate("xyz"):
        shape = [5, 6, 7]
        shape[axis] = 1
        img = nibabel.Nifti1Image(np.ones(shape), np.eye(4))
        plot_stat_map(img, None, display_mode=direction)
```

`ValueError: Too many cuts requested for the data: n_cuts=7, data size=1`

The culprit is the find_cut_slices function.

A fix would be to return all the slices along the axis if there are at least as many requested n_slices as there are slices.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `nilearn/plotting/find_cuts.py`
Content:
```
1 """
2 Tools to find activations and cut on maps
3 """
4 
5 # Author: Gael Varoquaux
6 # License: BSD
7 
8 import numpy as np
9 from scipy import ndimage
10 
11 # Local imports
12 from .._utils.ndimage import largest_connected_component
13 from .._utils import new_img_like
14 from .._utils.extmath import fast_abs_percentile
15 from .._utils.numpy_conversions import as_ndarray
16 from ..image.resampling import get_mask_bounds, coord_transform
17 from ..image.image import _smooth_array
18 
19 ################################################################################
20 # Functions for automatic choice of cuts coordinates
21 ################################################################################
22 
23 
24 def find_xyz_cut_coords(img, mask=None, activation_threshold=None):
25     """ Find the center of the largest activation connected component.
26 
27         Parameters
28         -----------
29         img : 3D Nifti1Image
30             The brain map.
31         mask : 3D ndarray, boolean, optional
32             An optional brain mask.
33         activation_threshold : float, optional
34             The lower threshold to the positive activation. If None, the
35             activation threshold is computed using the 80% percentile of
36             the absolute value of the map.
37 
38         Returns
39         -------
40         x : float
41             the x world coordinate.
42         y : float
43             the y world coordinate.
44         z : float
45             the z world coordinate.
46     """
47     data = img.get_data()
48     # To speed up computations, we work with partial views of the array,
49     # and keep track of the offset
50     offset = np.zeros(3)
51 
52     # Deal with masked arrays:
53     if hasattr(data, 'mask'):
54         not_mask = np.logical_not(data.mask)
55         if mask is None:
56             mask = not_mask
57         else:
58             mask *= not_mask
59         data = np.asarray(data)
60 
61     # Get rid of potential memmapping
62     data = as_ndarray(data)
63     my_map = data.copy()
64     if mask is not None:
65         slice_x, slice_y, slice_z = ndimage.find_objects(mask)[0]
66         my_map = my_map[slice_x, slice_y, slice_z]
67         mask = mask[slice_x, slice_y, slice_z]
68         my_map *= mask
69         offset += [slice_x.start, slice_y.start, slice_z.start]
70 
71     # Testing min and max is faster than np.all(my_map == 0)
72     if (my_map.max() == 0) and (my_map.min() == 0):
73         return .5 * np.array(data.shape)
74     if activation_threshold is None:
75         activation_threshold = fast_abs_percentile(my_map[my_map != 0].ravel(),
76                                                    80)
77     mask = np.abs(my_map) > activation_threshold - 1.e-15
78     # mask may be zero everywhere in rare cases
79     if mask.max() == 0:
80         return .5 * np.array(data.shape)
81     mask = largest_connected_component(mask)
82     slice_x, slice_y, slice_z = ndimage.find_objects(mask)[0]
83     my_map = my_map[slice_x, slice_y, slice_z]
84     mask = mask[slice_x, slice_y, slice_z]
85     my_map *= mask
86     offset += [slice_x.start, slice_y.start, slice_z.start]
87 
88     # For the second threshold, we use a mean, as it is much faster,
89     # althought it is less robust
90     second_threshold = np.abs(np.mean(my_map[mask]))
91     second_mask = (np.abs(my_map) > second_threshold)
92     if second_mask.sum() > 50:
93         my_map *= largest_connected_component(second_mask)
94     cut_coords = ndimage.center_of_mass(np.abs(my_map))
95     x_map, y_map, z_map = cut_coords + offset
96 
97     # Return as a list of scalars
98     return np.asarray(coord_transform(x_map, y_map, z_map,
99                                       img.get_affine())).tolist()
100 
101 
102 def _get_auto_mask_bounds(img):
103     """ Compute the bounds of the data with an automaticaly computed mask
104     """
105     data = img.get_data().copy()
106     affine = img.get_affine()
107     if hasattr(data, 'mask'):
108         # Masked array
109         mask = np.logical_not(data.mask)
110         data = np.asarray(data)
111     else:
112         # The mask will be anything that is fairly different
113         # from the values in the corners
114         edge_value = float(data[0, 0, 0] + data[0, -1, 0]
115                             + data[-1, 0, 0] + data[0, 0, -1]
116                             + data[-1, -1, 0] + data[-1, 0, -1]
117                             + data[0, -1, -1] + data[-1, -1, -1]
118                         )
119         edge_value /= 6
120         mask = np.abs(data - edge_value) > .005*data.ptp()
121     xmin, xmax, ymin, ymax, zmin, zmax = \
122             get_mask_bounds(new_img_like(img, mask, affine))
123     return (xmin, xmax), (ymin, ymax), (zmin, zmax)
124 
125 
126 def find_cut_slices(img, direction='z', n_cuts=12, spacing='auto'):
127     """ Find 'good' cross-section slicing positions along a given axis.
128 
129     Parameters
130     ----------
131     img: 3D Nifti1Image
132         the brain map
133     direction: string, optional (default "z")
134         sectional direction; possible values are "x", "y", or "z"
135     n_cuts: int, optional (default 12)
136         number of cuts in the plot
137     spacing: 'auto' or int, optional (default 'auto')
138         minimum spacing between cuts (in voxels, not milimeters)
139         if 'auto', the spacing is .5 / n_cuts * img_length
140 
141     Returns
142     -------
143     cut_coords: 1D array of length n_cuts
144         the computed cut_coords
145 
146     Notes
147     -----
148     This code works by iteratively locating peak activations that are
149     separated by a distance of at least 'spacing'. If n_cuts is very
150     large and all the activated regions are covered, cuts with a spacing
151     less than 'spacing' will be returned.
152     """
153 
154     assert direction in 'xyz'
155 
156     axis = 'xyz'.index(direction)
157 
158     affine = img.get_affine()
159     orig_data = np.abs(img.get_data())
160     this_shape = orig_data.shape[axis]
161     if n_cuts > this_shape:
162         raise ValueError('Too many cuts requested for the data: '
163                          'n_cuts=%i, data size=%i' % (n_cuts, this_shape))
164 
165     data = orig_data.copy()
166     if data.dtype.kind == 'i':
167         data = data.astype(np.float)
168 
169     data = _smooth_array(data, affine, fwhm='fast')
170 
171     if spacing == 'auto':
172         spacing = max(int(.5 / n_cuts * data.shape[axis]), 1)
173 
174     slices = [slice(None, None), slice(None, None), slice(None, None)]
175 
176     cut_coords = list()
177 
178     for _ in range(n_cuts):
179         # Find a peak
180         max_along_axis = np.unravel_index(np.abs(data).argmax(),
181                                           data.shape)[axis]
182 
183         # cancel out the surroundings of the peak
184         start = max(0, max_along_axis - spacing)
185         stop = max_along_axis + spacing
186         slices[axis] = slice(start, stop)
187         # We don't actually fully zero the neighborhood, to avoid ending
188         # up with fully zeros if n_cuts is too big: we can do multiple
189         # passes on the data
190         data[slices] *= 1.e-3
191 
192         cut_coords.append(max_along_axis)
193 
194     # We sometimes get duplicated cuts, so we add cuts at the beginning
195     # and the end
196     cut_coords = np.unique(cut_coords).tolist()
197     while len(cut_coords) < n_cuts:
198         # Candidates for new cuts:
199         slice_below = min(cut_coords) - 2
200         slice_above = max(cut_coords) + 2
201         candidates = [slice_above]
202         # One slice where there is the biggest gap in the existing
203         # cut_coords
204         if len(cut_coords) > 1:
205             middle_idx = np.argmax(np.diff(cut_coords))
206             slice_middle = int(.5 * (cut_coords[middle_idx]
207                                     + cut_coords[middle_idx + 1]))
208             if not slice_middle in cut_coords:
209                 candidates.append(slice_middle)
210         if slice_below >= 0:
211             # We need positive slice to avoid having negative
212             # indices, which would work, but not the way we think of them
213             candidates.append(slice_below)
214         best_weight = -10
215         for candidate in candidates:
216             if candidate >= this_shape:
217                 this_weight = 0
218             else:
219                 this_weight = np.sum(np.rollaxis(orig_data, axis)[candidate])
220             if this_weight > best_weight:
221                 best_candidate = candidate
222                 best_weight = this_weight
223 
224         cut_coords.append(best_candidate)
225         cut_coords = np.unique(cut_coords).tolist()
226 
227     cut_coords = np.array(cut_coords)
228     cut_coords.sort()
229 
230     # Transform this back in image space
231     kwargs = dict()
232     for name in 'xyz':
233         kwargs[name] = np.zeros(len(cut_coords))
234     kwargs[direction] = cut_coords
235     kwargs['affine'] = affine
236 
237     cut_coords = coord_transform(**kwargs)[axis]
238     # We need to atleast_1d to make sure that when n_cuts is 1 we do
239     # get an iterable
240     return np.atleast_1d(cut_coords)
241
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/nilearn/plotting/find_cuts.py b/nilearn/plotting/find_cuts.py
--- a/nilearn/plotting/find_cuts.py
+++ b/nilearn/plotting/find_cuts.py
@@ -5,6 +5,7 @@
 # Author: Gael Varoquaux
 # License: BSD
 
+import warnings
 import numpy as np
 from scipy import ndimage
 
@@ -123,6 +124,39 @@
     return (xmin, xmax), (ymin, ymax), (zmin, zmax)
 
 
+def _transform_cut_coords(cut_coords, direction, affine):
+    """Transforms cut_coords back in image space
+
+    Parameters
+    ----------
+    cut_coords: 1D array of length n_cuts
+        The coordinates to be transformed.
+
+    direction: string, optional (default "z")
+        sectional direction; possible values are "x", "y", or "z"
+
+    affine: 2D array of shape (4, 4)
+        The affine for the image.
+
+    Returns
+    -------
+    cut_coords: 1D array of length n_cuts
+       The original cut_coords transformed image space.
+    """
+    # make kwargs
+    axis = 'xyz'.index(direction)
+    kwargs = {}
+    for name in 'xyz':
+        kwargs[name] = np.zeros(len(cut_coords))
+    kwargs[direction] = cut_coords
+    kwargs['affine'] = affine
+
+    # We need atleast_1d to make sure that when n_cuts is 1 we do
+    # get an iterable
+    cut_coords = coord_transform(**kwargs)[axis]
+    return np.atleast_1d(cut_coords)
+
+
 def find_cut_slices(img, direction='z', n_cuts=12, spacing='auto'):
     """ Find 'good' cross-section slicing positions along a given axis.
 
@@ -151,16 +185,23 @@
     less than 'spacing' will be returned.
     """
 
-    assert direction in 'xyz'
-
+    # misc
+    if not direction in 'xyz':
+        raise ValueError(
+            "'direction' must be one of 'x', 'y', or 'z'. Got '%s'" % (
+                direction))
     axis = 'xyz'.index(direction)
-
     affine = img.get_affine()
     orig_data = np.abs(img.get_data())
     this_shape = orig_data.shape[axis]
+
+    # BF issue #575: Return all the slices along and axis if this axis
+    # is the display mode and there are at least as many requested
+    # n_slices as there are slices.
     if n_cuts > this_shape:
-        raise ValueError('Too many cuts requested for the data: '
-                         'n_cuts=%i, data size=%i' % (n_cuts, this_shape))
+        warnings.warn('Too many cuts requested for the data: '
+                      'n_cuts=%i, data size=%i' % (n_cuts, this_shape))
+        return _transform_cut_coords(np.arange(this_shape), direction, affine)
 
     data = orig_data.copy()
     if data.dtype.kind == 'i':
@@ -227,14 +268,4 @@
     cut_coords = np.array(cut_coords)
     cut_coords.sort()
 
-    # Transform this back in image space
-    kwargs = dict()
-    for name in 'xyz':
-        kwargs[name] = np.zeros(len(cut_coords))
-    kwargs[direction] = cut_coords
-    kwargs['affine'] = affine
-
-    cut_coords = coord_transform(**kwargs)[axis]
-    # We need to atleast_1d to make sure that when n_cuts is 1 we do
-    # get an iterable
-    return np.atleast_1d(cut_coords)
+    return _transform_cut_coords(cut_coords, direction, affine)

{"golden_diff": "diff --git a/nilearn/plotting/find_cuts.py b/nilearn/plotting/find_cuts.py\n--- a/nilearn/plotting/find_cuts.py\n+++ b/nilearn/plotting/find_cuts.py\n@@ -5,6 +5,7 @@\n # Author: Gael Varoquaux\n # License: BSD\n \n+import warnings\n import numpy as np\n from scipy import ndimage\n \n@@ -123,6 +124,39 @@\n     return (xmin, xmax), (ymin, ymax), (zmin, zmax)\n \n \n+def _transform_cut_coords(cut_coords, direction, affine):\n+    \"\"\"Transforms cut_coords back in image space\n+\n+    Parameters\n+    ----------\n+    cut_coords: 1D array of length n_cuts\n+        The coordinates to be transformed.\n+\n+    direction: string, optional (default \"z\")\n+        sectional direction; possible values are \"x\", \"y\", or \"z\"\n+\n+    affine: 2D array of shape (4, 4)\n+        The affine for the image.\n+\n+    Returns\n+    -------\n+    cut_coords: 1D array of length n_cuts\n+       The original cut_coords transformed image space.\n+    \"\"\"\n+    # make kwargs\n+    axis = 'xyz'.index(direction)\n+    kwargs = {}\n+    for name in 'xyz':\n+        kwargs[name] = np.zeros(len(cut_coords))\n+    kwargs[direction] = cut_coords\n+    kwargs['affine'] = affine\n+\n+    # We need atleast_1d to make sure that when n_cuts is 1 we do\n+    # get an iterable\n+    cut_coords = coord_transform(**kwargs)[axis]\n+    return np.atleast_1d(cut_coords)\n+\n+\n def find_cut_slices(img, direction='z', n_cuts=12, spacing='auto'):\n     \"\"\" Find 'good' cross-section slicing positions along a given axis.\n \n@@ -151,16 +185,23 @@\n     less than 'spacing' will be returned.\n     \"\"\"\n \n-    assert direction in 'xyz'\n-\n+    # misc\n+    if not direction in 'xyz':\n+        raise ValueError(\n+            \"'direction' must be one of 'x', 'y', or 'z'. Got '%s'\" % (\n+                direction))\n     axis = 'xyz'.index(direction)\n-\n     affine = img.get_affine()\n     orig_data = np.abs(img.get_data())\n     this_shape = orig_data.shape[axis]\n+\n+    # BF issue #575: Return all the slices along and axis if this axis\n+    # is the display mode and there are at least as many requested\n+    # n_slices as there are slices.\n     if n_cuts > this_shape:\n-        raise ValueError('Too many cuts requested for the data: '\n-                         'n_cuts=%i, data size=%i' % (n_cuts, this_shape))\n+        warnings.warn('Too many cuts requested for the data: '\n+                      'n_cuts=%i, data size=%i' % (n_cuts, this_shape))\n+        return _transform_cut_coords(np.arange(this_shape), direction, affine)\n \n     data = orig_data.copy()\n     if data.dtype.kind == 'i':\n@@ -227,14 +268,4 @@\n     cut_coords = np.array(cut_coords)\n     cut_coords.sort()\n \n-    # Transform this back in image space\n-    kwargs = dict()\n-    for name in 'xyz':\n-        kwargs[name] = np.zeros(len(cut_coords))\n-    kwargs[direction] = cut_coords\n-    kwargs['affine'] = affine\n-\n-    cut_coords = coord_transform(**kwargs)[axis]\n-    # We need to atleast_1d to make sure that when n_cuts is 1 we do\n-    # get an iterable\n-    return np.atleast_1d(cut_coords)\n+    return _transform_cut_coords(cut_coords, direction, affine)\n", "issue": "plot_stat_map (and probably plot_*) fails when display_mode axis has singleton dimension\nFuzzing the plotting code, I find the following testcase fails\n\n```\n    for axis, direction in enumerate(\"xyz\"):\n        shape = [5, 6, 7]\n        shape[axis] = 1\n        img = nibabel.Nifti1Image(np.ones(shape), np.eye(4))\n        plot_stat_map(img, None, display_mode=direction)\n```\n\n`ValueError: Too many cuts requested for the data: n_cuts=7, data size=1`\n\nThe culprit is the find_cut_slices function.\n\nA fix would be to return all the slices along the axis if there are at least as many requested n_slices as there are slices.\n\n", "before_files": [{"content": "\"\"\"\nTools to find activations and cut on maps\n\"\"\"\n\n# Author: Gael Varoquaux\n# License: BSD\n\nimport numpy as np\nfrom scipy import ndimage\n\n# Local imports\nfrom .._utils.ndimage import largest_connected_component\nfrom .._utils import new_img_like\nfrom .._utils.extmath import fast_abs_percentile\nfrom .._utils.numpy_conversions import as_ndarray\nfrom ..image.resampling import get_mask_bounds, coord_transform\nfrom ..image.image import _smooth_array\n\n################################################################################\n# Functions for automatic choice of cuts coordinates\n################################################################################\n\n\ndef find_xyz_cut_coords(img, mask=None, activation_threshold=None):\n    \"\"\" Find the center of the largest activation connected component.\n\n        Parameters\n        -----------\n        img : 3D Nifti1Image\n            The brain map.\n        mask : 3D ndarray, boolean, optional\n            An optional brain mask.\n        activation_threshold : float, optional\n            The lower threshold to the positive activation. If None, the\n            activation threshold is computed using the 80% percentile of\n            the absolute value of the map.\n\n        Returns\n        -------\n        x : float\n            the x world coordinate.\n        y : float\n            the y world coordinate.\n        z : float\n            the z world coordinate.\n    \"\"\"\n    data = img.get_data()\n    # To speed up computations, we work with partial views of the array,\n    # and keep track of the offset\n    offset = np.zeros(3)\n\n    # Deal with masked arrays:\n    if hasattr(data, 'mask'):\n        not_mask = np.logical_not(data.mask)\n        if mask is None:\n            mask = not_mask\n        else:\n            mask *= not_mask\n        data = np.asarray(data)\n\n    # Get rid of potential memmapping\n    data = as_ndarray(data)\n    my_map = data.copy()\n    if mask is not None:\n        slice_x, slice_y, slice_z = ndimage.find_objects(mask)[0]\n        my_map = my_map[slice_x, slice_y, slice_z]\n        mask = mask[slice_x, slice_y, slice_z]\n        my_map *= mask\n        offset += [slice_x.start, slice_y.start, slice_z.start]\n\n    # Testing min and max is faster than np.all(my_map == 0)\n    if (my_map.max() == 0) and (my_map.min() == 0):\n        return .5 * np.array(data.shape)\n    if activation_threshold is None:\n        activation_threshold = fast_abs_percentile(my_map[my_map != 0].ravel(),\n                                                   80)\n    mask = np.abs(my_map) > activation_threshold - 1.e-15\n    # mask may be zero everywhere in rare cases\n    if mask.max() == 0:\n        return .5 * np.array(data.shape)\n    mask = largest_connected_component(mask)\n    slice_x, slice_y, slice_z = ndimage.find_objects(mask)[0]\n    my_map = my_map[slice_x, slice_y, slice_z]\n    mask = mask[slice_x, slice_y, slice_z]\n    my_map *= mask\n    offset += [slice_x.start, slice_y.start, slice_z.start]\n\n    # For the second threshold, we use a mean, as it is much faster,\n    # althought it is less robust\n    second_threshold = np.abs(np.mean(my_map[mask]))\n    second_mask = (np.abs(my_map) > second_threshold)\n    if second_mask.sum() > 50:\n        my_map *= largest_connected_component(second_mask)\n    cut_coords = ndimage.center_of_mass(np.abs(my_map))\n    x_map, y_map, z_map = cut_coords + offset\n\n    # Return as a list of scalars\n    return np.asarray(coord_transform(x_map, y_map, z_map,\n                                      img.get_affine())).tolist()\n\n\ndef _get_auto_mask_bounds(img):\n    \"\"\" Compute the bounds of the data with an automaticaly computed mask\n    \"\"\"\n    data = img.get_data().copy()\n    affine = img.get_affine()\n    if hasattr(data, 'mask'):\n        # Masked array\n        mask = np.logical_not(data.mask)\n        data = np.asarray(data)\n    else:\n        # The mask will be anything that is fairly different\n        # from the values in the corners\n        edge_value = float(data[0, 0, 0] + data[0, -1, 0]\n                            + data[-1, 0, 0] + data[0, 0, -1]\n                            + data[-1, -1, 0] + data[-1, 0, -1]\n                            + data[0, -1, -1] + data[-1, -1, -1]\n                        )\n        edge_value /= 6\n        mask = np.abs(data - edge_value) > .005*data.ptp()\n    xmin, xmax, ymin, ymax, zmin, zmax = \\\n            get_mask_bounds(new_img_like(img, mask, affine))\n    return (xmin, xmax), (ymin, ymax), (zmin, zmax)\n\n\ndef find_cut_slices(img, direction='z', n_cuts=12, spacing='auto'):\n    \"\"\" Find 'good' cross-section slicing positions along a given axis.\n\n    Parameters\n    ----------\n    img: 3D Nifti1Image\n        the brain map\n    direction: string, optional (default \"z\")\n        sectional direction; possible values are \"x\", \"y\", or \"z\"\n    n_cuts: int, optional (default 12)\n        number of cuts in the plot\n    spacing: 'auto' or int, optional (default 'auto')\n        minimum spacing between cuts (in voxels, not milimeters)\n        if 'auto', the spacing is .5 / n_cuts * img_length\n\n    Returns\n    -------\n    cut_coords: 1D array of length n_cuts\n        the computed cut_coords\n\n    Notes\n    -----\n    This code works by iteratively locating peak activations that are\n    separated by a distance of at least 'spacing'. If n_cuts is very\n    large and all the activated regions are covered, cuts with a spacing\n    less than 'spacing' will be returned.\n    \"\"\"\n\n    assert direction in 'xyz'\n\n    axis = 'xyz'.index(direction)\n\n    affine = img.get_affine()\n    orig_data = np.abs(img.get_data())\n    this_shape = orig_data.shape[axis]\n    if n_cuts > this_shape:\n        raise ValueError('Too many cuts requested for the data: '\n                         'n_cuts=%i, data size=%i' % (n_cuts, this_shape))\n\n    data = orig_data.copy()\n    if data.dtype.kind == 'i':\n        data = data.astype(np.float)\n\n    data = _smooth_array(data, affine, fwhm='fast')\n\n    if spacing == 'auto':\n        spacing = max(int(.5 / n_cuts * data.shape[axis]), 1)\n\n    slices = [slice(None, None), slice(None, None), slice(None, None)]\n\n    cut_coords = list()\n\n    for _ in range(n_cuts):\n        # Find a peak\n        max_along_axis = np.unravel_index(np.abs(data).argmax(),\n                                          data.shape)[axis]\n\n        # cancel out the surroundings of the peak\n        start = max(0, max_along_axis - spacing)\n        stop = max_along_axis + spacing\n        slices[axis] = slice(start, stop)\n        # We don't actually fully zero the neighborhood, to avoid ending\n        # up with fully zeros if n_cuts is too big: we can do multiple\n        # passes on the data\n        data[slices] *= 1.e-3\n\n        cut_coords.append(max_along_axis)\n\n    # We sometimes get duplicated cuts, so we add cuts at the beginning\n    # and the end\n    cut_coords = np.unique(cut_coords).tolist()\n    while len(cut_coords) < n_cuts:\n        # Candidates for new cuts:\n        slice_below = min(cut_coords) - 2\n        slice_above = max(cut_coords) + 2\n        candidates = [slice_above]\n        # One slice where there is the biggest gap in the existing\n        # cut_coords\n        if len(cut_coords) > 1:\n            middle_idx = np.argmax(np.diff(cut_coords))\n            slice_middle = int(.5 * (cut_coords[middle_idx]\n                                    + cut_coords[middle_idx + 1]))\n            if not slice_middle in cut_coords:\n                candidates.append(slice_middle)\n        if slice_below >= 0:\n            # We need positive slice to avoid having negative\n            # indices, which would work, but not the way we think of them\n            candidates.append(slice_below)\n        best_weight = -10\n        for candidate in candidates:\n            if candidate >= this_shape:\n                this_weight = 0\n            else:\n                this_weight = np.sum(np.rollaxis(orig_data, axis)[candidate])\n            if this_weight > best_weight:\n                best_candidate = candidate\n                best_weight = this_weight\n\n        cut_coords.append(best_candidate)\n        cut_coords = np.unique(cut_coords).tolist()\n\n    cut_coords = np.array(cut_coords)\n    cut_coords.sort()\n\n    # Transform this back in image space\n    kwargs = dict()\n    for name in 'xyz':\n        kwargs[name] = np.zeros(len(cut_coords))\n    kwargs[direction] = cut_coords\n    kwargs['affine'] = affine\n\n    cut_coords = coord_transform(**kwargs)[axis]\n    # We need to atleast_1d to make sure that when n_cuts is 1 we do\n    # get an iterable\n    return np.atleast_1d(cut_coords)\n", "path": "nilearn/plotting/find_cuts.py"}], "after_files": [{"content": "\"\"\"\nTools to find activations and cut on maps\n\"\"\"\n\n# Author: Gael Varoquaux\n# License: BSD\n\nimport warnings\nimport numpy as np\nfrom scipy import ndimage\n\n# Local imports\nfrom .._utils.ndimage import largest_connected_component\nfrom .._utils import new_img_like\nfrom .._utils.extmath import fast_abs_percentile\nfrom .._utils.numpy_conversions import as_ndarray\nfrom ..image.resampling import get_mask_bounds, coord_transform\nfrom ..image.image import _smooth_array\n\n################################################################################\n# Functions for automatic choice of cuts coordinates\n################################################################################\n\n\ndef find_xyz_cut_coords(img, mask=None, activation_threshold=None):\n    \"\"\" Find the center of the largest activation connected component.\n\n        Parameters\n        -----------\n        img : 3D Nifti1Image\n            The brain map.\n        mask : 3D ndarray, boolean, optional\n            An optional brain mask.\n        activation_threshold : float, optional\n            The lower threshold to the positive activation. If None, the\n            activation threshold is computed using the 80% percentile of\n            the absolute value of the map.\n\n        Returns\n        -------\n        x : float\n            the x world coordinate.\n        y : float\n            the y world coordinate.\n        z : float\n            the z world coordinate.\n    \"\"\"\n    data = img.get_data()\n    # To speed up computations, we work with partial views of the array,\n    # and keep track of the offset\n    offset = np.zeros(3)\n\n    # Deal with masked arrays:\n    if hasattr(data, 'mask'):\n        not_mask = np.logical_not(data.mask)\n        if mask is None:\n            mask = not_mask\n        else:\n            mask *= not_mask\n        data = np.asarray(data)\n\n    # Get rid of potential memmapping\n    data = as_ndarray(data)\n    my_map = data.copy()\n    if mask is not None:\n        slice_x, slice_y, slice_z = ndimage.find_objects(mask)[0]\n        my_map = my_map[slice_x, slice_y, slice_z]\n        mask = mask[slice_x, slice_y, slice_z]\n        my_map *= mask\n        offset += [slice_x.start, slice_y.start, slice_z.start]\n\n    # Testing min and max is faster than np.all(my_map == 0)\n    if (my_map.max() == 0) and (my_map.min() == 0):\n        return .5 * np.array(data.shape)\n    if activation_threshold is None:\n        activation_threshold = fast_abs_percentile(my_map[my_map != 0].ravel(),\n                                                   80)\n    mask = np.abs(my_map) > activation_threshold - 1.e-15\n    # mask may be zero everywhere in rare cases\n    if mask.max() == 0:\n        return .5 * np.array(data.shape)\n    mask = largest_connected_component(mask)\n    slice_x, slice_y, slice_z = ndimage.find_objects(mask)[0]\n    my_map = my_map[slice_x, slice_y, slice_z]\n    mask = mask[slice_x, slice_y, slice_z]\n    my_map *= mask\n    offset += [slice_x.start, slice_y.start, slice_z.start]\n\n    # For the second threshold, we use a mean, as it is much faster,\n    # althought it is less robust\n    second_threshold = np.abs(np.mean(my_map[mask]))\n    second_mask = (np.abs(my_map) > second_threshold)\n    if second_mask.sum() > 50:\n        my_map *= largest_connected_component(second_mask)\n    cut_coords = ndimage.center_of_mass(np.abs(my_map))\n    x_map, y_map, z_map = cut_coords + offset\n\n    # Return as a list of scalars\n    return np.asarray(coord_transform(x_map, y_map, z_map,\n                                      img.get_affine())).tolist()\n\n\ndef _get_auto_mask_bounds(img):\n    \"\"\" Compute the bounds of the data with an automaticaly computed mask\n    \"\"\"\n    data = img.get_data().copy()\n    affine = img.get_affine()\n    if hasattr(data, 'mask'):\n        # Masked array\n        mask = np.logical_not(data.mask)\n        data = np.asarray(data)\n    else:\n        # The mask will be anything that is fairly different\n        # from the values in the corners\n        edge_value = float(data[0, 0, 0] + data[0, -1, 0]\n                            + data[-1, 0, 0] + data[0, 0, -1]\n                            + data[-1, -1, 0] + data[-1, 0, -1]\n                            + data[0, -1, -1] + data[-1, -1, -1]\n                        )\n        edge_value /= 6\n        mask = np.abs(data - edge_value) > .005*data.ptp()\n    xmin, xmax, ymin, ymax, zmin, zmax = \\\n            get_mask_bounds(new_img_like(img, mask, affine))\n    return (xmin, xmax), (ymin, ymax), (zmin, zmax)\n\n\ndef _transform_cut_coords(cut_coords, direction, affine):\n    \"\"\"Transforms cut_coords back in image space\n\n    Parameters\n    ----------\n    cut_coords: 1D array of length n_cuts\n        The coordinates to be transformed.\n\n    direction: string, optional (default \"z\")\n        sectional direction; possible values are \"x\", \"y\", or \"z\"\n\n    affine: 2D array of shape (4, 4)\n        The affine for the image.\n\n    Returns\n    -------\n    cut_coords: 1D array of length n_cuts\n       The original cut_coords transformed image space.\n    \"\"\"\n    # make kwargs\n    axis = 'xyz'.index(direction)\n    kwargs = {}\n    for name in 'xyz':\n        kwargs[name] = np.zeros(len(cut_coords))\n    kwargs[direction] = cut_coords\n    kwargs['affine'] = affine\n\n    # We need atleast_1d to make sure that when n_cuts is 1 we do\n    # get an iterable\n    cut_coords = coord_transform(**kwargs)[axis]\n    return np.atleast_1d(cut_coords)\n\n\ndef find_cut_slices(img, direction='z', n_cuts=12, spacing='auto'):\n    \"\"\" Find 'good' cross-section slicing positions along a given axis.\n\n    Parameters\n    ----------\n    img: 3D Nifti1Image\n        the brain map\n    direction: string, optional (default \"z\")\n        sectional direction; possible values are \"x\", \"y\", or \"z\"\n    n_cuts: int, optional (default 12)\n        number of cuts in the plot\n    spacing: 'auto' or int, optional (default 'auto')\n        minimum spacing between cuts (in voxels, not milimeters)\n        if 'auto', the spacing is .5 / n_cuts * img_length\n\n    Returns\n    -------\n    cut_coords: 1D array of length n_cuts\n        the computed cut_coords\n\n    Notes\n    -----\n    This code works by iteratively locating peak activations that are\n    separated by a distance of at least 'spacing'. If n_cuts is very\n    large and all the activated regions are covered, cuts with a spacing\n    less than 'spacing' will be returned.\n    \"\"\"\n\n    # misc\n    if not direction in 'xyz':\n        raise ValueError(\n            \"'direction' must be one of 'x', 'y', or 'z'. Got '%s'\" % (\n                direction))\n    axis = 'xyz'.index(direction)\n    affine = img.get_affine()\n    orig_data = np.abs(img.get_data())\n    this_shape = orig_data.shape[axis]\n\n    # BF issue #575: Return all the slices along and axis if this axis\n    # is the display mode and there are at least as many requested\n    # n_slices as there are slices.\n    if n_cuts > this_shape:\n        warnings.warn('Too many cuts requested for the data: '\n                      'n_cuts=%i, data size=%i' % (n_cuts, this_shape))\n        return _transform_cut_coords(np.arange(this_shape), direction, affine)\n\n    data = orig_data.copy()\n    if data.dtype.kind == 'i':\n        data = data.astype(np.float)\n\n    data = _smooth_array(data, affine, fwhm='fast')\n\n    if spacing == 'auto':\n        spacing = max(int(.5 / n_cuts * data.shape[axis]), 1)\n\n    slices = [slice(None, None), slice(None, None), slice(None, None)]\n\n    cut_coords = list()\n\n    for _ in range(n_cuts):\n        # Find a peak\n        max_along_axis = np.unravel_index(np.abs(data).argmax(),\n                                          data.shape)[axis]\n\n        # cancel out the surroundings of the peak\n        start = max(0, max_along_axis - spacing)\n        stop = max_along_axis + spacing\n        slices[axis] = slice(start, stop)\n        # We don't actually fully zero the neighborhood, to avoid ending\n        # up with fully zeros if n_cuts is too big: we can do multiple\n        # passes on the data\n        data[slices] *= 1.e-3\n\n        cut_coords.append(max_along_axis)\n\n    # We sometimes get duplicated cuts, so we add cuts at the beginning\n    # and the end\n    cut_coords = np.unique(cut_coords).tolist()\n    while len(cut_coords) < n_cuts:\n        # Candidates for new cuts:\n        slice_below = min(cut_coords) - 2\n        slice_above = max(cut_coords) + 2\n        candidates = [slice_above]\n        # One slice where there is the biggest gap in the existing\n        # cut_coords\n        if len(cut_coords) > 1:\n            middle_idx = np.argmax(np.diff(cut_coords))\n            slice_middle = int(.5 * (cut_coords[middle_idx]\n                                    + cut_coords[middle_idx + 1]))\n            if not slice_middle in cut_coords:\n                candidates.append(slice_middle)\n        if slice_below >= 0:\n            # We need positive slice to avoid having negative\n            # indices, which would work, but not the way we think of them\n            candidates.append(slice_below)\n        best_weight = -10\n        for candidate in candidates:\n            if candidate >= this_shape:\n                this_weight = 0\n            else:\n                this_weight = np.sum(np.rollaxis(orig_data, axis)[candidate])\n            if this_weight > best_weight:\n                best_candidate = candidate\n                best_weight = this_weight\n\n        cut_coords.append(best_candidate)\n        cut_coords = np.unique(cut_coords).tolist()\n\n    cut_coords = np.array(cut_coords)\n    cut_coords.sort()\n\n    return _transform_cut_coords(cut_coords, direction, affine)\n", "path": "nilearn/plotting/find_cuts.py"}]}