Source code for timagetk.visu.profiles

#!/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
import numpy as np

SLP_METHODS = ['mean', 'sum', 'median']


def _fun_slices_profile(fun, image, axis='z'):
    axsh = image.get_shape(axis)
    return [fun(image.get_slice(sl, axis)) for sl in range(axsh)]


def _fun_slices_profile2(fun, image, axis='z'):
    axes = image.axes_order_dict
    axes.pop(axis.upper())
    return fun(image, axis=tuple(axes.values()))


[docs] def slices_profile(image, axis='z', method=None): """Plot the intensity profile by slices. The selected method determine the type of function applied to each slice. Parameters ---------- image : timagetk.components.spatial_image.SpatialImage A 3D image to use for profile display. axis : str in {'x', 'y', 'z'} The axis to use. method : str or list in {'mean', 'sum', 'median'} The (list of) function to apply to each slice for the profile(s). Notes ----- Beware of the scale of the profile values if you are using more than one method. For example 'sum' will have much higher values than 'mean' and the corresponding 'mean' curve would appear flat at the bottom. Examples -------- >>> from timagetk.visu.profiles import slices_profile >>> from timagetk.io import imread >>> from timagetk.io.util import shared_dataset >>> # - Get 'p58' shared intensity image: >>> image = imread(shared_dataset("p58")[0]) >>> slices_profile(image, 'z', method=['mean', 'median']) >>> slices_profile(image, 'y', method=['mean', 'median']) >>> slices_profile(image, 'x', method=['mean', 'median']) """ if method is None: method = SLP_METHODS try: assert isinstance(method, (str, list)) except AssertionError: raise TypeError("Parameter `method` should be a 'list' or 'str'!") try: if isinstance(method, str): assert method in SLP_METHODS if isinstance(method, list): assert np.alltrue([isinstance(met, str) and met in SLP_METHODS for met in method]) except AssertionError: raise NotImplementedError("Given method(s) are not implemented... Yet!") axsh = image.get_shape(axis) profiles = {} if "mean" in method: profiles['mean'] = _fun_slices_profile2(np.mean, image, axis) if 'sum' in method: profiles['sum'] = _fun_slices_profile2(np.sum, image, axis) if 'median' in method: profiles['median'] = _fun_slices_profile2(np.median, image, axis) fig = plt.figure() ax_img = plt.subplot() fig.suptitle(f"{image.filename}") colors = ['r', 'g', 'b'] for n, (pname, pvals) in enumerate(profiles.items()): ax_img.plot(range(axsh), pvals, colors[n], label=pname) ax_img.set_title(f"Intensity profile - {axis.upper()}-axis") ax_img.set_xlabel(f"{axis.upper()}-slices") ax_img.set_ylabel("Intensity profile") ax_img.grid(linestyle='-.') plt.legend() plt.show()
[docs] def slices_profile_boxplot(image, axis='z', method=None): """Plot the intensity profile by slices. The selected method determine the type of function applied to each slice. Parameters ---------- image : timagetk.components.spatial_image.SpatialImage A 3D image to use for profile display. axis : str in {'x', 'y', 'z'} The axis to use. method : str or list in {'mean', 'sum', 'median'} The (list of) function to apply to each slice for the profile(s). Notes ----- Beware of the scale of the profile values if you are using more than onemethod. For example 'sum' will have much higher values than 'mean' and the corresponding 'mean' curve would appear flat at the bottom. Examples -------- >>> from timagetk.visu.profiles import slices_profile_boxplot >>> from timagetk.io import imread >>> from timagetk.io.util import shared_dataset >>> # - Get 'p58' shared intensity image: >>> image = imread(shared_dataset("p58")[0]) >>> slices_profile_boxplot(image.get_region([0, 5, 0, 10, 0, 10]), 'z') >>> slices_profile_boxplot(image, 'z') >>> slices_profile_boxplot(image.get_region([0, 5, 0, 10, 0, 10]), 'y') >>> slices_profile_boxplot(image, 'x') """ from matplotlib.ticker import MultipleLocator if method is None: method = SLP_METHODS try: assert isinstance(method, (str, list)) except AssertionError: raise TypeError("Parameter `method` should be a 'list' or 'str'!") try: if isinstance(method, str): assert method in SLP_METHODS if isinstance(method, list): assert np.alltrue([isinstance(met, str) and met in SLP_METHODS for met in method]) except AssertionError: raise NotImplementedError("Given method(s) are not implemented... Yet!") # Get the new axes shape as the product of the shape of axes to "pool" in a column new_axsh = image.get_shape() new_axsh.pop(image.axes_order_dict[axis.upper()]) new_axsh = np.prod(new_axsh) # Get the new axes order to set the selected `axis` as the first in the array new_axorder = image.axes_order_dict new_axorder.pop(axis.upper()) arr = image.transpose(*[axis] + list(new_axorder.keys())).get_array() # Get the profiles with 2D array where each column will be a box of the later boxplot profiles = arr.reshape((image.get_shape(axis=axis), new_axsh)).T flierprops = {'marker': '.', 'linestyle': 'none', 'markersize': 3} auto_width = profiles.shape[-1] * 0.25 # figure width auto-scaling width = auto_width if auto_width > 3. else 3. # minimum figure width fig = plt.figure(figsize=(width, 6)) ax_img = plt.subplot() fig.suptitle(f"{image.filename}") ax_img.boxplot(profiles, flierprops=flierprops) ax_img.set_title(f"Intensity profile - {axis.upper()}-axis") ax_img.set_xlabel(f"{axis.upper()}-slices") ax_img.set_ylabel("Intensity") if any(profiles.max(axis=0) - profiles.min(axis=0) > 125): # Y-axis ticks location ax_img.yaxis.set_major_locator(MultipleLocator(8 * 5)) ax_img.yaxis.set_major_formatter('{x:.0f}') # For the minor ticks, use no labels; default NullFormatter. ax_img.yaxis.set_minor_locator(MultipleLocator(8)) ax_img.grid(linestyle='-.', axis="y", which="both") if profiles.shape[-1] >= 80: ax_img.grid(linestyle='-.', axis="y") # X-axis ticks location ax_img.xaxis.set_major_locator(MultipleLocator(20)) ax_img.xaxis.set_major_formatter('{x:.0f}') # For the minor ticks, use no labels; default NullFormatter. ax_img.xaxis.set_minor_locator(MultipleLocator(5)) plt.tight_layout() plt.show()