<jupyter_start><jupyter_text>(data_visualization.parametric_maps)= Parametric mapsThis notebook demonstrates how parametric maps can be made. In such parametric images, pixel intensity corresponds to  measurements of the objects, for example area.<jupyter_code>import numpy as np
import pyclesperanto_prototype as cle
from skimage.io import imread, imsave
from skimage.measure import regionprops, regionprops_table
from skimage.util import map_array
from napari_simpleitk_image_processing import label_statistics<jupyter_output><empty_output><jupyter_text>Starting point for drawing parametric maps is always a label image.<jupyter_code>binary = cle.artificial_objects_2d()
labels = cle.voronoi_otsu_labeling(binary, spot_sigma=5)

cle.imshow(labels, labels=True)<jupyter_output><empty_output><jupyter_text>Parametric maps using scikit-imageYou can also compute your own measurement for each object and then visualize it in a parametric map image. Consider using [scikit-image's `regionprops()`](https://scikit-image.org/docs/dev/api/skimage.measure.htmlskimage.measure.regionprops) for computing the measurements.<jupyter_code>statistics_table = regionprops_table(cle.pull(labels), properties=('label', 'area',))<jupyter_output><empty_output><jupyter_text>Area map<jupyter_code>remapped = map_array(
        cle.pull(labels),
        statistics_table['label'],
        statistics_table['area'],
        )

cle.imshow(remapped, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Parametric maps in pyclesperanto Alternatively, we can use the function `cle.replace_intensities` for making these parametric maps. It expects a label image and a list of measurements ordered by label, starting with a measurement corresponding to background (index 0). In the list of measurements, no label should be missing. Consider to [relabel the label image sequentially](image-segmentation:relabel-sequential) if necessary.<jupyter_code>statistics = regionprops(cle.pull(labels))
# we're appending a [0] for the "measurement" of the background and attach all values behind
area = [0] + [s.area for s in statistics]

area_map2 = cle.replace_intensities(labels, area)

cle.imshow(area_map2, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Pixel count mappyclesperanto comes with some maps built-in. For example the pixel count map derived from a label image expresses area or volume of objects in colour.<jupyter_code>pixel_count_map = cle.label_pixel_count_map(labels)

cle.imshow(pixel_count_map, color_map='jet', colorbar=True)<jupyter_output>/Users/haase/code/pyclesperanto_prototype/pyclesperanto_prototype/_tier9/_statistics_of_labelled_pixels.py:283: RuntimeWarning: invalid value encountered in true_divide
  region_props['mean_max_distance_to_centroid_ratio'] = region_props['max_distance_to_centroid'] / region_props[
/Users/haase/code/pyclesperanto_prototype/pyclesperanto_prototype/_tier9/_statistics_of_labelled_pixels.py:285: RuntimeWarning: invalid value encountered in true_divide
  region_props['mean_max_distance_to_mass_center_ratio'] = region_props['max_distance_to_mass_center'] / region_props[<jupyter_text>Parametric maps using SimpleITK-based measurementsFurthermore, also [SimpleITK](https://simpleitk.readthedocs.io/) comes with quantitative measurements for labeled images. For convenience reasons, we will use the scriptable napari plugin [napari-simpleitk-image-processing](https://github.com/haesleinhuepf/napari-simpleitk-image-processing) for deriving measurements.<jupyter_code>statistics_sitk = label_statistics(labels, labels, size=True, shape=True, perimeter=True, intensity=False)

print(statistics_sitk.keys())<jupyter_output>dict_keys(['label', 'elongation', 'feret_diameter', 'flatness', 'roundness', 'equivalent_ellipsoid_diameter_0', 'equivalent_ellipsoid_diameter_1', 'equivalent_spherical_perimeter', 'equivalent_spherical_radius', 'number_of_pixels', 'number_of_pixels_on_border', 'perimeter', 'perimeter_on_border', 'perimeter_on_border_ratio'])<jupyter_text>Number of pixels map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
number_of_pixels = [0] + statistics_sitk['number_of_pixels']

number_of_pixels_map = cle.replace_intensities(labels, number_of_pixels)

cle.imshow(number_of_pixels_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Extension ratio mapThe extension ratio is a shape descriptor derived from the maximum distance of pixels to their object's centroid divided by the average distance of pixels to the centroid. It alllows to differentiate elongated from roundish objects.<jupyter_code>extension_ratio_map = cle.extension_ratio_map(labels)

cle.imshow(extension_ratio_map, 
           color_map='jet', 
           colorbar=True, 
           min_display_intensity=1.5, 
           max_display_intensity=2.5)<jupyter_output><empty_output><jupyter_text>Mean / minimum / maximum / standard-deviation intensity mapIf we use additionally an intensity image, we can also produce parametric images showing intensity measurements.<jupyter_code>blobs = cle.scale(imread('../../data/blobs.tif'), factor_x=2, factor_y=2, auto_size=True)

cle.imshow(blobs)
mean_intensity_map = cle.label_mean_intensity_map(blobs, labels)
cle.imshow(mean_intensity_map, 
           color_map='jet', 
           colorbar=True,
           min_display_intensity=100, 
           max_display_intensity=250)
maximum_intensity_map = cle.maximum_intensity_map(blobs, labels)
cle.imshow(maximum_intensity_map, 
           color_map='jet', 
           colorbar=True, 
           min_display_intensity=200, 
           max_display_intensity=270)
stddev_intensity_map = cle.standard_deviation_intensity_map(blobs, labels)
cle.imshow(stddev_intensity_map, color_map='jet', colorbar=True)<jupyter_output><empty_output><jupyter_text>Aspect ratio map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
aspect_ratio = [0]

for s in statistics:
    if s.minor_axis_length:
        aspect_ratio.append(s.major_axis_length / s.minor_axis_length)
    else:
        aspect_ratio.append(0) # note: an aspect ratio of 0 is an "invalid" value
aspect_ratio_map = cle.replace_intensities(labels, aspect_ratio)

cle.imshow(aspect_ratio_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Elongation map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
eccentricity = [0] + [s.eccentricity for s in statistics]

eccentricity_map = cle.replace_intensities(labels, eccentricity)

cle.imshow(eccentricity_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Extent map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
extent = [0] + [s.extent for s in statistics]

extent_map = cle.replace_intensities(labels, extent)

cle.imshow(extent_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Feret diameter map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
feret_diameter = [0] + [s.feret_diameter_max for s in statistics]

feret_diameter_map = cle.replace_intensities(labels, feret_diameter)

cle.imshow(feret_diameter_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Orientation map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
orientation = [0] + [s.orientation for s in statistics]

orientation_map = cle.replace_intensities(labels, orientation)

cle.imshow(orientation_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Perimeter map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
perimeter_ski = [0] + [s.perimeter for s in statistics]

perimeter_ski_map = cle.replace_intensities(labels, perimeter_ski)

cle.imshow(perimeter_ski_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Solidity map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
solidity = [0] + [s.solidity for s in statistics]

solidity_map = cle.replace_intensities(labels, solidity)

cle.imshow(solidity_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Elongation map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
elongation = [0] + statistics_sitk['elongation']

elongation_map = cle.replace_intensities(labels, elongation)

cle.imshow(elongation_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Flatness map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
flatness = [0] + statistics_sitk['flatness']

flatness_map = cle.replace_intensities(labels, flatness)

cle.imshow(flatness_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Roundness map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
roundness = [0] + statistics_sitk['roundness']

roundness_map = cle.replace_intensities(labels, roundness)

cle.imshow(roundness_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Perimeter map<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
perimeter_sitk = [0] + statistics_sitk['perimeter']

perimeter_sitk_map = cle.replace_intensities(labels, perimeter_sitk)

cle.imshow(perimeter_sitk_map, colorbar=True, color_map="jet")<jupyter_output><empty_output><jupyter_text>Quality assuranceIf you generate a parametric image with the "label" column, the parametric image should actually be equal to the label input image.<jupyter_code># we're appending a [0] for the "measurement" of the background and attach all values behind
label = [0] + statistics_sitk['label']

label_map = cle.replace_intensities(labels, label)

cle.imshow(label_map, labels=True)
label_difference = labels - label_map

cle.imshow(label_difference)
label_difference.min(), label_difference.max()<jupyter_output><empty_output><jupyter_text>When comparing perimeter measurements from scikit-image and SimpleITK, we could see small differences. Here we can visualize which objects are affected and to what degree.<jupyter_code>perimeter_difference = perimeter_sitk_map - perimeter_ski_map

cle.imshow(perimeter_difference, colorbar=True, color_map="jet")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09214345912538627, 'fraction_numerical': 0.005899428785466804, 'mean_word_length': 7.402832415420929, 'pattern_counts': {'":': 0, '<': 91, '<?xml version=': 0, '>': 91, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '23', 'dir': 'jupyter-structured-clean-dedup', 'id': '227936', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 3520, 'n_tokens_neox': 3371, 'n_words': 805, 'path': 'docs/60_data_visualization/parametric_maps.ipynb', 'repo_name': 'rayanirban/BioImageAnalysisNotebooks', 'size': '10679'}