phasorpy 0.3__cp311-cp311-win_arm64.whl → 0.5__cp311-cp311-win_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- phasorpy/_io.py +2655 -0
- phasorpy/_phasorpy.cp311-win_arm64.pyd +0 -0
- phasorpy/_phasorpy.pyx +119 -47
- phasorpy/_utils.py +165 -18
- phasorpy/cli.py +2 -0
- phasorpy/cluster.py +170 -0
- phasorpy/color.py +17 -13
- phasorpy/components.py +18 -18
- phasorpy/conftest.py +2 -0
- phasorpy/cursors.py +9 -9
- phasorpy/datasets.py +169 -10
- phasorpy/io.py +7 -1809
- phasorpy/phasor.py +281 -100
- phasorpy/plot.py +276 -36
- phasorpy/utils.py +12 -7
- phasorpy/version.py +14 -5
- {phasorpy-0.3.dist-info → phasorpy-0.5.dist-info}/METADATA +11 -15
- phasorpy-0.5.dist-info/RECORD +26 -0
- {phasorpy-0.3.dist-info → phasorpy-0.5.dist-info}/WHEEL +1 -1
- {phasorpy-0.3.dist-info → phasorpy-0.5.dist-info/licenses}/LICENSE.txt +1 -1
- phasorpy-0.3.dist-info/RECORD +0 -24
- {phasorpy-0.3.dist-info → phasorpy-0.5.dist-info}/entry_points.txt +0 -0
- {phasorpy-0.3.dist-info → phasorpy-0.5.dist-info}/top_level.txt +0 -0
phasorpy/plot.py
CHANGED
@@ -11,14 +11,17 @@ from __future__ import annotations
|
|
11
11
|
__all__ = [
|
12
12
|
'PhasorPlot',
|
13
13
|
'PhasorPlotFret',
|
14
|
+
'plot_histograms',
|
15
|
+
'plot_image',
|
14
16
|
'plot_phasor',
|
15
17
|
'plot_phasor_image',
|
16
|
-
'plot_signal_image',
|
17
18
|
'plot_polar_frequency',
|
19
|
+
'plot_signal_image',
|
18
20
|
]
|
19
21
|
|
20
22
|
import math
|
21
23
|
import os
|
24
|
+
import warnings
|
22
25
|
from collections.abc import Sequence
|
23
26
|
from typing import TYPE_CHECKING
|
24
27
|
|
@@ -43,6 +46,7 @@ from ._phasorpy import _intersection_circle_circle, _intersection_circle_line
|
|
43
46
|
from ._utils import (
|
44
47
|
dilate_coordinates,
|
45
48
|
parse_kwargs,
|
49
|
+
parse_signal_axis,
|
46
50
|
phasor_from_polar_scalar,
|
47
51
|
phasor_to_polar_scalar,
|
48
52
|
sort_coordinates,
|
@@ -74,7 +78,7 @@ class PhasorPlot:
|
|
74
78
|
Parameters
|
75
79
|
----------
|
76
80
|
allquadrants : bool, optional
|
77
|
-
Show all
|
81
|
+
Show all quadrants of phasor space.
|
78
82
|
By default, only the first quadrant with universal semicircle is shown.
|
79
83
|
ax : matplotlib axes, optional
|
80
84
|
Matplotlib axes used for plotting.
|
@@ -82,7 +86,7 @@ class PhasorPlot:
|
|
82
86
|
frequency : float, optional
|
83
87
|
Laser pulse or modulation frequency in MHz.
|
84
88
|
grid : bool, optional, default: True
|
85
|
-
Display polar grid or semicircle.
|
89
|
+
Display polar grid or universal semicircle.
|
86
90
|
**kwargs
|
87
91
|
Additional properties to set on `ax`.
|
88
92
|
|
@@ -217,10 +221,10 @@ class PhasorPlot:
|
|
217
221
|
/,
|
218
222
|
fmt: str = 'o',
|
219
223
|
*,
|
220
|
-
label:
|
224
|
+
label: Sequence[str] | None = None,
|
221
225
|
**kwargs: Any,
|
222
226
|
) -> list[Line2D]:
|
223
|
-
"""Plot
|
227
|
+
"""Plot imaginary versus real coordinates as markers or lines.
|
224
228
|
|
225
229
|
Parameters
|
226
230
|
----------
|
@@ -232,7 +236,7 @@ class PhasorPlot:
|
|
232
236
|
Must be of same shape as `real`.
|
233
237
|
fmt : str, optional, default: 'o'
|
234
238
|
Matplotlib style format string.
|
235
|
-
label :
|
239
|
+
label : sequence of str, optional
|
236
240
|
Plot label.
|
237
241
|
May be a sequence if phasor coordinates are two dimensional arrays.
|
238
242
|
**kwargs
|
@@ -285,7 +289,7 @@ class PhasorPlot:
|
|
285
289
|
/,
|
286
290
|
**kwargs: Any,
|
287
291
|
) -> tuple[NDArray[Any], NDArray[Any], NDArray[Any]]:
|
288
|
-
"""Return
|
292
|
+
"""Return two-dimensional histogram of imag versus real coordinates."""
|
289
293
|
update_kwargs(kwargs, range=self._limits)
|
290
294
|
(xmin, xmax), (ymin, ymax) = kwargs['range']
|
291
295
|
assert xmax > xmin and ymax > ymin
|
@@ -318,7 +322,7 @@ class PhasorPlot:
|
|
318
322
|
/,
|
319
323
|
**kwargs: Any,
|
320
324
|
) -> None:
|
321
|
-
"""Plot
|
325
|
+
"""Plot two-dimensional histogram of imag versus real coordinates.
|
322
326
|
|
323
327
|
Parameters
|
324
328
|
----------
|
@@ -368,7 +372,9 @@ class PhasorPlot:
|
|
368
372
|
and :py:meth:`matplotlib.axes.Axes.contour`.
|
369
373
|
|
370
374
|
"""
|
371
|
-
|
375
|
+
if 'cmap' not in kwargs and 'colors' not in kwargs:
|
376
|
+
kwargs['cmap'] = 'Blues'
|
377
|
+
update_kwargs(kwargs, norm='log')
|
372
378
|
kwargs_hist2d = parse_kwargs(
|
373
379
|
kwargs, 'bins', 'range', 'density', 'weights'
|
374
380
|
)
|
@@ -968,9 +974,9 @@ class PhasorPlotFret(PhasorPlot):
|
|
968
974
|
acceptor_lifetime : array_like
|
969
975
|
Lifetime of acceptor in ns.
|
970
976
|
fret_efficiency : array_like, optional, default 0
|
971
|
-
FRET efficiency in range [0
|
972
|
-
|
973
|
-
Fraction of donors participating in FRET. Range [0
|
977
|
+
FRET efficiency in range [0, 1].
|
978
|
+
donor_fretting : array_like, optional, default 1
|
979
|
+
Fraction of donors participating in FRET. Range [0, 1].
|
974
980
|
donor_bleedthrough : array_like, optional, default 0
|
975
981
|
Weight of donor fluorescence in acceptor channel
|
976
982
|
relative to fluorescence of fully sensitized acceptor.
|
@@ -1021,7 +1027,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1021
1027
|
_donor_lifetime_slider: Slider
|
1022
1028
|
_acceptor_lifetime_slider: Slider
|
1023
1029
|
_fret_efficiency_slider: Slider
|
1024
|
-
|
1030
|
+
_donor_fretting_slider: Slider
|
1025
1031
|
_donor_bleedthrough_slider: Slider
|
1026
1032
|
_acceptor_bleedthrough_slider: Slider
|
1027
1033
|
_acceptor_background_slider: Slider
|
@@ -1052,7 +1058,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1052
1058
|
donor_lifetime: float = 4.2,
|
1053
1059
|
acceptor_lifetime: float = 3.0,
|
1054
1060
|
fret_efficiency: float = 0.5,
|
1055
|
-
|
1061
|
+
donor_fretting: float = 1.0,
|
1056
1062
|
donor_bleedthrough: float = 0.0,
|
1057
1063
|
acceptor_bleedthrough: float = 0.0,
|
1058
1064
|
acceptor_background: float = 0.0,
|
@@ -1102,7 +1108,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1102
1108
|
frequency,
|
1103
1109
|
donor_lifetime,
|
1104
1110
|
fret_efficiency=self._fret_efficiencies,
|
1105
|
-
|
1111
|
+
donor_fretting=donor_fretting,
|
1106
1112
|
donor_background=donor_background,
|
1107
1113
|
background_real=background_real,
|
1108
1114
|
background_imag=background_imag,
|
@@ -1115,7 +1121,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1115
1121
|
donor_lifetime,
|
1116
1122
|
acceptor_lifetime,
|
1117
1123
|
fret_efficiency=self._fret_efficiencies,
|
1118
|
-
|
1124
|
+
donor_fretting=donor_fretting,
|
1119
1125
|
donor_bleedthrough=donor_bleedthrough,
|
1120
1126
|
acceptor_bleedthrough=acceptor_bleedthrough,
|
1121
1127
|
acceptor_background=acceptor_background,
|
@@ -1134,7 +1140,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1134
1140
|
)
|
1135
1141
|
self._acceptor_semicircle_line = lines[0]
|
1136
1142
|
|
1137
|
-
if
|
1143
|
+
if donor_fretting < 1.0 and donor_background == 0.0:
|
1138
1144
|
lines = self.line(
|
1139
1145
|
[donor_real, donor_fret_real],
|
1140
1146
|
[donor_imag, donor_fret_imag],
|
@@ -1284,18 +1290,18 @@ class PhasorPlotFret(PhasorPlot):
|
|
1284
1290
|
)
|
1285
1291
|
self._fret_efficiency_slider.on_changed(self._on_changed)
|
1286
1292
|
|
1287
|
-
self.
|
1293
|
+
self._donor_fretting_slider = Slider(
|
1288
1294
|
ax=axes[6],
|
1289
|
-
label='Donors
|
1295
|
+
label='Donors fretting ',
|
1290
1296
|
valfmt=' %.2f',
|
1291
1297
|
valmin=0.0,
|
1292
1298
|
valmax=1.0,
|
1293
1299
|
valstep=0.01,
|
1294
|
-
valinit=
|
1300
|
+
valinit=donor_fretting,
|
1295
1301
|
# facecolor='tab:green',
|
1296
1302
|
handle_style={'edgecolor': 'tab:green'},
|
1297
1303
|
)
|
1298
|
-
self.
|
1304
|
+
self._donor_fretting_slider.on_changed(self._on_changed)
|
1299
1305
|
|
1300
1306
|
self._donor_bleedthrough_slider = Slider(
|
1301
1307
|
ax=axes[5],
|
@@ -1397,7 +1403,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1397
1403
|
donor_lifetime = self._donor_lifetime_slider.val
|
1398
1404
|
acceptor_lifetime = self._acceptor_lifetime_slider.val
|
1399
1405
|
fret_efficiency = self._fret_efficiency_slider.val
|
1400
|
-
|
1406
|
+
donor_fretting = self._donor_fretting_slider.val
|
1401
1407
|
donor_bleedthrough = self._donor_bleedthrough_slider.val
|
1402
1408
|
acceptor_bleedthrough = self._acceptor_bleedthrough_slider.val
|
1403
1409
|
acceptor_background = self._acceptor_background_slider.val
|
@@ -1419,7 +1425,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1419
1425
|
frequency,
|
1420
1426
|
donor_lifetime,
|
1421
1427
|
fret_efficiency=self._fret_efficiencies,
|
1422
|
-
|
1428
|
+
donor_fretting=donor_fretting,
|
1423
1429
|
donor_background=donor_background,
|
1424
1430
|
background_real=background_real,
|
1425
1431
|
background_imag=background_imag,
|
@@ -1432,7 +1438,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1432
1438
|
donor_lifetime,
|
1433
1439
|
acceptor_lifetime,
|
1434
1440
|
fret_efficiency=self._fret_efficiencies,
|
1435
|
-
|
1441
|
+
donor_fretting=donor_fretting,
|
1436
1442
|
donor_bleedthrough=donor_bleedthrough,
|
1437
1443
|
acceptor_bleedthrough=acceptor_bleedthrough,
|
1438
1444
|
acceptor_background=acceptor_background,
|
@@ -1448,7 +1454,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1448
1454
|
else:
|
1449
1455
|
self._donor_background_line.set_data([0.0, 0.0], [0.0, 0.0])
|
1450
1456
|
|
1451
|
-
if
|
1457
|
+
if donor_fretting < 1.0 and donor_background == 0.0:
|
1452
1458
|
self._donor_donor_line.set_data(
|
1453
1459
|
[donor_real, donor_fret_real],
|
1454
1460
|
[donor_imag, donor_fret_imag],
|
@@ -1718,7 +1724,7 @@ def plot_phasor_image(
|
|
1718
1724
|
percentile : float, optional
|
1719
1725
|
The (q, 100-q) percentiles of image data are covered by colormaps.
|
1720
1726
|
By default, the complete value range of `mean` is covered,
|
1721
|
-
for `real` and `imag` the range [-1
|
1727
|
+
for `real` and `imag` the range [-1, 1].
|
1722
1728
|
title : str, optional
|
1723
1729
|
Figure title.
|
1724
1730
|
show : bool, optional, default: True
|
@@ -1858,9 +1864,10 @@ def plot_signal_image(
|
|
1858
1864
|
signal: ArrayLike,
|
1859
1865
|
/,
|
1860
1866
|
*,
|
1861
|
-
axis: int | None = None,
|
1867
|
+
axis: int | str | None = None,
|
1862
1868
|
percentile: float | Sequence[float] | None = None,
|
1863
1869
|
title: str | None = None,
|
1870
|
+
xlabel: str | None = None,
|
1864
1871
|
show: bool = True,
|
1865
1872
|
**kwargs: Any,
|
1866
1873
|
) -> None:
|
@@ -1876,15 +1883,18 @@ def plot_signal_image(
|
|
1876
1883
|
----------
|
1877
1884
|
signal : array_like
|
1878
1885
|
Image stack. Must be three or more dimensional.
|
1879
|
-
axis : int, optional
|
1886
|
+
axis : int or str, optional
|
1880
1887
|
Axis over which phasor coordinates would be computed.
|
1881
|
-
|
1888
|
+
By default, the 'H' or 'C' axes if signal contains such dimension
|
1889
|
+
names, else the last axis (-1).
|
1882
1890
|
percentile : float or [float, float], optional
|
1883
1891
|
The [q, 100-q] percentiles of image data are covered by colormaps.
|
1884
1892
|
By default, the complete value range of `mean` is covered,
|
1885
|
-
for `real` and `imag` the range [-1
|
1893
|
+
for `real` and `imag` the range [-1, 1].
|
1886
1894
|
title : str, optional
|
1887
1895
|
Figure title.
|
1896
|
+
xlabel : str, optional
|
1897
|
+
Label of axis over which phasor coordinates would be computed.
|
1888
1898
|
show : bool, optional, default: True
|
1889
1899
|
Display figure.
|
1890
1900
|
**kwargs
|
@@ -1899,13 +1909,22 @@ def plot_signal_image(
|
|
1899
1909
|
"""
|
1900
1910
|
# TODO: add option to separate channels?
|
1901
1911
|
# TODO: add option to plot non-images?
|
1912
|
+
|
1913
|
+
axis, axis_label = parse_signal_axis(signal, axis)
|
1914
|
+
if (
|
1915
|
+
axis_label
|
1916
|
+
and hasattr(signal, 'coords')
|
1917
|
+
and axis_label in signal.coords
|
1918
|
+
):
|
1919
|
+
axis_coords = signal.coords[axis_label]
|
1920
|
+
else:
|
1921
|
+
axis_coords = None
|
1922
|
+
|
1902
1923
|
update_kwargs(kwargs, interpolation='nearest')
|
1903
1924
|
signal = numpy.asarray(signal)
|
1904
1925
|
if signal.ndim < 3:
|
1905
1926
|
raise ValueError(f'not an image stack {signal.ndim=} < 3')
|
1906
1927
|
|
1907
|
-
if axis is None:
|
1908
|
-
axis = -1
|
1909
1928
|
axis %= signal.ndim
|
1910
1929
|
|
1911
1930
|
# for MyPy
|
@@ -1922,8 +1941,18 @@ def plot_signal_image(
|
|
1922
1941
|
axes = list(range(signal.ndim))
|
1923
1942
|
del axes[axis]
|
1924
1943
|
ax = fig.add_subplot(gs[0, 1])
|
1925
|
-
|
1926
|
-
|
1944
|
+
|
1945
|
+
if axis_coords is not None:
|
1946
|
+
ax.set_title(f'{axis=} {axis_label!r}')
|
1947
|
+
ax.plot(axis_coords, numpy.nanmean(signal, axis=tuple(axes)))
|
1948
|
+
else:
|
1949
|
+
ax.set_title(f'{axis=}')
|
1950
|
+
ax.plot(numpy.nanmean(signal, axis=tuple(axes)))
|
1951
|
+
|
1952
|
+
ax.set_ylim(kwargs.get('vmin', None), kwargs.get('vmax', None))
|
1953
|
+
|
1954
|
+
if xlabel is not None:
|
1955
|
+
ax.set_xlabel(xlabel)
|
1927
1956
|
|
1928
1957
|
# image
|
1929
1958
|
axes = list(sorted(axes[:-2] + [axis]))
|
@@ -1934,12 +1963,164 @@ def plot_signal_image(
|
|
1934
1963
|
percentile=percentile,
|
1935
1964
|
shrink=0.5,
|
1936
1965
|
title='mean',
|
1966
|
+
**kwargs,
|
1937
1967
|
)
|
1938
1968
|
|
1939
1969
|
if show:
|
1940
1970
|
pyplot.show()
|
1941
1971
|
|
1942
1972
|
|
1973
|
+
def plot_image(
|
1974
|
+
*images: ArrayLike,
|
1975
|
+
percentile: float | None = None,
|
1976
|
+
columns: int | None = None,
|
1977
|
+
title: str | None = None,
|
1978
|
+
labels: Sequence[str | None] | None = None,
|
1979
|
+
show: bool = True,
|
1980
|
+
**kwargs: Any,
|
1981
|
+
) -> None:
|
1982
|
+
"""Plot images.
|
1983
|
+
|
1984
|
+
Parameters
|
1985
|
+
----------
|
1986
|
+
*images : array_like
|
1987
|
+
Images to be plotted. Must be two or more dimensional.
|
1988
|
+
The last two axes are assumed to be the image axes.
|
1989
|
+
Other axes are averaged for display.
|
1990
|
+
Three-dimensional images with last axis size of three or four
|
1991
|
+
are plotted as RGB(A) images.
|
1992
|
+
percentile : float, optional
|
1993
|
+
The (q, 100-q) percentiles of image data are covered by colormaps.
|
1994
|
+
By default, the complete value range is covered.
|
1995
|
+
Does not apply to RGB images.
|
1996
|
+
columns : int, optional
|
1997
|
+
Number of columns in figure.
|
1998
|
+
By default, up to four columns are used.
|
1999
|
+
title : str, optional
|
2000
|
+
Figure title.
|
2001
|
+
labels : sequence of str, optional
|
2002
|
+
Labels for each image.
|
2003
|
+
show : bool, optional, default: True
|
2004
|
+
Display figure.
|
2005
|
+
**kwargs
|
2006
|
+
Additional arguments passed to :func:`matplotlib.pyplot.imshow`.
|
2007
|
+
|
2008
|
+
Raises
|
2009
|
+
------
|
2010
|
+
ValueError
|
2011
|
+
Percentile is out of range.
|
2012
|
+
|
2013
|
+
"""
|
2014
|
+
update_kwargs(
|
2015
|
+
kwargs, interpolation='nearest', location='right', shrink=0.5
|
2016
|
+
)
|
2017
|
+
cmap = kwargs.pop('cmap', None)
|
2018
|
+
figsize = kwargs.pop('figsize', None)
|
2019
|
+
subplot_kw = kwargs.pop('subplot_kw', {})
|
2020
|
+
location = kwargs['location']
|
2021
|
+
allrgb = True
|
2022
|
+
|
2023
|
+
arrays = []
|
2024
|
+
shape = [1, 1]
|
2025
|
+
for image in images:
|
2026
|
+
image = numpy.asarray(image)
|
2027
|
+
if image.ndim < 2:
|
2028
|
+
raise ValueError(f'not an image {image.ndim=} < 2')
|
2029
|
+
if image.ndim == 3 and image.shape[2] in {3, 4}:
|
2030
|
+
# RGB(A)
|
2031
|
+
pass
|
2032
|
+
else:
|
2033
|
+
allrgb = False
|
2034
|
+
image = image.reshape(-1, *image.shape[-2:])
|
2035
|
+
if image.shape[0] == 1:
|
2036
|
+
image = image[0]
|
2037
|
+
else:
|
2038
|
+
with warnings.catch_warnings():
|
2039
|
+
warnings.filterwarnings('ignore', category=RuntimeWarning)
|
2040
|
+
image = numpy.nanmean(image, axis=0)
|
2041
|
+
assert isinstance(image, numpy.ndarray)
|
2042
|
+
for i in (-1, -2):
|
2043
|
+
if image.shape[i] > shape[i]:
|
2044
|
+
shape[i] = image.shape[i]
|
2045
|
+
arrays.append(image)
|
2046
|
+
|
2047
|
+
if columns is None:
|
2048
|
+
n = len(arrays)
|
2049
|
+
if n < 3:
|
2050
|
+
columns = n
|
2051
|
+
elif n < 5:
|
2052
|
+
columns = 2
|
2053
|
+
elif n < 7:
|
2054
|
+
columns = 3
|
2055
|
+
else:
|
2056
|
+
columns = 4
|
2057
|
+
rows = int(numpy.ceil(len(arrays) / columns))
|
2058
|
+
|
2059
|
+
vmin = None
|
2060
|
+
vmax = None
|
2061
|
+
if percentile is None:
|
2062
|
+
vmin = kwargs.pop('vmin', None)
|
2063
|
+
vmax = kwargs.pop('vmax', None)
|
2064
|
+
if vmin is None:
|
2065
|
+
vmin = numpy.inf
|
2066
|
+
for image in images:
|
2067
|
+
vmin = min(vmin, numpy.nanmin(image))
|
2068
|
+
if vmin == numpy.inf:
|
2069
|
+
vmin = None
|
2070
|
+
if vmax is None:
|
2071
|
+
vmax = -numpy.inf
|
2072
|
+
for image in images:
|
2073
|
+
vmax = max(vmax, numpy.nanmax(image))
|
2074
|
+
if vmax == -numpy.inf:
|
2075
|
+
vmax = None
|
2076
|
+
|
2077
|
+
# create figure with size depending on image aspect
|
2078
|
+
fig = pyplot.figure(layout='constrained', figsize=figsize)
|
2079
|
+
if figsize is None:
|
2080
|
+
# TODO: find optimal figure height as a function of
|
2081
|
+
# number of rows and columns, image shapes, labels, and colorbar
|
2082
|
+
# presence and placements.
|
2083
|
+
if allrgb:
|
2084
|
+
hadd = 0.0
|
2085
|
+
elif location == 'right':
|
2086
|
+
hadd = 0.5
|
2087
|
+
else:
|
2088
|
+
hadd = 1.2
|
2089
|
+
if labels is not None:
|
2090
|
+
hadd += 0.3 * rows
|
2091
|
+
w, h = fig.get_size_inches()
|
2092
|
+
aspect = min(1.0, max(0.5, shape[0] / shape[1]))
|
2093
|
+
fig.set_size_inches(
|
2094
|
+
w, h * 0.9 / columns * aspect * rows + h * 0.1 * aspect + hadd
|
2095
|
+
)
|
2096
|
+
gs = GridSpec(rows, columns, figure=fig)
|
2097
|
+
if title:
|
2098
|
+
fig.suptitle(title)
|
2099
|
+
|
2100
|
+
axs = []
|
2101
|
+
for i, image in enumerate(arrays):
|
2102
|
+
ax = fig.add_subplot(gs[i // columns, i % columns], **subplot_kw)
|
2103
|
+
ax.set_anchor('C')
|
2104
|
+
axs.append(ax)
|
2105
|
+
pos = _imshow(
|
2106
|
+
ax,
|
2107
|
+
image,
|
2108
|
+
percentile=percentile,
|
2109
|
+
vmin=vmin,
|
2110
|
+
vmax=vmax,
|
2111
|
+
cmap=cmap,
|
2112
|
+
colorbar=percentile is not None,
|
2113
|
+
axis=i == 0 and not subplot_kw,
|
2114
|
+
title=None if labels is None else labels[i],
|
2115
|
+
**kwargs,
|
2116
|
+
)
|
2117
|
+
if not allrgb and percentile is None:
|
2118
|
+
fig.colorbar(pos, ax=axs, shrink=kwargs['shrink'], location=location)
|
2119
|
+
|
2120
|
+
if show:
|
2121
|
+
pyplot.show()
|
2122
|
+
|
2123
|
+
|
1943
2124
|
def plot_polar_frequency(
|
1944
2125
|
frequency: ArrayLike,
|
1945
2126
|
phase: ArrayLike,
|
@@ -2002,6 +2183,58 @@ def plot_polar_frequency(
|
|
2002
2183
|
pyplot.show()
|
2003
2184
|
|
2004
2185
|
|
2186
|
+
def plot_histograms(
|
2187
|
+
*data: ArrayLike,
|
2188
|
+
title: str | None = None,
|
2189
|
+
xlabel: str | None = None,
|
2190
|
+
ylabel: str | None = None,
|
2191
|
+
labels: Sequence[str] | None = None,
|
2192
|
+
show: bool = True,
|
2193
|
+
**kwargs: Any,
|
2194
|
+
) -> None:
|
2195
|
+
"""Plot histograms of flattened data arrays.
|
2196
|
+
|
2197
|
+
Parameters
|
2198
|
+
----------
|
2199
|
+
data: array_like
|
2200
|
+
Data arrays to be plotted as histograms.
|
2201
|
+
title : str, optional
|
2202
|
+
Figure title.
|
2203
|
+
xlabel : str, optional
|
2204
|
+
Label for x-axis.
|
2205
|
+
ylabel : str, optional
|
2206
|
+
Label for y-axis.
|
2207
|
+
labels: sequence of str, optional
|
2208
|
+
Labels for each data array.
|
2209
|
+
show : bool, optional, default: True
|
2210
|
+
Display figure.
|
2211
|
+
**kwargs
|
2212
|
+
Additional arguments passed to :func:`matplotlib.pyplot.hist`.
|
2213
|
+
|
2214
|
+
"""
|
2215
|
+
ax = pyplot.subplots()[1]
|
2216
|
+
if kwargs.get('alpha') is None:
|
2217
|
+
ax.hist(
|
2218
|
+
[numpy.asarray(d).flatten() for d in data], label=labels, **kwargs
|
2219
|
+
)
|
2220
|
+
else:
|
2221
|
+
for d, label in zip(
|
2222
|
+
data, [None] * len(data) if labels is None else labels
|
2223
|
+
):
|
2224
|
+
ax.hist(numpy.asarray(d).flatten(), label=label, **kwargs)
|
2225
|
+
if title is not None:
|
2226
|
+
ax.set_title(title)
|
2227
|
+
if xlabel is not None:
|
2228
|
+
ax.set_xlabel(xlabel)
|
2229
|
+
if ylabel is not None:
|
2230
|
+
ax.set_ylabel(ylabel)
|
2231
|
+
if labels is not None:
|
2232
|
+
ax.legend()
|
2233
|
+
pyplot.tight_layout()
|
2234
|
+
if show:
|
2235
|
+
pyplot.show()
|
2236
|
+
|
2237
|
+
|
2005
2238
|
def _imshow(
|
2006
2239
|
ax: Axes,
|
2007
2240
|
image: NDArray[Any],
|
@@ -2022,6 +2255,13 @@ def _imshow(
|
|
2022
2255
|
|
2023
2256
|
"""
|
2024
2257
|
update_kwargs(kwargs, interpolation='none')
|
2258
|
+
location = kwargs.pop('location', 'bottom')
|
2259
|
+
if image.ndim == 3 and image.shape[2] in {3, 4}:
|
2260
|
+
# RGB(A)
|
2261
|
+
vmin = None
|
2262
|
+
vmax = None
|
2263
|
+
percentile = None
|
2264
|
+
colorbar = False
|
2025
2265
|
if percentile is not None:
|
2026
2266
|
if isinstance(percentile, Sequence):
|
2027
2267
|
percentile = percentile[0], percentile[1]
|
@@ -2034,7 +2274,7 @@ def _imshow(
|
|
2034
2274
|
or percentile[1] > 100
|
2035
2275
|
):
|
2036
2276
|
raise ValueError(f'{percentile=} out of range')
|
2037
|
-
vmin, vmax = numpy.
|
2277
|
+
vmin, vmax = numpy.nanpercentile(image, percentile)
|
2038
2278
|
pos = ax.imshow(image, vmin=vmin, vmax=vmax, **kwargs)
|
2039
2279
|
if colorbar:
|
2040
2280
|
if percentile is not None and vmin is not None and vmax is not None:
|
@@ -2045,7 +2285,7 @@ def _imshow(
|
|
2045
2285
|
if fig is not None:
|
2046
2286
|
if shrink is None:
|
2047
2287
|
shrink = 0.8
|
2048
|
-
fig.colorbar(pos, shrink=shrink, location=
|
2288
|
+
fig.colorbar(pos, shrink=shrink, location=location, ticks=ticks)
|
2049
2289
|
if title:
|
2050
2290
|
ax.set_title(title)
|
2051
2291
|
if not axis:
|
phasorpy/utils.py
CHANGED
@@ -104,7 +104,7 @@ def spectral_vector_denoise(
|
|
104
104
|
.. [4] Harman RC, Lang RT, Kercher EM, Leven P, and Spring BQ.
|
105
105
|
`Denoising multiplexed microscopy images in n-dimensional spectral space
|
106
106
|
<https://doi.org/10.1364/BOE.463979>`_.
|
107
|
-
*
|
107
|
+
*Biomed Opt Express*, 13(8): 4298-4309 (2022)
|
108
108
|
|
109
109
|
Examples
|
110
110
|
--------
|
@@ -201,7 +201,7 @@ def anscombe_transformation(
|
|
201
201
|
|
202
202
|
Parameters
|
203
203
|
----------
|
204
|
-
data: array_like
|
204
|
+
data : array_like
|
205
205
|
Noisy Poisson-distributed data to be transformed.
|
206
206
|
**kwargs
|
207
207
|
Optional `arguments passed to numpy universal functions
|
@@ -250,9 +250,9 @@ def anscombe_transformation_inverse(
|
|
250
250
|
|
251
251
|
Parameters
|
252
252
|
----------
|
253
|
-
data: array_like
|
253
|
+
data : array_like
|
254
254
|
Anscombe-transformed data.
|
255
|
-
approx: bool, default: False
|
255
|
+
approx : bool, default: False
|
256
256
|
If true, return approximation of exact unbiased inverse.
|
257
257
|
**kwargs
|
258
258
|
Optional `arguments passed to numpy universal functions
|
@@ -288,13 +288,13 @@ def anscombe_transformation_inverse(
|
|
288
288
|
`A closed-form approximation of the exact unbiased inverse of the
|
289
289
|
Anscombe variance-stabilizing transformation
|
290
290
|
<https://doi.org/10.1109/TIP.2011.2121085>`_.
|
291
|
-
IEEE Trans Image Process
|
291
|
+
*IEEE Trans Image Process*, 20(9): 2697-8 (2011).
|
292
292
|
|
293
293
|
.. [3] Makitalo M, and Foi A
|
294
294
|
`Optimal inversion of the generalized Anscombe transformation for
|
295
295
|
Poisson-Gaussian noise
|
296
296
|
<https://doi.org/10.1109/TIP.2012.2202675>`_,
|
297
|
-
IEEE Trans Image Process
|
297
|
+
*IEEE Trans Image Process*, 22(1): 91-103 (2013)
|
298
298
|
|
299
299
|
Examples
|
300
300
|
--------
|
@@ -317,7 +317,7 @@ def number_threads(
|
|
317
317
|
max_threads: int | None = None,
|
318
318
|
/,
|
319
319
|
) -> int:
|
320
|
-
"""Return number of threads for parallel computations
|
320
|
+
"""Return number of threads for parallel computations across CPU cores.
|
321
321
|
|
322
322
|
This function is used to parse ``num_threads`` parameters.
|
323
323
|
|
@@ -332,6 +332,11 @@ def number_threads(
|
|
332
332
|
max_threads : int, optional
|
333
333
|
Maximum number of threads to return.
|
334
334
|
|
335
|
+
Returns
|
336
|
+
-------
|
337
|
+
int
|
338
|
+
Number of threads for parallel computations.
|
339
|
+
|
335
340
|
Examples
|
336
341
|
--------
|
337
342
|
>>> number_threads()
|
phasorpy/version.py
CHANGED
@@ -1,24 +1,32 @@
|
|
1
|
-
"""Version information."""
|
1
|
+
"""Version information for PhasorPy and dependencies."""
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
|
5
|
+
__all__ = ['__version__', 'versions']
|
6
|
+
|
7
|
+
__version__ = '0.5'
|
6
8
|
|
7
9
|
|
8
10
|
def versions(
|
9
11
|
*, sep: str = '\n', dash: str = '-', verbose: bool = False
|
10
12
|
) -> str:
|
11
|
-
"""Return
|
13
|
+
"""Return version information for PhasorPy and its dependencies.
|
12
14
|
|
13
15
|
Parameters
|
14
16
|
----------
|
15
17
|
sep : str, optional
|
16
|
-
Separator between version items.
|
18
|
+
Separator between version items. Defaults to newline.
|
17
19
|
dash : str, optional
|
18
|
-
Separator between module name and version.
|
20
|
+
Separator between module name and version. Defaults to dash.
|
19
21
|
verbose : bool, optional
|
20
22
|
Include paths to Python interpreter and modules.
|
21
23
|
|
24
|
+
Returns
|
25
|
+
-------
|
26
|
+
str
|
27
|
+
Formatted string containing version information.
|
28
|
+
Format: "<package><dash><version>[<space>(<path>)]<sep>"
|
29
|
+
|
22
30
|
Example
|
23
31
|
-------
|
24
32
|
>>> print(versions())
|
@@ -44,6 +52,7 @@ def versions(
|
|
44
52
|
'lfdfiles',
|
45
53
|
'sdtfile',
|
46
54
|
'ptufile',
|
55
|
+
'liffile',
|
47
56
|
'matplotlib',
|
48
57
|
'scipy',
|
49
58
|
'skimage',
|