#!/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()