Example #1
0
def save_sprite(img,
                output_sprite,
                output_cmap=None,
                output_json=None,
                vmax=None,
                vmin=None,
                cmap='Greys',
                threshold=None,
                n_colors=256,
                format='png',
                resample=True,
                interpolation='nearest'):
    """ Generate a sprite from a 3D Niimg-like object.

        Parameters
        ----------
        img :  Niimg-like object
            See http://nilearn.github.io/manipulating_images/input_output.html
        output_file : string or file-like
            Path string to a filename, or a Python file-like object.
            If *format* is *None* and *fname* is a string, the output
            format is deduced from the extension of the filename.
        output_cmap : string, file-like or None, optional (default None)
            Path string to a filename, or a Python file-like object.
            The color map will be saved in that file (unless it is None).
            If *format* is *None* and *fname* is a string, the output format is
            deduced from the extension of the filename.
        output_json : string, file-like or None, optional (default None)
            Path string to a filename, or a Python file-like object.
            The parameters of the sprite will be saved in that file
            (unless it is None): Y and Z sizes, vmin, vmax, affine transform.
        vmax : float, or None, optional (default None)
            max value for mapping colors.
        vmin : float, or None, optional (default None)
            min value for mapping color.
        cmap : name of a matplotlib colormap, optional (default 'Greys')
            The colormap for the sprite. A matplotlib colormap can also
            be passed directly in cmap.
        threshold : a number, None, or 'auto', optional (default None)
            If None is given, the image is not thresholded.
            If a number is given, it is used to threshold the image:
            values below the threshold (in absolute value) are plotted
            as transparent. If auto is given, the threshold is determined
            magically by analysis of the image.
        n_colors : integer, optional (default 256)
            The number of discrete colors to use in the colormap, if it is
            generated.
        format : string, optional (default 'png')
            One of the file extensions supported by the active backend.  Most
            backends support png, pdf, ps, eps and svg.
        resample : boolean, optional (default True)
            Resample to isotropic voxels, with a LR/AP/VD orientation.
            This is necessary for proper rendering of arbitrary Niimg volumes,
            but not necessary if the image is in an isotropic standard space.
        interpolation : string, optional (default nearest)
            The interpolation method for resampling
            See nilearn.image.resample_img
        black_bg : boolean, optional
            If True, the background of the image is set to be black.

        Returns
        ----------
        sprite : numpy array with the sprite
    """

    # Get cmap
    if isinstance(cm, str):
        cmap = plt.cm.get_cmap(cmap)

    img = check_niimg_3d(img, dtype='auto')

    # resample to isotropic voxel with standard orientation
    if resample:
        img = _resample_to_self(img, interpolation)

    # Read data
    data = _safe_get_data(img, ensure_finite=True)
    if np.isnan(np.sum(data)):
        data = np.nan_to_num(data)

    # Deal with automatic settings of plot parameters
    if threshold == 'auto':
        # Threshold epsilon below a percentile value, to be sure that some
        # voxels pass the threshold
        threshold = fast_abs_percentile(data) - 1e-5

    # threshold
    threshold = float(threshold) if threshold is not None else None

    # Get vmin vmax
    show_nan_msg = False
    if vmax is not None and np.isnan(vmax):
        vmax = None
        show_nan_msg = True
    if vmin is not None and np.isnan(vmin):
        vmin = None
        show_nan_msg = True
    if show_nan_msg:
        nan_msg = ('NaN is not permitted for the vmax and vmin arguments.\n'
                   'Tip: Use np.nanmax() instead of np.max().')
        warnings.warn(nan_msg)

    if vmax is None:
        vmax = np.nanmax(data)
    if vmin is None:
        vmin = np.nanmin(data)

    # Create sprite
    sprite = _data2sprite(data)

    # Mask sprite
    if threshold is not None:
        if threshold == 0:
            sprite = np.ma.masked_equal(sprite, 0, copy=False)
        else:
            sprite = np.ma.masked_inside(sprite,
                                         -threshold,
                                         threshold,
                                         copy=False)
    # Save the sprite
    imsave(output_sprite,
           sprite,
           vmin=vmin,
           vmax=vmax,
           cmap=cmap,
           format=format)

    # Save the parameters
    if type(vmin).__module__ == 'numpy':
        vmin = vmin.tolist()  # json does not deal with numpy array
    if type(vmax).__module__ == 'numpy':
        vmax = vmax.tolist()  # json does not deal with numpy array

    if output_json is not None:
        params = {
            'nbSlice': {
                'X': data.shape[0],
                'Y': data.shape[1],
                'Z': data.shape[2]
            },
            'min': vmin,
            'max': vmax,
            'affine': img.affine.tolist()
        }
        if isinstance(output_json, str):
            f = open(output_json, 'w')
            f.write(json.dumps(params))
            f.close()
        else:
            output_json.write(json.dumps(params))

    # save the colormap
    if output_cmap is not None:
        data = np.arange(0, n_colors) / (n_colors - 1)
        data = data.reshape([1, n_colors])
        imsave(output_cmap, data, cmap=cmap, format=format)

    return sprite
Example #2
0
def find_cut_coords(img, mask=None, activation_threshold=None):
    import warnings
    import numpy as np
    from scipy import ndimage
    from nilearn._utils import as_ndarray, new_img_like
    from nilearn._utils.ndimage import largest_connected_component
    from nilearn._utils.extmath import fast_abs_percentile
    """ Find the center of the largest activation connected component.
        Parameters
        -----------
        img : 3D Nifti1Image
            The brain map.
        mask : 3D ndarray, boolean, optional
            An optional brain mask.
        activation_threshold : float, optional
            The lower threshold to the positive activation. If None, the
            activation threshold is computed using the 80% percentile of
            the absolute value of the map.
        Returns
        -------
        x : float
            the x world coordinate.
        y : float
            the y world coordinate.
        z : float
            the z world coordinate.
    """
    data = img.get_data()
    # To speed up computations, we work with partial views of the array,
    # and keep track of the offset
    offset = np.zeros(3)

    # Deal with masked arrays:
    if hasattr(data, 'mask'):
        not_mask = np.logical_not(data.mask)
        if mask is None:
            mask = not_mask
        else:
            mask *= not_mask
        data = np.asarray(data)

    # Get rid of potential memmapping
    data = as_ndarray(data)
    my_map = data.copy()
    if mask is not None:
        slice_x, slice_y, slice_z = ndimage.find_objects(mask)[0]
        my_map = my_map[slice_x, slice_y, slice_z]
        mask = mask[slice_x, slice_y, slice_z]
        my_map *= mask
        offset += [slice_x.start, slice_y.start, slice_z.start]

    # Testing min and max is faster than np.all(my_map == 0)
    if (my_map.max() == 0) and (my_map.min() == 0):
        return .5 * np.array(data.shape)
    if activation_threshold is None:
        activation_threshold = fast_abs_percentile(my_map[my_map != 0].ravel(),
                                                   80)
    mask = np.abs(my_map) > activation_threshold - 1.e-15
    # mask may be zero everywhere in rare cases
    if mask.max() == 0:
        return .5 * np.array(data.shape)
    mask = largest_connected_component(mask)
    slice_x, slice_y, slice_z = ndimage.find_objects(mask)[0]
    my_map = my_map[slice_x, slice_y, slice_z]
    mask = mask[slice_x, slice_y, slice_z]
    my_map *= mask
    offset += [slice_x.start, slice_y.start, slice_z.start]

    # For the second threshold, we use a mean, as it is much faster,
    # althought it is less robust
    second_threshold = np.abs(np.mean(my_map[mask]))
    second_mask = (np.abs(my_map) > second_threshold)
    if second_mask.sum() > 50:
        my_map *= largest_connected_component(second_mask)
    cut_coords = ndimage.center_of_mass(np.abs(my_map))
    x_map, y_map, z_map = cut_coords + offset

    coords = []
    coords.append(x_map)
    coords.append(y_map)
    coords.append(z_map)

    # Return as a list of scalars
    return coords
Example #3
0
def find_cut_coords(img, mask=None, activation_threshold=None):
    import warnings
    import numpy as np
    from scipy import ndimage
    from nilearn._utils import as_ndarray, new_img_like
    from nilearn._utils.ndimage import largest_connected_component
    from nilearn._utils.extmath import fast_abs_percentile
    """ Find the center of the largest activation connected component.
        Parameters
        -----------
        img : 3D Nifti1Image
            The brain map.
        mask : 3D ndarray, boolean, optional
            An optional brain mask.
        activation_threshold : float, optional
            The lower threshold to the positive activation. If None, the
            activation threshold is computed using the 80% percentile of
            the absolute value of the map.
        Returns
        -------
        x : float
            the x world coordinate.
        y : float
            the y world coordinate.
        z : float
            the z world coordinate.
    """
    data = img.get_data()
    # To speed up computations, we work with partial views of the array,
    # and keep track of the offset
    offset = np.zeros(3)

    # Deal with masked arrays:
    if hasattr(data, 'mask'):
        not_mask = np.logical_not(data.mask)
        if mask is None:
            mask = not_mask
        else:
            mask *= not_mask
        data = np.asarray(data)

    # Get rid of potential memmapping
    data = as_ndarray(data)
    my_map = data.copy()
    if mask is not None:
        slice_x, slice_y, slice_z = ndimage.find_objects(mask)[0]
        my_map = my_map[slice_x, slice_y, slice_z]
        mask = mask[slice_x, slice_y, slice_z]
        my_map *= mask
        offset += [slice_x.start, slice_y.start, slice_z.start]

    # Testing min and max is faster than np.all(my_map == 0)
    if (my_map.max() == 0) and (my_map.min() == 0):
        return .5 * np.array(data.shape)
    if activation_threshold is None:
        activation_threshold = fast_abs_percentile(my_map[my_map != 0].ravel(),
                                                   80)
    mask = np.abs(my_map) > activation_threshold - 1.e-15
    # mask may be zero everywhere in rare cases
    if mask.max() == 0:
        return .5 * np.array(data.shape)
    mask = largest_connected_component(mask)
    slice_x, slice_y, slice_z = ndimage.find_objects(mask)[0]
    my_map = my_map[slice_x, slice_y, slice_z]
    mask = mask[slice_x, slice_y, slice_z]
    my_map *= mask
    offset += [slice_x.start, slice_y.start, slice_z.start]

    # For the second threshold, we use a mean, as it is much faster,
    # althought it is less robust
    second_threshold = np.abs(np.mean(my_map[mask]))
    second_mask = (np.abs(my_map) > second_threshold)
    if second_mask.sum() > 50:
        my_map *= largest_connected_component(second_mask)
    cut_coords = ndimage.center_of_mass(np.abs(my_map))
    x_map, y_map, z_map = cut_coords + offset

    coords = []
    coords.append(x_map)
    coords.append(y_map)
    coords.append(z_map)

    # Return as a list of scalars
    return coords
Example #4
0
def test_fast_abs_percentile_no_index_error():
    # check the offending low-level function
    fast_abs_percentile(np.arange(4))
Example #5
0
def test_fast_abs_percentile():
    data = np.arange(1, 100)
    for p in range(10, 100, 10):
        yield nose.tools.assert_equal, fast_abs_percentile(data, p - 1), p
Example #6
0
def test_fast_abs_percentile():
    rng = check_random_state(1)
    data = np.arange(100)
    rng.shuffle(data)
    for p in data:
        yield nose.tools.assert_equal, fast_abs_percentile(data, p), p
Example #7
0
def plot_full_surf_stat_map(stat,
                            title=None,
                            ts=None,
                            mask=None,
                            inflate=False,
                            outfile=None,
                            add_colorbar=True,
                            vmax=None,
                            **kwargs):
    """Use nilearn's plot_surf_stat_map to plot volume data in the surface.
    Plots a collage of both hemispheres and both medial and lateral views of
    the brain. The surface mesh used for plotting is freesurfer's fsaverage.

    :param stat: A 3D statistical map (Nilearn's niimg object)
    :param title: A title for the image
    :param ts: Optional timeseries to be plotted in the background.
    :param mask: Optional mask passed to nilearn's vol_to_surf.
    :param inflate: If True, plot on inflated, if False, on pial.
    :param outfile: Optional output filename to save figure.
    :param vmax: Colormap vmax limit

    Other kwargs are passed to Nilearn's plot_surf_stat_map.
    """

    fig, axes = plt.subplots(dpi=100,
                             nrows=2,
                             ncols=2,
                             subplot_kw={'projection': '3d'})
    ((ax_ll, ax_rl), (ax_lm, ax_rm)) = axes

    # Compute the surface textures from the statistical map.
    texture_r = surface.vol_to_surf(stat, FSAVERAGE.pial_right, mask_img=mask)
    texture_l = surface.vol_to_surf(stat, FSAVERAGE.pial_left, mask_img=mask)

    # Vmax scaled for optimal dynamic range.
    if vmax is None:
        vmax = fast_abs_percentile(stat.dataobj, 99.8)

    # Plot on inflated brain or on pial surface?
    if inflate:
        leftsurf = FSAVERAGE.infl_left
        rightsurf = FSAVERAGE.infl_right
    else:
        leftsurf = FSAVERAGE.pial_left
        rightsurf = FSAVERAGE.pial_right

    plotting.plot_surf_stat_map(rightsurf,
                                texture_r,
                                colorbar=False,
                                hemi='right',
                                axes=ax_rl,
                                bg_map=FSAVERAGE.sulc_right,
                                vmax=vmax,
                                **kwargs)
    plotting.plot_surf_stat_map(rightsurf,
                                texture_r,
                                colorbar=False,
                                hemi='right',
                                view='medial',
                                axes=ax_rm,
                                bg_map=FSAVERAGE.sulc_right,
                                vmax=vmax,
                                **kwargs)

    plotting.plot_surf_stat_map(leftsurf,
                                texture_l,
                                colorbar=False,
                                hemi='left',
                                axes=ax_ll,
                                bg_map=FSAVERAGE.sulc_left,
                                vmax=vmax,
                                **kwargs)
    plotting.plot_surf_stat_map(leftsurf,
                                texture_l,
                                colorbar=False,
                                hemi='left',
                                view='medial',
                                axes=ax_lm,
                                bg_map=FSAVERAGE.sulc_left,
                                vmax=vmax,
                                **kwargs)

    # The default camera distance in the 3D plot makes the surfaces look small.
    # The fix is simple, bring the camera closer to the object.
    for ax in axes.flatten():
        ax.dist = 6
        # Alpha set to 0 so that the timeseries is visible.
        ax.patch.set_alpha(0.)
    # Remove whitespace between subplots.
    fig.subplots_adjust(wspace=-0.02, hspace=0.0)

    if ts is not None:
        # x0, y0, width, height = 0.34, 0.465, 0.38, 0.06
        # x0 left -> right, y0 top -> down.
        x0, y0 = 0.15, 0.445
        width, height = (1.05 - 2 * x0), 0.12
        ax5 = fig.add_axes([x0, y0, width, height], zorder=-1)
        ax5.plot(ts[::2], 'dimgray', linewidth=0.8)
        ax5.axis('off')
        # Only necessary if ax5 is on top. (zorder larger than other axes)
        # ax5.patch.set_alpha(0.)

    # Add colorbar
    if add_colorbar:
        if 'threshold' in kwargs:
            if kwargs['threshold'] is not None:
                threshold = kwargs['threshold']
            else:
                threshold = 0

        vmin = -vmax  # when also displaying negative values, change to -vmax
        if 'cmap' in kwargs:
            cmap = nilearn_cmaps[kwargs['cmap']]
        else:
            cmap = nilearn_cmaps['cold_hot']

        norm = Normalize(vmin=vmin, vmax=vmax)
        cmaplist = [cmap(i) for i in range(cmap.N)]
        # set colors to grey for absolute values < threshold
        istart = int(norm(-threshold, clip=True) * (cmap.N - 1))
        istop = int(norm(threshold, clip=True) * (cmap.N - 1))
        for i in range(istart, istop):
            cmaplist[i] = (0.5, 0.5, 0.5, 1.)
        our_cmap = LinearSegmentedColormap.from_list('Custom cmap', cmaplist,
                                                     cmap.N)
        sm = plt.cm.ScalarMappable(cmap=our_cmap,
                                   norm=plt.Normalize(vmin=vmin, vmax=vmax))
        # fake up the array of the scalar mappable.
        sm._A = []
        # fig.subplots_adjust(bottom=0.05)
        cbar_ax = fig.add_subplot(32, 1,
                                  32)  # fig.add_axes([0.3, 0.9, 0.4, 0.03])
        fig.colorbar(sm, cax=cbar_ax, orientation='horizontal')

    if title is not None:
        # y defaults to 0.98. The value of 0.93 lowers it a bit.
        fig.suptitle(title, fontsize=12, y=0.93)

    if outfile is not None:
        plt.savefig(outfile, dpi=100, bbox_inches='tight')
Example #8
0
def test_fast_abs_percentile_no_index_error():
    # check the offending low-level function
    fast_abs_percentile(np.arange(4))
Example #9
0
def test_fast_abs_percentile():
    rng = check_random_state(1)
    data = np.arange(100)
    rng.shuffle(data)
    for p in data:
        yield nose.tools.assert_equal, fast_abs_percentile(data, p), p
Example #10
0
def test_fast_abs_percentile():
    data = np.arange(1, 100)
    for p in range(10, 100, 10):
        yield nose.tools.assert_equal, fast_abs_percentile(data, p - 1), p