phasorpy 0.3__cp312-cp312-win_arm64.whl → 0.5__cp312-cp312-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/cluster.py ADDED
@@ -0,0 +1,170 @@
1
+ """Cluster phasor coordinates.
2
+
3
+ The `phasorpy.cluster` module provides functions to:
4
+
5
+ - fit elliptic clusters to phasor coordinates using
6
+ Gaussian Mixture Model (GMM):
7
+
8
+ - :py:func:`phasor_cluster_gmm`
9
+
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ __all__ = ['phasor_cluster_gmm']
15
+
16
+ from typing import TYPE_CHECKING
17
+
18
+ if TYPE_CHECKING:
19
+ from ._typing import Any, ArrayLike
20
+
21
+ import math
22
+
23
+ import numpy
24
+ from sklearn.mixture import GaussianMixture
25
+
26
+
27
+ def phasor_cluster_gmm(
28
+ real: ArrayLike,
29
+ imag: ArrayLike,
30
+ /,
31
+ *,
32
+ sigma: float = 2.0,
33
+ clusters: int = 1,
34
+ **kwargs: Any,
35
+ ) -> tuple[
36
+ tuple[float, ...],
37
+ tuple[float, ...],
38
+ tuple[float, ...],
39
+ tuple[float, ...],
40
+ tuple[float, ...],
41
+ ]:
42
+ """Return elliptic clusters in phasor coordinates using GMM.
43
+
44
+ Fit a Gaussian Mixture Model (GMM) to the provided phasor coordinates and
45
+ extract the parameters of ellipses that represent each cluster according
46
+ to [1]_.
47
+
48
+ Parameters
49
+ ----------
50
+ real : array_like
51
+ Real component of phasor coordinates.
52
+ imag : array_like
53
+ Imaginary component of phasor coordinates.
54
+ sigma: float, default = 2.0
55
+ Scaling factor for radii of major and minor axes.
56
+ Defaults to 2, which corresponds to the scaling of eigenvalues for a
57
+ 95% confidence ellipse.
58
+ clusters : int, optional
59
+ Number of Gaussian distributions to fit to phasor coordinates.
60
+ Defaults to 1.
61
+ **kwargs
62
+ Additional keyword arguments passed to
63
+ :py:class:`sklearn.mixture.GaussianMixture`.
64
+
65
+ Common options include:
66
+
67
+ - covariance_type : {'full', 'tied', 'diag', 'spherical'}
68
+ - max_iter : int, maximum number of EM iterations
69
+ - random_state : int, for reproducible results
70
+
71
+ Returns
72
+ -------
73
+ center_real : tuple of float
74
+ Real component of ellipse centers.
75
+ center_imag : tuple of float
76
+ Imaginary component of ellipse centers.
77
+ radius_major : tuple of float
78
+ Major radii of ellipses.
79
+ radius_minor : tuple of float
80
+ Minor radii of ellipses.
81
+ angle : tuple of float
82
+ Rotation angles of major axes in radians, within range [0, pi].
83
+
84
+ Raises
85
+ ------
86
+ ValueError
87
+ If the array shapes of `real` and `imag` do not match.
88
+ If `clusters` is not a positive integer.
89
+
90
+
91
+ References
92
+ ----------
93
+ .. [1] Vallmitjana A, Torrado B, and Gratton E.
94
+ `Phasor-based image segmentation: machine learning clustering techniques
95
+ <https://doi.org/10.1364/BOE.422766>`_.
96
+ *Biomed Opt Express*, 12(6): 3410-3422 (2021).
97
+
98
+ Examples
99
+ --------
100
+ Recover the clusters from a synthetic distribution of phasor coordinates
101
+ with two clusters:
102
+
103
+ >>> real1, imag1 = numpy.random.multivariate_normal(
104
+ ... [0.2, 0.3], [[3e-3, 1e-3], [1e-3, 2e-3]], 100
105
+ ... ).T
106
+ >>> real2, imag2 = numpy.random.multivariate_normal(
107
+ ... [0.4, 0.5], [[2e-3, -1e-3], [-1e-3, 3e-3]], 100
108
+ ... ).T
109
+ >>> real = numpy.concatenate([real1, real2])
110
+ >>> imag = numpy.concatenate([imag1, imag2])
111
+ >>> center_real, center_imag, radius_major, radius_minor, angle = (
112
+ ... phasor_cluster_gmm(real, imag, clusters=2)
113
+ ... )
114
+ >>> centers_real # doctest: +SKIP
115
+ (0.2, 0.4)
116
+
117
+ """
118
+ coords = numpy.stack((real, imag), axis=-1).reshape(-1, 2)
119
+
120
+ valid_data = ~numpy.isnan(coords).any(axis=1)
121
+ coords = coords[valid_data]
122
+
123
+ kwargs.pop('n_components', None)
124
+
125
+ gmm = GaussianMixture(n_components=clusters, **kwargs)
126
+ gmm.fit(coords)
127
+
128
+ center_real = []
129
+ center_imag = []
130
+ radius_major = []
131
+ radius_minor = []
132
+ angle = []
133
+
134
+ for i in range(clusters):
135
+ center_real.append(float(gmm.means_[i, 0]))
136
+ center_imag.append(float(gmm.means_[i, 1]))
137
+
138
+ if gmm.covariance_type == 'full':
139
+ cov = gmm.covariances_[i]
140
+ elif gmm.covariance_type == 'tied':
141
+ cov = gmm.covariances_
142
+ elif gmm.covariance_type == 'diag':
143
+ cov = numpy.diag(gmm.covariances_[i])
144
+ else: # 'spherical'
145
+ cov = numpy.eye(2) * gmm.covariances_[i]
146
+
147
+ eigenvalues, eigenvectors = numpy.linalg.eigh(cov[:2, :2])
148
+
149
+ idx = eigenvalues.argsort()[::-1]
150
+ eigenvalues = eigenvalues[idx]
151
+ eigenvectors = eigenvectors[:, idx]
152
+
153
+ major_vector = eigenvectors[:, 0]
154
+ current_angle = math.atan2(major_vector[1], major_vector[0])
155
+
156
+ if current_angle < 0:
157
+ current_angle += math.pi
158
+
159
+ angle.append(float(current_angle))
160
+
161
+ radius_major.append(sigma * math.sqrt(2 * eigenvalues[0]))
162
+ radius_minor.append(sigma * math.sqrt(2 * eigenvalues[1]))
163
+
164
+ return (
165
+ tuple(center_real),
166
+ tuple(center_imag),
167
+ tuple(radius_major),
168
+ tuple(radius_minor),
169
+ tuple(angle),
170
+ )
phasorpy/color.py CHANGED
@@ -19,13 +19,13 @@ def wavelength2rgb(
19
19
  ) -> tuple[float, float, float] | NDArray[Any]:
20
20
  """Return approximate sRGB color components of visible wavelength(s).
21
21
 
22
- Wavelength values are clipped to 360..750, rounded, and used to index
23
- the :py:attr:`SRGB_SPECTRUM` palette.
22
+ Wavelengths are clipped to range [360, 750] nm, rounded, and used to
23
+ index the :py:attr:`SRGB_SPECTRUM` palette.
24
24
 
25
25
  Parameters
26
26
  ----------
27
27
  wavelength : array_like
28
- Scalar or array of wavelength(s) to convert.
28
+ Scalar or array of wavelengths in nm.
29
29
  dtype : data-type, optional
30
30
  Data-type of return value. The default is ``float32``.
31
31
 
@@ -33,8 +33,8 @@ def wavelength2rgb(
33
33
  -------
34
34
  ndarray or tuple
35
35
  Approximate sRGB color components of visible wavelength.
36
- Floating-point types are in range 0.0 to 1.0.
37
- Integer types are scaled to the dtype's maximum value.
36
+ Floating-point values are in range [0.0, 1.0].
37
+ Integer values are scaled to the dtype's maximum value.
38
38
 
39
39
  Examples
40
40
  --------
@@ -59,8 +59,7 @@ def wavelength2rgb(
59
59
  else:
60
60
  rgb = rgb.astype(dtype)
61
61
  if astuple:
62
- rgb_list = rgb.tolist()
63
- return (rgb_list[0], rgb_list[1], rgb_list[2])
62
+ return tuple(rgb.tolist()[:3])
64
63
  return rgb
65
64
 
66
65
 
@@ -69,7 +68,7 @@ def float2int(
69
68
  /,
70
69
  dtype: DTypeLike = numpy.uint8,
71
70
  ) -> NDArray[Any]:
72
- """Return normalized color components as integer type.
71
+ """Return normalized color components as integers.
73
72
 
74
73
  Parameters
75
74
  ----------
@@ -78,6 +77,11 @@ def float2int(
78
77
  dtype : data-type, optional
79
78
  Data type of return value. The default is ``uint8``.
80
79
 
80
+ Returns
81
+ -------
82
+ ndarray
83
+ Color components as integers scaled to dtype's range.
84
+
81
85
  Examples
82
86
  --------
83
87
  >>> float2int([0.0, 0.5, 1.0])
@@ -163,11 +167,11 @@ CATEGORICAL: NDArray[numpy.float32] = numpy.array([
163
167
  [0.523809, 0.888889, 0.460317],
164
168
  [0.285714, 0.0, 0.238095],
165
169
  ], dtype=numpy.float32)
166
- """Categorical sRGB color palette inspired by C Glasbey.
170
+ """Categorical sRGB color palette inspired by C. Glasbey.
167
171
 
168
- The palette contains 64 maximally distinct colours.
172
+ Contains 64 maximally distinct colours for visualization.
169
173
 
170
- Generated with the `glasbey <https://glasbey.readthedocs.io>`_ package::
174
+ Generated using the `glasbey <https://glasbey.readthedocs.io>`_ package::
171
175
 
172
176
  import glasbey; numpy.array(glasbey.create_palette(64, as_hex=False))
173
177
 
@@ -569,11 +573,11 @@ SRGB_SPECTRUM: NDArray[numpy.float32] = numpy.array([
569
573
  [0.005006, 0.0, 0.0],
570
574
  [0.004664, 0.0, 0.0],
571
575
  ], dtype=numpy.float32)
572
- """sRGB color components for visible light wavelengths 360-750 nm.
576
+ """sRGB color components for wavelengths of visible light (360-750 nm).
573
577
 
574
578
  Based on the CIE 1931 2° Standard Observer.
575
579
 
576
- Generated with the `colour <https://colour.readthedocs.io>`_ package::
580
+ Generated using the `colour <https://colour.readthedocs.io>`_ package::
577
581
 
578
582
  import colour; colour.plotting.plot_visible_spectrum()
579
583
 
phasorpy/components.py CHANGED
@@ -65,10 +65,10 @@ def two_fractions_from_phasor(
65
65
  Real component of phasor coordinates.
66
66
  imag : array_like
67
67
  Imaginary component of phasor coordinates.
68
- components_real: array_like, shape (2,)
69
- Real coordinates of the first and second components.
70
- components_imag: array_like, shape (2,)
71
- Imaginary coordinates of the first and second components.
68
+ components_real : array_like, shape (2,)
69
+ Real coordinates of first and second components.
70
+ components_imag : array_like, shape (2,)
71
+ Imaginary coordinates of first and second components.
72
72
 
73
73
  Returns
74
74
  -------
@@ -78,7 +78,7 @@ def two_fractions_from_phasor(
78
78
  Raises
79
79
  ------
80
80
  ValueError
81
- If the real and/or imaginary coordinates of the known components are
81
+ If the real or imaginary coordinates of the known components are
82
82
  not of size 2.
83
83
 
84
84
  See Also
@@ -145,13 +145,13 @@ def graphical_component_analysis(
145
145
  Real component of phasor coordinates.
146
146
  imag : array_like
147
147
  Imaginary component of phasor coordinates.
148
- components_real: array_like, shape (2,) or (3,)
148
+ components_real : array_like, shape (2,) or (3,)
149
149
  Real coordinates for two or three components.
150
- components_imag: array_like, shape (2,) or (3,)
150
+ components_imag : array_like, shape (2,) or (3,)
151
151
  Imaginary coordinates for two or three components.
152
- radius: float, optional, default: 0.05
153
- Radius of the cursor in phasor coordinates.
154
- fractions: array_like or int, optional
152
+ radius : float, optional, default: 0.05
153
+ Radius of cursor.
154
+ fractions : array_like or int, optional
155
155
  Number of equidistant fractions, or 1D array of fraction values.
156
156
  Fraction values must be in range [0.0, 1.0].
157
157
  If an integer, ``numpy.linspace(0.0, 1.0, fractions)`` fraction values
@@ -163,8 +163,8 @@ def graphical_component_analysis(
163
163
  Returns
164
164
  -------
165
165
  counts : tuple of ndarray
166
- Counts along each line segment connecting the components, ordered
167
- 0-1 (2 components) or 0-1, 0-2, 1-2 (3 components).
166
+ Counts along each line segment connecting components.
167
+ Ordered 0-1 (2 components) or 0-1, 0-2, 1-2 (3 components).
168
168
 
169
169
  Raises
170
170
  ------
@@ -172,7 +172,7 @@ def graphical_component_analysis(
172
172
  The array shapes of `real` and `imag`, or `components_real` and
173
173
  `components_imag` do not match.
174
174
  The number of components is not 2 or 3.
175
- Fraction values are not in range [0.0, 1.0].
175
+ Fraction values are out of range [0.0, 1.0].
176
176
 
177
177
  See Also
178
178
  --------
@@ -216,7 +216,7 @@ def graphical_component_analysis(
216
216
  >>> graphical_component_analysis(
217
217
  ... [0.6, 0.3], [0.35, 0.38], [0.2, 0.9], [0.4, 0.3], fractions=6
218
218
  ... ) # doctest: +NUMBER
219
- (array([0, 0, 1, 0, 1, 0]),)
219
+ (array([0, 0, 1, 0, 1, 0], dtype=uint64),)
220
220
 
221
221
  Count the number of phasors between the combinations of three components:
222
222
 
@@ -227,9 +227,9 @@ def graphical_component_analysis(
227
227
  ... [0.0, 0.4, 0.3],
228
228
  ... fractions=6,
229
229
  ... ) # doctest: +NUMBER +NORMALIZE_WHITESPACE
230
- (array([0, 1, 1, 1, 1, 0]),
231
- array([0, 1, 0, 0, 0, 0]),
232
- array([0, 1, 2, 0, 0, 0]))
230
+ (array([0, 1, 1, 1, 1, 0], dtype=uint64),
231
+ array([0, 1, 0, 0, 0, 0], dtype=uint64),
232
+ array([0, 1, 2, 0, 0, 0], dtype=uint64))
233
233
 
234
234
  """
235
235
  real = numpy.asarray(real)
@@ -305,7 +305,7 @@ def graphical_component_analysis(
305
305
  components_imag[3 - i - j], # c_imag
306
306
  radius,
307
307
  )
308
- fraction_counts = numpy.sum(mask)
308
+ fraction_counts = numpy.sum(mask, dtype=numpy.uint64)
309
309
  component_counts.append(fraction_counts)
310
310
 
311
311
  counts.append(numpy.asarray(component_counts))
phasorpy/conftest.py CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ __all__: list[str] = []
6
+
5
7
  import math
6
8
  from typing import TYPE_CHECKING
7
9
 
phasorpy/cursors.py CHANGED
@@ -291,15 +291,15 @@ def mask_from_polar_cursor(
291
291
  imag : array_like
292
292
  Imaginary component of phasor coordinates.
293
293
  phase_min : array_like, shape (n,)
294
- Minimum of angular range of cursors in radians.
295
- Values should be between -pi and pi.
294
+ Lower bound of angular range of cursors in radians.
295
+ Values should be in range [-pi, pi].
296
296
  phase_max : array_like, shape (n,)
297
- Maximum of angular range of cursors in radians.
298
- Values should be between -pi and pi.
297
+ Upper bound of angular range of cursors in radians.
298
+ Values should be in range [-pi, pi].
299
299
  modulation_min : array_like, shape (n,)
300
- Minimum of radial range of cursors.
300
+ Lower bound of radial range of cursors.
301
301
  modulation_max : array_like, shape (n,)
302
- Maximum of radial range of cursors.
302
+ Upper bound of radial range of cursors.
303
303
 
304
304
  Returns
305
305
  -------
@@ -362,7 +362,7 @@ def mask_from_polar_cursor(
362
362
  f'{phase_min.ndim=}, {phase_max.ndim=}, '
363
363
  f'{modulation_min.ndim=}, or {modulation_max.ndim=} > 1'
364
364
  )
365
- # TODO: check if angles are between -pi and pi
365
+ # TODO: check if angles are in range [-pi and pi]
366
366
 
367
367
  moveaxis = False
368
368
  if real.ndim > 0 and (
@@ -406,7 +406,7 @@ def pseudo_color(
406
406
  Maximum value to normalize `intensity`.
407
407
  If None, the maximum value of `intensity` is used.
408
408
  colors : array_like, optional, shape (N, 3)
409
- Colors assigned to each cursor.
409
+ RGB colors assigned to each cursor.
410
410
  The last dimension contains the normalized RGB floating point values.
411
411
  The default is :py:data:`phasorpy.color.CATEGORICAL`.
412
412
 
@@ -463,7 +463,7 @@ def pseudo_color(
463
463
  shape = numpy.asarray(masks[0]).shape
464
464
 
465
465
  if intensity is not None:
466
- # normalize intensity to range 0..1
466
+ # normalize intensity to range [0, 1]
467
467
  intensity = numpy.array(
468
468
  intensity, dtype=numpy.float32, ndmin=1, copy=True
469
469
  )
phasorpy/datasets.py CHANGED
@@ -14,8 +14,11 @@ Datasets from the following repositories are available:
14
14
  <https://github.com/zoccoler/napari-flim-phasor-plotter/tree/0.0.6/src/napari_flim_phasor_plotter/data>`_
15
15
  - `Phasor-based multi-harmonic unmixing for in-vivo hyperspectral imaging
16
16
  <https://zenodo.org/records/13625087>`_
17
+ (`second record <https://zenodo.org/records/14860228>`_)
17
18
  - `Convallaria slice acquired with time-resolved 2-photon microscope
18
19
  <https://zenodo.org/records/14026720>`_
20
+ - `Convallaria FLIM dataset in FLIM LABS JSON format
21
+ <https://zenodo.org/records/15007900>`_
19
22
 
20
23
  The implementation is based on the `Pooch <https://www.fatiando.org/pooch>`_
21
24
  library.
@@ -266,14 +269,15 @@ ZENODO_13625087 = pooch.create(
266
269
  base_url=(
267
270
  'https://github.com/phasorpy/phasorpy-data/raw/main/zenodo_13625087'
268
271
  # if DATA_ON_GITHUB
269
- # else 'doi:10.1088/2050-6120/ac9ae9'
272
+ # else 'doi:10.1088/2050-6120/ac9ae9' # TODO: not working with Pooch
270
273
  ),
271
274
  env=ENV,
272
275
  registry={
273
- '33_Hoechst_Golgi_Mito_Lyso_CellMAsk_404_488_561_633_SP.lsm': (
274
- 'sha256:'
275
- '68fcefcad4e750e9ec7068820e455258c986f6a9b724e66744a28bbbb689f986'
276
- ),
276
+ # part of ZENODO_14860228
277
+ # '33_Hoechst_Golgi_Mito_Lyso_CellMAsk_404_488_561_633_SP.lsm': (
278
+ # 'sha256:'
279
+ # '68fcefcad4e750e9ec7068820e455258c986f6a9b724e66744a28bbbb689f986'
280
+ # ),
277
281
  '34_Hoechst_Golgi_Mito_Lyso_CellMAsk_404_488_561_633_SP.lsm': (
278
282
  'sha256:'
279
283
  '5c0b7d76c274fd64891fca2507013b7c8c9979d8131ce282fac55fd24fbb38bd'
@@ -289,9 +293,65 @@ ZENODO_13625087 = pooch.create(
289
293
  },
290
294
  )
291
295
 
296
+ ZENODO_14860228 = pooch.create(
297
+ path=pooch.os_cache('phasorpy'),
298
+ base_url=(
299
+ 'https://github.com/phasorpy/phasorpy-data/raw/main/zenodo_14860228'
300
+ if DATA_ON_GITHUB
301
+ else 'doi:10.5281/zenodo.14860228'
302
+ ),
303
+ env=ENV,
304
+ registry={
305
+ '38_Hoechst_Golgi_Mito_Lyso_CellMAsk_404_488_561_633_SP.lsm': (
306
+ 'sha256:'
307
+ '092ac050edf55e26dcda8cba10122408c6f1b81d19accf07214385d6eebfcf3e'
308
+ ),
309
+ 'spectral cell mask.lsm': (
310
+ 'sha256:'
311
+ 'c4c2c567bd99ef4930d7278794d4e3daebaad0375c0852a5ab86a2ea056f4fe3'
312
+ ),
313
+ 'spectral golgi.lsm': (
314
+ 'sha256:'
315
+ 'd0a5079d9ed18b1248434f3f6d4b2b240fb034891121262cfe9dfec64d8429cd'
316
+ ),
317
+ 'spectral hoehst.lsm': (
318
+ 'sha256:'
319
+ '3ee44a7f9f125698bb5e34746d9723669f67c520ffbf21244757d7fc25dbbb88'
320
+ ),
321
+ 'spectral lyso tracker green.lsm': (
322
+ 'sha256:'
323
+ '0964448649e2c73a57f5ca0c705c86511fb4625c0a2af0d7850dfa39698fcbb9'
324
+ ),
325
+ 'spectral mito tracker.lsm': (
326
+ 'sha256:'
327
+ '99b9892b247256ebf8a9917c662bc7bb66a8daf3b5db950fbbb191de0cd35b37'
328
+ ),
329
+ },
330
+ )
331
+
332
+ ZENODO_14976703 = pooch.create(
333
+ path=pooch.os_cache('phasorpy'),
334
+ base_url=(
335
+ 'https://github.com/phasorpy/phasorpy-data/raw/main/zenodo_14976703'
336
+ if DATA_ON_GITHUB
337
+ else 'doi:10.5281/zenodo.14976703'
338
+ ),
339
+ env=ENV,
340
+ registry={
341
+ 'Convalaria_LambdaScan.lif': (
342
+ 'sha256:'
343
+ '27f1282cf02f87e11f8c7d3064066a4517ad4c9c769c796b32e459774f18c62a'
344
+ ),
345
+ },
346
+ )
347
+
292
348
  CONVALLARIA_FBD = pooch.create(
293
349
  path=pooch.os_cache('phasorpy'),
294
- base_url='doi:10.5281/zenodo.14026719',
350
+ base_url=(
351
+ 'https://github.com/phasorpy/phasorpy-data/raw/main/zenodo_14026720'
352
+ if DATA_ON_GITHUB
353
+ else 'doi:10.5281/zenodo.14026719'
354
+ ),
295
355
  env=ENV,
296
356
  registry={
297
357
  'Convallaria_$EI0S.fbd': (
@@ -305,6 +365,99 @@ CONVALLARIA_FBD = pooch.create(
305
365
  },
306
366
  )
307
367
 
368
+ FLIMLABS = pooch.create(
369
+ path=pooch.os_cache('phasorpy'),
370
+ base_url=(
371
+ 'https://github.com/phasorpy/phasorpy-data/raw/main/flimlabs'
372
+ if DATA_ON_GITHUB
373
+ else 'doi:10.5281/zenodo.15007900'
374
+ ),
375
+ env=ENV,
376
+ registry={
377
+ 'Convallaria_m2_1740751781_phasor_ch1.json': (
378
+ 'sha256:'
379
+ 'a8bf0179f352ab2c6c78d0bd399545ab1fb6d5537f23dc06e5f12a7ef5af6615'
380
+ ),
381
+ 'Convallaria_m2_1740751781_phasor_ch1.json.zip': (
382
+ 'sha256:'
383
+ '9c5691f55e85778717ace13607d573bcd00c29e357e063c8db4f173340f72984'
384
+ ),
385
+ 'Fluorescein_Calibration_m2_1740751189_imaging.json': (
386
+ 'sha256:'
387
+ 'aeebb074dbea6bff7578f409c7622b2f7f173bb23e5475d1436adedca7fc2eed'
388
+ ),
389
+ 'Fluorescein_Calibration_m2_1740751189_imaging.json.zip': (
390
+ 'sha256:'
391
+ '32960bc1dec85fd16ffc7dd74a3cd63041fb3b69054ee6582f913129b0847086'
392
+ ),
393
+ 'Fluorescein_Calibration_m2_1740751189_imaging_calibration.json': (
394
+ 'sha256:'
395
+ '7fd1b9749789bd139c132602a771a127ea0c76f403d1750e9636cd657cce017a'
396
+ ),
397
+ },
398
+ )
399
+
400
+ FIGSHARE_22336594 = pooch.create(
401
+ path=pooch.os_cache('phasorpy'),
402
+ base_url=(
403
+ 'https://github.com/phasorpy/phasorpy-data/raw/main/figshare_22336594'
404
+ if DATA_ON_GITHUB
405
+ else 'doi:10.6084/m9.figshare.22336594.v1'
406
+ ),
407
+ env=ENV,
408
+ registry={
409
+ 'FLIM_testdata.lif': (
410
+ 'sha256:'
411
+ '902d8fa6cd39da7cf062b32d43aab518fa2a851eab72b4bd8b8eca1bad591850'
412
+ ),
413
+ },
414
+ )
415
+
416
+ FIGSHARE_22336594_EXPORTED = pooch.create(
417
+ path=pooch.os_cache('phasorpy'),
418
+ base_url=(
419
+ 'https://github.com/phasorpy/phasorpy-data/raw/main/figshare_22336594'
420
+ ),
421
+ env=ENV,
422
+ registry={
423
+ 'FLIM_testdata.lif.ptu': (
424
+ 'sha256:'
425
+ 'c85792b25d0b274f1484e490c99aa19052ab8e48e4e5022aabb1f218cd1123b6'
426
+ ),
427
+ 'FLIM_testdata.lif.ptu.zip': (
428
+ 'sha256:'
429
+ 'c5134c470f6a3e5cb21eabd538cbd5061d9911dad96d58e3a4040cfddadaef33'
430
+ ),
431
+ 'FLIM_testdata.xlef': (
432
+ 'sha256:'
433
+ '7860ef0847dc9f5534895a9c11b979bb446f67382b577fe63fb166e281e5dc5e'
434
+ ),
435
+ 'FLIM_testdata.xlef.zip': (
436
+ 'sha256:'
437
+ 'ad0ad6389f38dcba6f9809b54934ef3f19da975d9dabeb4c3a248692b959b9cf'
438
+ ),
439
+ 'FLIM_testdata.lif.filtered.ptu': (
440
+ 'sha256:'
441
+ 'a00b84f626a39e79263322c60ae50b64163b36bb977ecc4dc54619097ba7f5b7'
442
+ ),
443
+ 'FLIM_testdata.lif.filtered.ptu.zip': (
444
+ 'sha256:'
445
+ '717366b231213bfd6e295c3efb7bf1bcd90e720eb28aab3223376087172e93e5'
446
+ ),
447
+ },
448
+ )
449
+
450
+ MISC = pooch.create(
451
+ path=pooch.os_cache('phasorpy'),
452
+ base_url='https://github.com/phasorpy/phasorpy-data/raw/main/misc',
453
+ env=ENV,
454
+ registry={
455
+ 'NADHandSHG.ifli': (
456
+ 'sha256:'
457
+ 'dfa65952850b8a222258776a8a14eb1ab7e70ff5f62b58aa2214797c5921b4a3'
458
+ ),
459
+ },
460
+ )
308
461
 
309
462
  REPOSITORIES: dict[str, pooch.Pooch] = {
310
463
  'tests': TESTS,
@@ -312,7 +465,13 @@ REPOSITORIES: dict[str, pooch.Pooch] = {
312
465
  'flute': FLUTE,
313
466
  'napari-flim-phasor-plotter': NAPARI_FLIM_PHASOR_PLOTTER,
314
467
  'zenodo-13625087': ZENODO_13625087,
468
+ 'zenodo-14860228': ZENODO_14860228,
469
+ 'zenodo-14976703': ZENODO_14976703,
315
470
  'convallaria-fbd': CONVALLARIA_FBD,
471
+ 'flimlabs': FLIMLABS,
472
+ 'figshare_22336594': FIGSHARE_22336594,
473
+ 'figshare_22336594_exported': FIGSHARE_22336594_EXPORTED,
474
+ 'misc': MISC,
316
475
  }
317
476
  """Pooch repositories."""
318
477
 
@@ -325,19 +484,19 @@ def fetch(
325
484
  ) -> Any: # str | tuple[str, ...]
326
485
  """Return absolute path(s) to sample file(s) in local storage.
327
486
 
328
- The files are downloaded from a remote repository if they do not already
329
- exist in the local storage.
487
+ The files are downloaded from a remote repository if not present in local
488
+ storage.
330
489
 
331
490
  Parameters
332
491
  ----------
333
- *args: str or iterable of str, optional
492
+ *args : str or iterable of str, optional
334
493
  Name(s) of file(s) or repositories to fetch from local storage.
335
494
  If omitted, return files in all repositories.
336
495
  extract_dir : str or None, optional
337
496
  Path, relative to cache location, where ZIP files will be unpacked.
338
497
  return_scalar : bool, optional
339
498
  If true (default), return single path as string, else tuple of string.
340
- **kwargs : optional
499
+ **kwargs
341
500
  Additional arguments passed to ``pooch.fetch()``.
342
501
  For example, ``progressbar=True``.
343
502