Source code for timagetk.visu.nuclei

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#  Copyright (c) 2022 Univ. Lyon, ENS de Lyon, UCB Lyon 1, CNRS, INRAe, Inria
#  All rights reserved.
#  This file is part of the TimageTK library, and is released under the "GPLv3"
#  license. Please see the LICENSE.md file that should have been included as
#  part of this package.
# ------------------------------------------------------------------------------

import matplotlib.pyplot as plt

from timagetk.components.multi_channel import MultiChannelImage
from timagetk.components.spatial_image import SpatialImage
from timagetk.visu.mplt import image_plot


def _2d_nuclei_scatter(ax, nuclei_array, nuclei_color, signal_name, x_extent, y_extent, cmap='viridis'):
    """sub-function to create a 2D scatter plot of colored nuclei.

    Parameters
    ----------
    ax : matplotlib.axes.Axes
        Use it to combine plots in the same sub-figure
    nuclei_array : numpy.ndarray
        The X,Y(,Z) coordinates of the nuclei.
    nuclei_color : numpy.ndarray
        The color to use for nuclei, can be a label or a signal, should be sorted as `nuclei_array`
    signal_name : str
        The name of the nuclei targeted signal.
    x_extent : int or float
        The extent of the x-axis.
    y_extent : int or float
        The extent of the y-axis.

    Returns
    -------
    matplotlib.axes.Axes
        The updated `ax` ``Axes`` instance.

    """
    fig_ax = ax.scatter(nuclei_array[:, 0], nuclei_array[:, 1], c=nuclei_color, cmap=cmap)
    ax.set_xlim(0, x_extent)  # scale the x-axis
    ax.set_ylim(y_extent, 0)  # invert and scale the y-axis
    ax.set_aspect("equal")  # set same unit size for x and y axes
    ax.xaxis.tick_top()  # and move the X-axis ticks to top
    ax.set_title(signal_name)
    cbar_sc = plt.colorbar(fig_ax, ax=ax, shrink=0.85)
    cbar_sc.minorticks_on()
    return fig_ax


[docs] def channel_signal(nuclei_array, nuclei_signal, channel_image, channel_name, cmap='viridis', figname=""): """Create a figure with the channel image and the quantified signals. Parameters ---------- nuclei_array : numpy.ndarray The X,Y(,Z) coordinates of the nuclei. nuclei_signal : numpy.ndarray The quantified nuclei signals. channel_image : timagetk.components.spatial_image.SpatialImage or timagetk.MultiChannelImage The channel intensity image used to quantify the nuclei signal. channel_name : str Name of the channel image. cmap : str or list of str, optional Name of the colormap to use for the nuclei scatter plot, 'viridis' by default. See notes for advised color maps. figname : str or pathlib.Path If a string is given, consider it's a valid file location (path, name & extension) Do not show the figure, just create, write & close. Notes ----- We advise to use the **sequential** color maps, such as: - *Sequential (2)* [mplt_cmap_sequential]_: `'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink', 'summer', 'Wistia'`. - *Perceptually Uniform Sequential* [mplt_cmap_sequential2]_: `'viridis', 'plasma', 'inferno', 'magma', 'cividis'`. To understand the differences in "perception" induced by the different color maps, see: [mplt_cmap_perception]_ Examples -------- >>> from timagetk.visu.nuclei import channel_signal >>> from timagetk.tasks.nuclei_detection import nuclei_detection >>> from timagetk.tasks.nuclei_detection import compute_nuclei_channel_intensities >>> from timagetk.synthetic_data.nuclei_image import example_nuclei_signal_images >>> from timagetk import MultiChannelImage >>> nuclei_img, signal_img = example_nuclei_signal_images(n_points=30, extent=20., signal_type='random') >>> nuclei_arr, _ = nuclei_detection(nuclei_img) >>> image = MultiChannelImage([nuclei_img, signal_img], channel_names=['tag', 'signal']) >>> nuclei_sig, _ = compute_nuclei_channel_intensities(image, nuclei_arr, ['signal']) >>> channel_signal(nuclei_arr, nuclei_sig["signal"], image, "signal", cmap='gray') """ fig = plt.figure(figsize=(20, 9), constrained_layout=True) gs = fig.add_gridspec(1, 2, wspace=0.05, top=0.985, bottom=0.02, left=0.03, right=1.0) if isinstance(channel_image, MultiChannelImage): channel_image = channel_image.get_channel(channel_name) xy_vxs = channel_image.get_voxelsize()[::-1][:2] z_proj_im = channel_image.max(axis=0) ax_img, fig_img = image_plot(SpatialImage(z_proj_im.get_array(), voxelsize=xy_vxs), fig.add_subplot(gs[0, 0]), cmap) ax_img.set_title(channel_name) _ = _2d_nuclei_scatter(fig.add_subplot(gs[0, 1]), nuclei_array, nuclei_signal, channel_name, channel_image.get_extent('x'), channel_image.get_extent('y'), cmap) if figname != "": plt.savefig(figname) plt.close() else: plt.show()
[docs] def nuclei_signals(nuclei_array, nuclei_signals, x_extent, y_extent, cmap='viridis', figname=""): """Create scatter plot(s) of quantified nuclei signal(s). Parameters ---------- nuclei_array : numpy.ndarray The X,Y(,Z) coordinates of the nuclei. nuclei_signals : dict The dictionary of quantified nuclei signals with signal(s) name(s) as key(s). x_extent : int or float The extent of the x-axis. y_extent : int or float The extent of the y-axis. cmap : str or list of str, optional Name of the colormap to use, 'viridis' by default. See notes for advised color maps. figname : str or pathlib.Path If a string is given, consider it's a valid file location (path, name & extension) Do not show the figure, just create, write & close. Notes ----- We advise to use the **sequential** color maps, such as: - *Sequential (2)* [mplt_cmap_sequential]_: `'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink', 'summer', 'Wistia'`. - *Perceptually Uniform Sequential* [mplt_cmap_sequential2]_: `'viridis', 'plasma', 'inferno', 'magma', 'cividis'`. To understand the differences in "perception" induced by the different color maps, see: [mplt_cmap_perception]_ Examples -------- >>> from timagetk.visu.nuclei import nuclei_signals >>> from timagetk.tasks.nuclei_detection import nuclei_detection >>> from timagetk.tasks.nuclei_detection import compute_nuclei_channel_intensities >>> from timagetk.synthetic_data.nuclei_image import example_nuclei_signal_images >>> from timagetk import MultiChannelImage >>> nuclei_img, signal_img = example_nuclei_signal_images(n_points=30, extent=20., signal_type='random') >>> nuclei_arr, _ = nuclei_detection(nuclei_img) >>> image = MultiChannelImage([nuclei_img, signal_img], channel_names=['tag', 'signal']) >>> nuclei_sig, _ = compute_nuclei_channel_intensities(image, nuclei_arr, ['signal']) >>> nuclei_signals(nuclei_arr, nuclei_sig, image.get_extent('x'), image.get_extent('y')) """ n_signals = len(nuclei_signals) fig = plt.figure(figsize=(7 * n_signals, 6), constrained_layout=True) gs = fig.add_gridspec(1, n_signals, wspace=0.05, top=0.985, bottom=0.02, left=0.03, right=1.0) if isinstance(cmap, list): try: assert len(cmap) == n_signals except AssertionError: raise ValueError(f"You gave {len(cmap)} colormaps for {n_signals} quantified nuclei signals!") else: cmap = [cmap] * n_signals for s_id, (sig_name, signal) in enumerate(nuclei_signals.items()): _ = _2d_nuclei_scatter(fig.add_subplot(gs[0, s_id]), nuclei_array, signal, sig_name, x_extent, y_extent, cmap[s_id]) if figname != "": plt.savefig(figname) plt.close() else: plt.show()