phasorpy 0.6__cp311-cp311-win_arm64.whl → 0.7__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/__init__.py +1 -1
- phasorpy/_phasorpy.cp311-win_arm64.pyd +0 -0
- phasorpy/_phasorpy.pyx +281 -9
- phasorpy/_utils.py +101 -28
- phasorpy/cli.py +19 -1
- phasorpy/cluster.py +10 -16
- phasorpy/color.py +11 -7
- phasorpy/{components.py → component.py} +255 -32
- phasorpy/{cursors.py → cursor.py} +31 -33
- phasorpy/datasets.py +117 -7
- phasorpy/experimental.py +8 -10
- phasorpy/io/__init__.py +1 -0
- phasorpy/io/_flimlabs.py +20 -10
- phasorpy/io/_leica.py +3 -1
- phasorpy/io/_ometiff.py +2 -3
- phasorpy/io/_other.py +115 -7
- phasorpy/io/_simfcs.py +41 -16
- phasorpy/lifetime.py +2058 -0
- phasorpy/phasor.py +71 -1947
- phasorpy/plot/_functions.py +8 -2
- phasorpy/plot/_lifetime_plots.py +33 -23
- phasorpy/plot/_phasorplot.py +547 -159
- phasorpy/plot/_phasorplot_fret.py +11 -9
- phasorpy/utils.py +21 -10
- {phasorpy-0.6.dist-info → phasorpy-0.7.dist-info}/METADATA +2 -2
- phasorpy-0.7.dist-info/RECORD +35 -0
- phasorpy-0.6.dist-info/RECORD +0 -34
- {phasorpy-0.6.dist-info → phasorpy-0.7.dist-info}/WHEEL +0 -0
- {phasorpy-0.6.dist-info → phasorpy-0.7.dist-info}/entry_points.txt +0 -0
- {phasorpy-0.6.dist-info → phasorpy-0.7.dist-info}/licenses/LICENSE.txt +0 -0
- {phasorpy-0.6.dist-info → phasorpy-0.7.dist-info}/top_level.txt +0 -0
phasorpy/io/_other.py
CHANGED
@@ -8,11 +8,13 @@ __all__ = [
|
|
8
8
|
'phasor_from_ifli',
|
9
9
|
'signal_from_imspector_tiff',
|
10
10
|
'signal_from_lsm',
|
11
|
+
'signal_from_pqbin',
|
11
12
|
'signal_from_ptu',
|
12
13
|
'signal_from_sdt',
|
13
14
|
]
|
14
15
|
|
15
16
|
import os
|
17
|
+
import struct
|
16
18
|
from typing import TYPE_CHECKING
|
17
19
|
from xml.etree import ElementTree
|
18
20
|
|
@@ -48,7 +50,7 @@ def signal_from_sdt(
|
|
48
50
|
filename : str or Path
|
49
51
|
Name of Becker & Hickl SDT file to read.
|
50
52
|
index : int, optional, default: 0
|
51
|
-
Index of dataset to read
|
53
|
+
Index of dataset to read if the file contains multiple datasets.
|
52
54
|
|
53
55
|
Returns
|
54
56
|
-------
|
@@ -63,7 +65,7 @@ def signal_from_sdt(
|
|
63
65
|
Raises
|
64
66
|
------
|
65
67
|
ValueError
|
66
|
-
File is not
|
68
|
+
File is not an SDT file containing TCSPC histogram.
|
67
69
|
|
68
70
|
Notes
|
69
71
|
-----
|
@@ -127,6 +129,7 @@ def signal_from_ptu(
|
|
127
129
|
channel: int | None = 0,
|
128
130
|
dtime: int | None = 0,
|
129
131
|
keepdims: bool = False,
|
132
|
+
**kwargs: Any,
|
130
133
|
) -> DataArray:
|
131
134
|
"""Return TCSPC histogram and metadata from PicoQuant PTU T3 mode file.
|
132
135
|
|
@@ -141,7 +144,7 @@ def signal_from_ptu(
|
|
141
144
|
Indices for all dimensions of image mode files:
|
142
145
|
|
143
146
|
- ``None``: return all items along axis (default).
|
144
|
-
- ``Ellipsis
|
147
|
+
- ``Ellipsis`` (``...``): return all items along multiple axes.
|
145
148
|
- ``int``: return single item along axis.
|
146
149
|
- ``slice``: return chunk of axis.
|
147
150
|
``slice.step`` is a binning factor.
|
@@ -149,7 +152,7 @@ def signal_from_ptu(
|
|
149
152
|
|
150
153
|
trimdims : str, optional, default: 'TCH'
|
151
154
|
Axes to trim.
|
152
|
-
dtype :
|
155
|
+
dtype : dtype_like, optional, default: uint16
|
153
156
|
Unsigned integer type of TCSPC histogram.
|
154
157
|
Increase the bit depth to avoid overflows when integrating.
|
155
158
|
frame : int, optional
|
@@ -168,6 +171,9 @@ def signal_from_ptu(
|
|
168
171
|
Overrides `selection` for axis ``H``.
|
169
172
|
keepdims : bool, optional, default: False
|
170
173
|
If true, return reduced axes as size-one dimensions.
|
174
|
+
**kwargs
|
175
|
+
Additional arguments passed to :py:meth:`PtuFile.decode_image`
|
176
|
+
or :py:meth:`PtuFile.decode_histogram`.
|
171
177
|
|
172
178
|
Returns
|
173
179
|
-------
|
@@ -214,6 +220,8 @@ def signal_from_ptu(
|
|
214
220
|
import ptufile
|
215
221
|
from xarray import DataArray
|
216
222
|
|
223
|
+
kwargs.pop('records', None)
|
224
|
+
|
217
225
|
with ptufile.PtuFile(filename, trimdims=trimdims) as ptu:
|
218
226
|
if not ptu.is_t3:
|
219
227
|
raise ValueError(f'{ptu.filename!r} is not a T3 mode PTU file')
|
@@ -226,6 +234,7 @@ def signal_from_ptu(
|
|
226
234
|
dtime=dtime,
|
227
235
|
keepdims=keepdims,
|
228
236
|
asxarray=True,
|
237
|
+
**kwargs,
|
229
238
|
)
|
230
239
|
assert isinstance(data, DataArray)
|
231
240
|
elif ptu.measurement_submode == 1:
|
@@ -233,7 +242,7 @@ def signal_from_ptu(
|
|
233
242
|
if dtime == -1:
|
234
243
|
raise ValueError(f'{dtime=} not supported for point mode')
|
235
244
|
data = ptu.decode_histogram(
|
236
|
-
dtype=dtype, dtime=dtime, asxarray=True
|
245
|
+
dtype=dtype, dtime=dtime, asxarray=True, **kwargs
|
237
246
|
)
|
238
247
|
assert isinstance(data, DataArray)
|
239
248
|
if channel is not None:
|
@@ -263,7 +272,7 @@ def signal_from_lsm(
|
|
263
272
|
) -> DataArray:
|
264
273
|
"""Return hyperspectral image and metadata from Zeiss LSM file.
|
265
274
|
|
266
|
-
LSM files contain multi-dimensional images and metadata from laser
|
275
|
+
Zeiss LSM files contain multi-dimensional images and metadata from laser
|
267
276
|
scanning microscopy measurements. The file format is based on TIFF.
|
268
277
|
|
269
278
|
Parameters
|
@@ -542,7 +551,7 @@ def phasor_from_ifli(
|
|
542
551
|
Index of channel to return.
|
543
552
|
By default, return the first channel.
|
544
553
|
If None, return all channels.
|
545
|
-
harmonic : int, sequence of int, or 'all', optional
|
554
|
+
harmonic : int, sequence of int, 'any', or 'all', optional
|
546
555
|
Harmonic(s) to return from file.
|
547
556
|
If None (default), return the first harmonic stored in file.
|
548
557
|
If `'all'`, return all harmonics of first frequency stored in file.
|
@@ -780,3 +789,102 @@ def signal_from_flif(
|
|
780
789
|
from xarray import DataArray
|
781
790
|
|
782
791
|
return DataArray(data, **metadata)
|
792
|
+
|
793
|
+
|
794
|
+
def signal_from_pqbin(
|
795
|
+
filename: str | PathLike[Any],
|
796
|
+
/,
|
797
|
+
) -> DataArray:
|
798
|
+
"""Return TCSPC histogram and metadata from PicoQuant BIN file.
|
799
|
+
|
800
|
+
PicoQuant BIN files contain TCSPC histograms with limited metadata.
|
801
|
+
|
802
|
+
Parameters
|
803
|
+
----------
|
804
|
+
filename : str or Path
|
805
|
+
Name of PicoQuant BIN file to read.
|
806
|
+
|
807
|
+
Returns
|
808
|
+
-------
|
809
|
+
xarray.DataArray
|
810
|
+
TCSPC histogram with :ref:`axes codes <axes>` ``'YXH'``,
|
811
|
+
and type ``uint32``.
|
812
|
+
|
813
|
+
- ``coords['H']``: delay-times of histogram bins in ns.
|
814
|
+
- ``attrs['frequency']``: repetition frequency in MHz.
|
815
|
+
This assumes that the histogram contains exactly one period.
|
816
|
+
|
817
|
+
Raises
|
818
|
+
------
|
819
|
+
ValueError
|
820
|
+
File is not a PicoQuant BIN file.
|
821
|
+
|
822
|
+
Examples
|
823
|
+
--------
|
824
|
+
>>> signal = signal_from_pqbin('picoquant.bin') # doctest: +SKIP
|
825
|
+
>>> signal.values # doctest: +SKIP
|
826
|
+
array(...)
|
827
|
+
>>> signal.dtype # doctest: +SKIP
|
828
|
+
dtype('uint32')
|
829
|
+
>>> signal.shape # doctest: +SKIP
|
830
|
+
(256, 256, 2000)
|
831
|
+
>>> signal.dims # doctest: +SKIP
|
832
|
+
('Y', 'X', 'H')
|
833
|
+
>>> signal.coords['H'].data # doctest: +SKIP
|
834
|
+
array([0, ..., 49.975])
|
835
|
+
>>> signal.attrs['frequency'] # doctest: +SKIP
|
836
|
+
19.99
|
837
|
+
|
838
|
+
"""
|
839
|
+
with open(filename, 'rb') as fh:
|
840
|
+
header = fh.read(20)
|
841
|
+
if len(header) != 20:
|
842
|
+
raise ValueError(
|
843
|
+
f'invalid PicoQuant BIN header length {len(header)} != 20'
|
844
|
+
)
|
845
|
+
(size_x, size_y, pixel_resolution, size_h, tcspc_resolution) = (
|
846
|
+
struct.unpack('<IIfIf', header)
|
847
|
+
)
|
848
|
+
size = size_y * size_x * size_h * 4
|
849
|
+
|
850
|
+
# check the header values against arbitrary but reasonable limits
|
851
|
+
# to detect invalid files and prevent memory errors
|
852
|
+
if (
|
853
|
+
size <= 0
|
854
|
+
or size > 2**35 - 1 # 32 GiB
|
855
|
+
or size_x > 16384
|
856
|
+
or size_y > 16384
|
857
|
+
or size_h > 16384
|
858
|
+
or pixel_resolution < 0.0
|
859
|
+
or pixel_resolution > 1.0
|
860
|
+
or tcspc_resolution <= 0.0
|
861
|
+
or tcspc_resolution > 1.0
|
862
|
+
):
|
863
|
+
raise ValueError('invalid PicoQuant BIN file header')
|
864
|
+
|
865
|
+
shape = size_y, size_x, size_h
|
866
|
+
data = numpy.empty(shape, '<u4')
|
867
|
+
if fh.readinto(data) != size:
|
868
|
+
raise ValueError('invalid PicoQuant BIN data size')
|
869
|
+
|
870
|
+
metadata = xarray_metadata(
|
871
|
+
('Y', 'X', 'H'),
|
872
|
+
shape,
|
873
|
+
filename,
|
874
|
+
attrs={
|
875
|
+
'frequency': 1000.0 / (size_h * tcspc_resolution), # MHz
|
876
|
+
'pixel_resolution': pixel_resolution, # um
|
877
|
+
'tcspc_resolution': tcspc_resolution, # ns
|
878
|
+
},
|
879
|
+
Y=numpy.linspace(
|
880
|
+
0, size_y * pixel_resolution * 1e-6, size_y, endpoint=False
|
881
|
+
),
|
882
|
+
X=numpy.linspace(
|
883
|
+
0, size_x * pixel_resolution * 1e-6, size_x, endpoint=False
|
884
|
+
),
|
885
|
+
H=numpy.linspace(0, size_h * tcspc_resolution, size_h, endpoint=False),
|
886
|
+
)
|
887
|
+
|
888
|
+
from xarray import DataArray
|
889
|
+
|
890
|
+
return DataArray(data, **metadata)
|
phasorpy/io/_simfcs.py
CHANGED
@@ -12,6 +12,7 @@ __all__ = [
|
|
12
12
|
'signal_from_z64',
|
13
13
|
]
|
14
14
|
|
15
|
+
import math
|
15
16
|
import os
|
16
17
|
import struct
|
17
18
|
import zlib
|
@@ -75,9 +76,11 @@ def phasor_to_simfcs_referenced(
|
|
75
76
|
Harmonics must be starting at and increasing by one.
|
76
77
|
size : int, optional
|
77
78
|
Size of X and Y dimensions of square-sized images stored in file.
|
79
|
+
Must be in range [4, 65535].
|
78
80
|
By default, ``size = min(256, max(4, sizey, sizex))``.
|
79
81
|
dims : sequence of str, optional
|
80
82
|
Character codes for `mean` dimensions used to format file names.
|
83
|
+
Only used when chunking multi-dimensional data into multiple files.
|
81
84
|
|
82
85
|
See Also
|
83
86
|
--------
|
@@ -180,17 +183,21 @@ def phasor_from_simfcs_referenced(
|
|
180
183
|
) -> tuple[NDArray[Any], NDArray[Any], NDArray[Any], dict[str, Any]]:
|
181
184
|
"""Return phasor coordinates and metadata from SimFCS REF or R64 file.
|
182
185
|
|
183
|
-
SimFCS referenced REF and R64 files contain phasor
|
184
|
-
(encoded as phase and modulation) for two harmonics.
|
186
|
+
SimFCS referenced REF and R64 files contain square-shaped phasor
|
187
|
+
coordinate images (encoded as phase and modulation) for two harmonics.
|
185
188
|
Phasor coordinates from lifetime-resolved signals are calibrated.
|
189
|
+
Variants of referenced files (RE<n>) written by other software may
|
190
|
+
contain up to eight harmonics and may be uncalibrated.
|
186
191
|
|
187
192
|
Parameters
|
188
193
|
----------
|
189
194
|
filename : str or Path
|
190
|
-
Name of SimFCS REF or
|
191
|
-
harmonic : int
|
195
|
+
Name of SimFCS REF, R64, or RE<n> file to read.
|
196
|
+
harmonic : int, sequence of int, or 'all', optional
|
192
197
|
Harmonic(s) to include in returned phasor coordinates.
|
193
198
|
By default, only the first harmonic is returned.
|
199
|
+
If 'all', return all available harmonics.
|
200
|
+
If int or sequence, return specified harmonic(s).
|
194
201
|
|
195
202
|
Returns
|
196
203
|
-------
|
@@ -203,7 +210,7 @@ def phasor_from_simfcs_referenced(
|
|
203
210
|
Image of imaginary component of phasor coordinates.
|
204
211
|
Multiple harmonics, if any, are in the first axis.
|
205
212
|
attrs : dict
|
206
|
-
Select metadata:
|
213
|
+
Select metadata containing:
|
207
214
|
|
208
215
|
- ``'dims'`` (tuple of str):
|
209
216
|
:ref:`Axes codes <axes>` for `mean` image dimensions.
|
@@ -211,7 +218,7 @@ def phasor_from_simfcs_referenced(
|
|
211
218
|
Raises
|
212
219
|
------
|
213
220
|
lfdfiles.LfdfileError
|
214
|
-
File is not a SimFCS REF or
|
221
|
+
File is not a SimFCS REF, R64, or RE<n> file.
|
215
222
|
|
216
223
|
See Also
|
217
224
|
--------
|
@@ -219,7 +226,7 @@ def phasor_from_simfcs_referenced(
|
|
219
226
|
|
220
227
|
Notes
|
221
228
|
-----
|
222
|
-
The implementation is based on the
|
229
|
+
The implementation for reading R64 files is based on the
|
223
230
|
`lfdfiles <https://github.com/cgohlke/lfdfiles/>`__ library.
|
224
231
|
|
225
232
|
Examples
|
@@ -232,17 +239,35 @@ def phasor_from_simfcs_referenced(
|
|
232
239
|
array([[...]], dtype=float32)
|
233
240
|
|
234
241
|
"""
|
235
|
-
import lfdfiles
|
236
|
-
|
237
242
|
ext = os.path.splitext(filename)[-1].lower()
|
238
243
|
if ext == '.r64':
|
244
|
+
import lfdfiles
|
245
|
+
|
239
246
|
with lfdfiles.SimfcsR64(filename) as r64:
|
240
247
|
data = r64.asarray()
|
241
|
-
elif ext ==
|
242
|
-
|
243
|
-
|
248
|
+
elif ext.startswith('.re') and len(ext) == 4:
|
249
|
+
if ext[-1] == 'f':
|
250
|
+
num_images = 5
|
251
|
+
elif ext[-1].isdigit():
|
252
|
+
# non-SimFCS referenced files containing other number of harmonics
|
253
|
+
num_images = int(ext[-1]) * 2 + 1
|
254
|
+
else:
|
255
|
+
raise ValueError(
|
256
|
+
f'file extension must be .ref, .r64, or .re<n>, not {ext!r}'
|
257
|
+
)
|
258
|
+
size = os.path.getsize(filename)
|
259
|
+
if (
|
260
|
+
size > 4294967295
|
261
|
+
or size % (num_images * 4)
|
262
|
+
or not math.sqrt(size // (num_images * 4)).is_integer()
|
263
|
+
):
|
264
|
+
raise ValueError(f'{filename!r} is not a valid referenced file')
|
265
|
+
size = int(math.sqrt(size // (num_images * 4)))
|
266
|
+
data = numpy.fromfile(filename, dtype='<f4').reshape((-1, size, size))
|
244
267
|
else:
|
245
|
-
raise ValueError(
|
268
|
+
raise ValueError(
|
269
|
+
f'file extension must be .ref, .r64, or .re<n>, not {ext!r}'
|
270
|
+
)
|
246
271
|
|
247
272
|
harmonic, keep_harmonic_dim = parse_harmonic(harmonic, data.shape[0] // 2)
|
248
273
|
|
@@ -289,7 +314,7 @@ def signal_from_fbd(
|
|
289
314
|
frame : int, optional
|
290
315
|
If None (default), return all frames.
|
291
316
|
If < 0, integrate time axis, else return specified frame.
|
292
|
-
channel : int, optional
|
317
|
+
channel : int or None, optional
|
293
318
|
Index of channel to return.
|
294
319
|
By default, return the first channel.
|
295
320
|
If None, return all channels.
|
@@ -530,7 +555,7 @@ def signal_from_bh(
|
|
530
555
|
Returns
|
531
556
|
-------
|
532
557
|
xarray.DataArray
|
533
|
-
TCSPC histogram with ref:`axes codes <axes>` ``'HYX'``,
|
558
|
+
TCSPC histogram with :ref:`axes codes <axes>` ``'HYX'``,
|
534
559
|
shape ``(256, 256, 256)``, and type ``float32``.
|
535
560
|
|
536
561
|
Raises
|
@@ -587,7 +612,7 @@ def signal_from_bhz(
|
|
587
612
|
Returns
|
588
613
|
-------
|
589
614
|
xarray.DataArray
|
590
|
-
TCSPC histogram with ref:`axes codes <axes>` ``'HYX'``,
|
615
|
+
TCSPC histogram with :ref:`axes codes <axes>` ``'HYX'``,
|
591
616
|
shape ``(256, 256, 256)``, and type ``float32``.
|
592
617
|
|
593
618
|
Raises
|