phasorpy 0.4__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 +382 -158
- phasorpy/_phasorpy.cp311-win_arm64.pyd +0 -0
- phasorpy/_phasorpy.pyx +54 -51
- phasorpy/_utils.py +89 -7
- phasorpy/cli.py +2 -0
- phasorpy/cluster.py +170 -0
- phasorpy/color.py +16 -11
- phasorpy/components.py +18 -18
- phasorpy/conftest.py +2 -0
- phasorpy/cursors.py +9 -9
- phasorpy/datasets.py +129 -51
- phasorpy/io.py +4 -0
- phasorpy/phasor.py +265 -96
- phasorpy/plot.py +251 -27
- phasorpy/utils.py +12 -7
- phasorpy/version.py +13 -5
- {phasorpy-0.4.dist-info → phasorpy-0.5.dist-info}/METADATA +10 -15
- phasorpy-0.5.dist-info/RECORD +26 -0
- {phasorpy-0.4.dist-info → phasorpy-0.5.dist-info}/WHEEL +1 -1
- phasorpy-0.4.dist-info/RECORD +0 -25
- {phasorpy-0.4.dist-info → phasorpy-0.5.dist-info}/entry_points.txt +0 -0
- {phasorpy-0.4.dist-info → phasorpy-0.5.dist-info/licenses}/LICENSE.txt +0 -0
- {phasorpy-0.4.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
|
|
@@ -75,7 +78,7 @@ class PhasorPlot:
|
|
75
78
|
Parameters
|
76
79
|
----------
|
77
80
|
allquadrants : bool, optional
|
78
|
-
Show all
|
81
|
+
Show all quadrants of phasor space.
|
79
82
|
By default, only the first quadrant with universal semicircle is shown.
|
80
83
|
ax : matplotlib axes, optional
|
81
84
|
Matplotlib axes used for plotting.
|
@@ -83,7 +86,7 @@ class PhasorPlot:
|
|
83
86
|
frequency : float, optional
|
84
87
|
Laser pulse or modulation frequency in MHz.
|
85
88
|
grid : bool, optional, default: True
|
86
|
-
Display polar grid or semicircle.
|
89
|
+
Display polar grid or universal semicircle.
|
87
90
|
**kwargs
|
88
91
|
Additional properties to set on `ax`.
|
89
92
|
|
@@ -221,7 +224,7 @@ class PhasorPlot:
|
|
221
224
|
label: Sequence[str] | None = None,
|
222
225
|
**kwargs: Any,
|
223
226
|
) -> list[Line2D]:
|
224
|
-
"""Plot
|
227
|
+
"""Plot imaginary versus real coordinates as markers or lines.
|
225
228
|
|
226
229
|
Parameters
|
227
230
|
----------
|
@@ -286,7 +289,7 @@ class PhasorPlot:
|
|
286
289
|
/,
|
287
290
|
**kwargs: Any,
|
288
291
|
) -> tuple[NDArray[Any], NDArray[Any], NDArray[Any]]:
|
289
|
-
"""Return
|
292
|
+
"""Return two-dimensional histogram of imag versus real coordinates."""
|
290
293
|
update_kwargs(kwargs, range=self._limits)
|
291
294
|
(xmin, xmax), (ymin, ymax) = kwargs['range']
|
292
295
|
assert xmax > xmin and ymax > ymin
|
@@ -319,7 +322,7 @@ class PhasorPlot:
|
|
319
322
|
/,
|
320
323
|
**kwargs: Any,
|
321
324
|
) -> None:
|
322
|
-
"""Plot
|
325
|
+
"""Plot two-dimensional histogram of imag versus real coordinates.
|
323
326
|
|
324
327
|
Parameters
|
325
328
|
----------
|
@@ -369,7 +372,9 @@ class PhasorPlot:
|
|
369
372
|
and :py:meth:`matplotlib.axes.Axes.contour`.
|
370
373
|
|
371
374
|
"""
|
372
|
-
|
375
|
+
if 'cmap' not in kwargs and 'colors' not in kwargs:
|
376
|
+
kwargs['cmap'] = 'Blues'
|
377
|
+
update_kwargs(kwargs, norm='log')
|
373
378
|
kwargs_hist2d = parse_kwargs(
|
374
379
|
kwargs, 'bins', 'range', 'density', 'weights'
|
375
380
|
)
|
@@ -969,9 +974,9 @@ class PhasorPlotFret(PhasorPlot):
|
|
969
974
|
acceptor_lifetime : array_like
|
970
975
|
Lifetime of acceptor in ns.
|
971
976
|
fret_efficiency : array_like, optional, default 0
|
972
|
-
FRET efficiency in range [0
|
973
|
-
|
974
|
-
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].
|
975
980
|
donor_bleedthrough : array_like, optional, default 0
|
976
981
|
Weight of donor fluorescence in acceptor channel
|
977
982
|
relative to fluorescence of fully sensitized acceptor.
|
@@ -1022,7 +1027,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1022
1027
|
_donor_lifetime_slider: Slider
|
1023
1028
|
_acceptor_lifetime_slider: Slider
|
1024
1029
|
_fret_efficiency_slider: Slider
|
1025
|
-
|
1030
|
+
_donor_fretting_slider: Slider
|
1026
1031
|
_donor_bleedthrough_slider: Slider
|
1027
1032
|
_acceptor_bleedthrough_slider: Slider
|
1028
1033
|
_acceptor_background_slider: Slider
|
@@ -1053,7 +1058,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1053
1058
|
donor_lifetime: float = 4.2,
|
1054
1059
|
acceptor_lifetime: float = 3.0,
|
1055
1060
|
fret_efficiency: float = 0.5,
|
1056
|
-
|
1061
|
+
donor_fretting: float = 1.0,
|
1057
1062
|
donor_bleedthrough: float = 0.0,
|
1058
1063
|
acceptor_bleedthrough: float = 0.0,
|
1059
1064
|
acceptor_background: float = 0.0,
|
@@ -1103,7 +1108,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1103
1108
|
frequency,
|
1104
1109
|
donor_lifetime,
|
1105
1110
|
fret_efficiency=self._fret_efficiencies,
|
1106
|
-
|
1111
|
+
donor_fretting=donor_fretting,
|
1107
1112
|
donor_background=donor_background,
|
1108
1113
|
background_real=background_real,
|
1109
1114
|
background_imag=background_imag,
|
@@ -1116,7 +1121,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1116
1121
|
donor_lifetime,
|
1117
1122
|
acceptor_lifetime,
|
1118
1123
|
fret_efficiency=self._fret_efficiencies,
|
1119
|
-
|
1124
|
+
donor_fretting=donor_fretting,
|
1120
1125
|
donor_bleedthrough=donor_bleedthrough,
|
1121
1126
|
acceptor_bleedthrough=acceptor_bleedthrough,
|
1122
1127
|
acceptor_background=acceptor_background,
|
@@ -1135,7 +1140,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1135
1140
|
)
|
1136
1141
|
self._acceptor_semicircle_line = lines[0]
|
1137
1142
|
|
1138
|
-
if
|
1143
|
+
if donor_fretting < 1.0 and donor_background == 0.0:
|
1139
1144
|
lines = self.line(
|
1140
1145
|
[donor_real, donor_fret_real],
|
1141
1146
|
[donor_imag, donor_fret_imag],
|
@@ -1285,18 +1290,18 @@ class PhasorPlotFret(PhasorPlot):
|
|
1285
1290
|
)
|
1286
1291
|
self._fret_efficiency_slider.on_changed(self._on_changed)
|
1287
1292
|
|
1288
|
-
self.
|
1293
|
+
self._donor_fretting_slider = Slider(
|
1289
1294
|
ax=axes[6],
|
1290
|
-
label='Donors
|
1295
|
+
label='Donors fretting ',
|
1291
1296
|
valfmt=' %.2f',
|
1292
1297
|
valmin=0.0,
|
1293
1298
|
valmax=1.0,
|
1294
1299
|
valstep=0.01,
|
1295
|
-
valinit=
|
1300
|
+
valinit=donor_fretting,
|
1296
1301
|
# facecolor='tab:green',
|
1297
1302
|
handle_style={'edgecolor': 'tab:green'},
|
1298
1303
|
)
|
1299
|
-
self.
|
1304
|
+
self._donor_fretting_slider.on_changed(self._on_changed)
|
1300
1305
|
|
1301
1306
|
self._donor_bleedthrough_slider = Slider(
|
1302
1307
|
ax=axes[5],
|
@@ -1398,7 +1403,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1398
1403
|
donor_lifetime = self._donor_lifetime_slider.val
|
1399
1404
|
acceptor_lifetime = self._acceptor_lifetime_slider.val
|
1400
1405
|
fret_efficiency = self._fret_efficiency_slider.val
|
1401
|
-
|
1406
|
+
donor_fretting = self._donor_fretting_slider.val
|
1402
1407
|
donor_bleedthrough = self._donor_bleedthrough_slider.val
|
1403
1408
|
acceptor_bleedthrough = self._acceptor_bleedthrough_slider.val
|
1404
1409
|
acceptor_background = self._acceptor_background_slider.val
|
@@ -1420,7 +1425,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1420
1425
|
frequency,
|
1421
1426
|
donor_lifetime,
|
1422
1427
|
fret_efficiency=self._fret_efficiencies,
|
1423
|
-
|
1428
|
+
donor_fretting=donor_fretting,
|
1424
1429
|
donor_background=donor_background,
|
1425
1430
|
background_real=background_real,
|
1426
1431
|
background_imag=background_imag,
|
@@ -1433,7 +1438,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1433
1438
|
donor_lifetime,
|
1434
1439
|
acceptor_lifetime,
|
1435
1440
|
fret_efficiency=self._fret_efficiencies,
|
1436
|
-
|
1441
|
+
donor_fretting=donor_fretting,
|
1437
1442
|
donor_bleedthrough=donor_bleedthrough,
|
1438
1443
|
acceptor_bleedthrough=acceptor_bleedthrough,
|
1439
1444
|
acceptor_background=acceptor_background,
|
@@ -1449,7 +1454,7 @@ class PhasorPlotFret(PhasorPlot):
|
|
1449
1454
|
else:
|
1450
1455
|
self._donor_background_line.set_data([0.0, 0.0], [0.0, 0.0])
|
1451
1456
|
|
1452
|
-
if
|
1457
|
+
if donor_fretting < 1.0 and donor_background == 0.0:
|
1453
1458
|
self._donor_donor_line.set_data(
|
1454
1459
|
[donor_real, donor_fret_real],
|
1455
1460
|
[donor_imag, donor_fret_imag],
|
@@ -1719,7 +1724,7 @@ def plot_phasor_image(
|
|
1719
1724
|
percentile : float, optional
|
1720
1725
|
The (q, 100-q) percentiles of image data are covered by colormaps.
|
1721
1726
|
By default, the complete value range of `mean` is covered,
|
1722
|
-
for `real` and `imag` the range [-1
|
1727
|
+
for `real` and `imag` the range [-1, 1].
|
1723
1728
|
title : str, optional
|
1724
1729
|
Figure title.
|
1725
1730
|
show : bool, optional, default: True
|
@@ -1862,6 +1867,7 @@ def plot_signal_image(
|
|
1862
1867
|
axis: int | str | None = None,
|
1863
1868
|
percentile: float | Sequence[float] | None = None,
|
1864
1869
|
title: str | None = None,
|
1870
|
+
xlabel: str | None = None,
|
1865
1871
|
show: bool = True,
|
1866
1872
|
**kwargs: Any,
|
1867
1873
|
) -> None:
|
@@ -1884,9 +1890,11 @@ def plot_signal_image(
|
|
1884
1890
|
percentile : float or [float, float], optional
|
1885
1891
|
The [q, 100-q] percentiles of image data are covered by colormaps.
|
1886
1892
|
By default, the complete value range of `mean` is covered,
|
1887
|
-
for `real` and `imag` the range [-1
|
1893
|
+
for `real` and `imag` the range [-1, 1].
|
1888
1894
|
title : str, optional
|
1889
1895
|
Figure title.
|
1896
|
+
xlabel : str, optional
|
1897
|
+
Label of axis over which phasor coordinates would be computed.
|
1890
1898
|
show : bool, optional, default: True
|
1891
1899
|
Display figure.
|
1892
1900
|
**kwargs
|
@@ -1941,6 +1949,11 @@ def plot_signal_image(
|
|
1941
1949
|
ax.set_title(f'{axis=}')
|
1942
1950
|
ax.plot(numpy.nanmean(signal, axis=tuple(axes)))
|
1943
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)
|
1956
|
+
|
1944
1957
|
# image
|
1945
1958
|
axes = list(sorted(axes[:-2] + [axis]))
|
1946
1959
|
ax = fig.add_subplot(gs[0, 0])
|
@@ -1950,7 +1963,159 @@ def plot_signal_image(
|
|
1950
1963
|
percentile=percentile,
|
1951
1964
|
shrink=0.5,
|
1952
1965
|
title='mean',
|
1966
|
+
**kwargs,
|
1967
|
+
)
|
1968
|
+
|
1969
|
+
if show:
|
1970
|
+
pyplot.show()
|
1971
|
+
|
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
|
1953
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)
|
1954
2119
|
|
1955
2120
|
if show:
|
1956
2121
|
pyplot.show()
|
@@ -2018,6 +2183,58 @@ def plot_polar_frequency(
|
|
2018
2183
|
pyplot.show()
|
2019
2184
|
|
2020
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
|
+
|
2021
2238
|
def _imshow(
|
2022
2239
|
ax: Axes,
|
2023
2240
|
image: NDArray[Any],
|
@@ -2038,6 +2255,13 @@ def _imshow(
|
|
2038
2255
|
|
2039
2256
|
"""
|
2040
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
|
2041
2265
|
if percentile is not None:
|
2042
2266
|
if isinstance(percentile, Sequence):
|
2043
2267
|
percentile = percentile[0], percentile[1]
|
@@ -2050,7 +2274,7 @@ def _imshow(
|
|
2050
2274
|
or percentile[1] > 100
|
2051
2275
|
):
|
2052
2276
|
raise ValueError(f'{percentile=} out of range')
|
2053
|
-
vmin, vmax = numpy.
|
2277
|
+
vmin, vmax = numpy.nanpercentile(image, percentile)
|
2054
2278
|
pos = ax.imshow(image, vmin=vmin, vmax=vmax, **kwargs)
|
2055
2279
|
if colorbar:
|
2056
2280
|
if percentile is not None and vmin is not None and vmax is not None:
|
@@ -2061,7 +2285,7 @@ def _imshow(
|
|
2061
2285
|
if fig is not None:
|
2062
2286
|
if shrink is None:
|
2063
2287
|
shrink = 0.8
|
2064
|
-
fig.colorbar(pos, shrink=shrink, location=
|
2288
|
+
fig.colorbar(pos, shrink=shrink, location=location, ticks=ticks)
|
2065
2289
|
if title:
|
2066
2290
|
ax.set_title(title)
|
2067
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())
|
@@ -1,9 +1,9 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: phasorpy
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5
|
4
4
|
Summary: Analysis of fluorescence lifetime and hyperspectral images using the phasor approach
|
5
5
|
Author: PhasorPy Contributors
|
6
|
-
License: MIT
|
6
|
+
License-Expression: MIT
|
7
7
|
Project-URL: Homepage, https://www.phasorpy.org
|
8
8
|
Project-URL: Documentation, https://www.phasorpy.org/docs/stable/
|
9
9
|
Project-URL: Download, https://pypi.org/project/phasorpy/#files
|
@@ -13,25 +13,24 @@ Project-URL: Release notes, https://www.phasorpy.org/docs/stable/release
|
|
13
13
|
Classifier: Development Status :: 3 - Alpha
|
14
14
|
Classifier: Intended Audience :: Developers
|
15
15
|
Classifier: Intended Audience :: Science/Research
|
16
|
-
Classifier: License :: OSI Approved :: MIT License
|
17
16
|
Classifier: Programming Language :: Python
|
18
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
19
18
|
Classifier: Operating System :: OS Independent
|
20
19
|
Classifier: Programming Language :: Python :: 3
|
21
20
|
Classifier: Programming Language :: Python :: 3 :: Only
|
22
|
-
Classifier: Programming Language :: Python :: 3.10
|
23
21
|
Classifier: Programming Language :: Python :: 3.11
|
24
22
|
Classifier: Programming Language :: Python :: 3.12
|
25
23
|
Classifier: Programming Language :: Python :: 3.13
|
26
|
-
Requires-Python: >=3.
|
24
|
+
Requires-Python: >=3.11
|
27
25
|
Description-Content-Type: text/markdown
|
28
26
|
License-File: LICENSE.txt
|
29
|
-
Requires-Dist: numpy>=1.
|
30
|
-
Requires-Dist: matplotlib>=3.
|
27
|
+
Requires-Dist: numpy>=1.25.0
|
28
|
+
Requires-Dist: matplotlib>=3.8.0
|
31
29
|
Requires-Dist: scipy>=1.11.0
|
32
30
|
Requires-Dist: click
|
33
31
|
Requires-Dist: pooch
|
34
32
|
Requires-Dist: tqdm
|
33
|
+
Requires-Dist: scikit-learn>=1.5.0
|
35
34
|
Requires-Dist: xarray>=2023.4.0
|
36
35
|
Requires-Dist: tifffile>=2024.8.30
|
37
36
|
Provides-Extra: docs
|
@@ -42,17 +41,13 @@ Requires-Dist: sphinx-copybutton; extra == "docs"
|
|
42
41
|
Requires-Dist: sphinx_click; extra == "docs"
|
43
42
|
Requires-Dist: pydata-sphinx-theme>=0.16.0; extra == "docs"
|
44
43
|
Requires-Dist: numpydoc; extra == "docs"
|
45
|
-
Provides-Extra: test
|
46
|
-
Requires-Dist: pytest; extra == "test"
|
47
|
-
Requires-Dist: pytest-cov; extra == "test"
|
48
|
-
Requires-Dist: pytest-runner; extra == "test"
|
49
|
-
Requires-Dist: pytest-doctestplus; extra == "test"
|
50
|
-
Requires-Dist: coverage; extra == "test"
|
51
44
|
Provides-Extra: all
|
52
45
|
Requires-Dist: lfdfiles>=2024.5.24; extra == "all"
|
53
46
|
Requires-Dist: sdtfile>=2024.5.24; extra == "all"
|
54
47
|
Requires-Dist: ptufile>=2024.9.14; extra == "all"
|
55
|
-
Requires-Dist: liffile>=2025.
|
48
|
+
Requires-Dist: liffile>=2025.2.10; extra == "all"
|
49
|
+
Requires-Dist: pawflim; extra == "all"
|
50
|
+
Dynamic: license-file
|
56
51
|
|
57
52
|
# PhasorPy
|
58
53
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
phasorpy/__init__.py,sha256=SwOTreV7wd8ZEL3waXQlgbNnsErWJ0dh6A2d77DWp0Y,254
|
2
|
+
phasorpy/__main__.py,sha256=0u6C98HYfajV1RoUww8kAc0CxdsON0ijgEyTYExCSLM,149
|
3
|
+
phasorpy/_io.py,sha256=iT6yzCCbzW3R5OvN2aDuGgfAhfzTXQDOIyRCNnSxdnA,86658
|
4
|
+
phasorpy/_phasorpy.cp311-win_arm64.pyd,sha256=Cbv9nTwipiXeZ1133gKiZYiAhN2mCduArSphmDh1KwY,704512
|
5
|
+
phasorpy/_phasorpy.pyx,sha256=0miKMEcc1dsohc252uTFiEWUdthzwx7jNVLDuQKZGPY,64124
|
6
|
+
phasorpy/_typing.py,sha256=ii-5-8KTs2BZq0Ytu3yJl8ejSQj1V06c1_Jcwa_2Snk,1324
|
7
|
+
phasorpy/_utils.py,sha256=5x3mDxabSBq52aO1hUkeIVsqBsoBfs5FEcCLB0aFZgU,17401
|
8
|
+
phasorpy/cli.py,sha256=_p0NYuA3EYgz5OI3Jvpo0G48UO6hhMuo5nHOTMUO74o,2004
|
9
|
+
phasorpy/cluster.py,sha256=Ai3jrBKTwL0VJ0T61NL_FPB88Xgo7YVP1c-FLSKmUs0,5001
|
10
|
+
phasorpy/color.py,sha256=Y0XINGWDI5DxTUO9FnwYbf3oZq9IB2XagoJOdXhEsvQ,17378
|
11
|
+
phasorpy/components.py,sha256=qIZ91o22Dua0Dx189t-UGkO2AEQD296INTAUHYoomtA,10455
|
12
|
+
phasorpy/conftest.py,sha256=0dCO8UZtEnhZv-JW1_vGvPZOmaihRLOo_Wc857socWI,976
|
13
|
+
phasorpy/cursors.py,sha256=1KzsfZBD-kKLdjiMUC3ZIKjSnVtnUwggVlt883EmcRo,15571
|
14
|
+
phasorpy/datasets.py,sha256=EggCWJnpHIHuobRV7aEBNM44B79hMzInNA_lEnMZum8,20870
|
15
|
+
phasorpy/io.py,sha256=xvQD8xGYCxp6LRFRTDguMUeXFSUG29knNd3HPWkTyjg,237
|
16
|
+
phasorpy/phasor.py,sha256=NeFmuYEvg9YMlL83sLkhKLO6IJepP5uZsc6BRCYRpuQ,119885
|
17
|
+
phasorpy/plot.py,sha256=Jkdwjubhm8rKQuraESW0Sn6tHHxGyryjDBj5n85oTyw,77423
|
18
|
+
phasorpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
|
+
phasorpy/utils.py,sha256=lBvYpS3WNLIjYcZ2kv1X6V5rFT3zNBqGsnJMEGqay1M,11770
|
20
|
+
phasorpy/version.py,sha256=pz2RAbZKrk1cd3jzmZ4lQOry9UzcBMxBO_WGjVpK360,2053
|
21
|
+
phasorpy-0.5.dist-info/licenses/LICENSE.txt,sha256=KVzeDa0MBRSUYPFFNuo7Atn6v62TiJTgGzHigltEX0o,1104
|
22
|
+
phasorpy-0.5.dist-info/METADATA,sha256=ULBHKOkw7nFpSd-M9_xUlHUEHJb3_jaTgdaqN8x6W6o,3322
|
23
|
+
phasorpy-0.5.dist-info/WHEEL,sha256=sBhYaL21dqiXhQM5J-ifdGDkONDmlqxO0u3ZWpw49mA,101
|
24
|
+
phasorpy-0.5.dist-info/entry_points.txt,sha256=VRhsl3qGiIKwtMraKapmduchTMbdReUi1AoVTe9f3ss,47
|
25
|
+
phasorpy-0.5.dist-info/top_level.txt,sha256=4Y0uYzya5R2loleAxZ6s2n53_FysUbgFTfFaU0i9rbo,9
|
26
|
+
phasorpy-0.5.dist-info/RECORD,,
|