File: plot_3d_interaction.py

package info (click to toggle)
skimage 0.25.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 32,720 kB
  • sloc: python: 60,007; cpp: 2,592; ansic: 1,591; xml: 1,342; javascript: 1,267; makefile: 168; sh: 20
file content (145 lines) | stat: -rw-r--r-- 5,104 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"""
==========================================
Interact with 3D images (of kidney tissue)
==========================================

In this tutorial, we explore interactively a biomedical image which has three
spatial dimensions and three color dimensions (channels).
For a general introduction to 3D image processing, please refer to
:ref:`sphx_glr_auto_examples_applications_plot_3d_image_processing.py`.
The data we use here correspond to kidney tissue which was
imaged with confocal fluorescence microscopy (more details at [1]_ under
``kidney-tissue-fluorescence.tif``).

.. [1] https://gitlab.com/scikit-image/data/#data

"""

import matplotlib.pyplot as plt
import numpy as np

import plotly
import plotly.express as px
import skimage as ski


#####################################################################
# Load image
# ==========
# This biomedical image is available through `scikit-image`'s data registry.

data = ski.data.kidney()

#####################################################################
# The returned dataset is a 3D multichannel image:

print(f'number of dimensions: {data.ndim}')
print(f'shape: {data.shape}')
print(f'dtype: {data.dtype}')

#####################################################################
# Dimensions are provided in the following order: ``(z, y, x, c)``, i.e.,
# ``[plane, row, column, channel]``.

n_plane, n_row, n_col, n_chan = data.shape

#####################################################################
# Let us consider only a slice (2D plane) of the data for now. More
# specifically, let us consider the slice located halfway in the stack.
# The `imshow` function can display both grayscale and RGB(A) 2D images.

_, ax = plt.subplots()
ax.imshow(data[n_plane // 2])

#####################################################################
# According to the warning message, the range of values is unexpected. The
# image rendering is clearly not satisfactory color-wise.

vmin, vmax = data.min(), data.max()
print(f'range: ({vmin}, {vmax})')

#####################################################################
# We turn to Plotly's implementation of the :func:`plotly.express.imshow` function, for it
# supports `value ranges
# <https://plotly.com/python/imshow/#defining-the-data-range-covered-by-the-color-range-with-zmin-and-zmax>`_
# beyond ``(0.0, 1.0)`` for floats and ``(0, 255)`` for integers.

fig = px.imshow(data[n_plane // 2], zmax=vmax)
plotly.io.show(fig)
# sphinx_gallery_thumbnail_number = 2

#####################################################################
# Here you go, *fluorescence* microscopy!

#####################################################################
# Normalize range for each channel
# ================================
# Generally speaking, we may want to normalize the value range on a
# per-channel basis. Let us facet our data (slice) along the channel axis.
# This way, we get three single-channel images, where the max value of each
# image is used:

fig = px.imshow(
    data[n_plane // 2], facet_col=2, binary_string=True, labels={'facet_col': 'channel'}
)
plotly.io.show(fig)

#####################################################################
# What is the range of values for each color channel?
# We check by taking the min and max across all non-channel
# axes.

vmin_0, vmin_1, vmin_2 = np.min(data, axis=(0, 1, 2))
vmax_0, vmax_1, vmax_2 = np.max(data, axis=(0, 1, 2))
print(f'range for channel 0: ({vmin_0}, {vmax_0})')
print(f'range for channel 1: ({vmin_1}, {vmax_1})')
print(f'range for channel 2: ({vmin_2}, {vmax_2})')

#####################################################################
# Let us be very specific and pass value ranges on a per-channel basis:

fig = px.imshow(
    data[n_plane // 2], zmin=[vmin_0, vmin_1, vmin_2], zmax=[vmax_0, vmax_1, vmax_2]
)
plotly.io.show(fig)

#####################################################################
# Plotly lets you interact with this visualization by panning, zooming in and
# out, and exporting the desired figure as a static image in PNG format.

#####################################################################
# Explore slices as animation frames
# ==================================
# Click the play button to move along the ``z`` axis, through the stack of all
# 16 slices.

fig = px.imshow(
    data,
    zmin=[vmin_0, vmin_1, vmin_2],
    zmax=[vmax_0, vmax_1, vmax_2],
    animation_frame=0,
    binary_string=True,
    labels={'animation_frame': 'plane'},
)
plotly.io.show(fig)

#####################################################################
# Combine channel facetting and slice animation
# =============================================

fig = px.imshow(
    data,
    animation_frame=0,
    facet_col=3,
    binary_string=True,
    labels={'facet_col': 'channel', 'animation_frame': 'plane'},
)
plotly.io.show(fig)

#####################################################################
# The biologist's eye can spot that the two bright blobs (best seen in
# ``channel=2``) are kidney glomeruli [2]_.
#
# .. [2] https://en.wikipedia.org/wiki/Glomerulus_(kidney)

plt.show()