phasorpy 0.2__cp312-cp312-macosx_10_13_x86_64.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/datasets.py ADDED
@@ -0,0 +1,453 @@
1
+ """Manage sample data files for testing and tutorials.
2
+
3
+ The ``phasorpy.datasets`` module provides a :py:func:`fetch` function to
4
+ download data files from remote repositories and cache them in a local
5
+ directory. The cache location can be changed by setting the
6
+ ``PHASORPY_DATA_DIR`` environment variable.
7
+
8
+ Datasets from the following repositories are available:
9
+
10
+ - `PhasorPy tests <https://zenodo.org/record/8417894>`_
11
+ - `LFD Workshop <https://zenodo.org/record/8411056>`_
12
+ - `FLUTE <https://zenodo.org/record/8046636>`_
13
+ - `napari-flim-phasor-plotter
14
+ <https://github.com/zoccoler/napari-flim-phasor-plotter/tree/0.0.6/src/napari_flim_phasor_plotter/data>`_
15
+ - `Phasor-based multi-harmonic unmixing for in-vivo hyperspectral imaging
16
+ <https://zenodo.org/records/13625087>`_
17
+ - `Convallaria slice acquired with time-resolved 2-photon microscope
18
+ <https://zenodo.org/records/14026720>`_
19
+
20
+ The implementation is based on the `Pooch <https://www.fatiando.org/pooch>`_
21
+ library.
22
+
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ __all__ = ['fetch', 'REPOSITORIES']
28
+
29
+ import os
30
+ from typing import TYPE_CHECKING
31
+
32
+ if TYPE_CHECKING:
33
+ from ._typing import Any, Iterable
34
+
35
+ import pooch
36
+
37
+ ENV = 'PHASORPY_DATA_DIR'
38
+
39
+ DATA_ON_GITHUB = bool(
40
+ os.environ.get('PHASORPY_DATA_ON_GITHUB', False)
41
+ ) or bool(os.environ.get('GITHUB_ACTIONS', False))
42
+
43
+ TESTS = pooch.create(
44
+ path=pooch.os_cache('phasorpy'),
45
+ base_url=(
46
+ 'https://github.com/phasorpy/phasorpy-data/raw/main/tests'
47
+ if DATA_ON_GITHUB
48
+ else 'doi:10.5281/zenodo.8417894'
49
+ ),
50
+ env=ENV,
51
+ registry={
52
+ 'flimage.int.bin': (
53
+ 'sha256:'
54
+ '5d470ed31ed0611b43270261341bc1c41f55fda665eaf529d848a139fcae5fc8'
55
+ ),
56
+ 'flimage.int.bin.zip': (
57
+ 'sha256:'
58
+ '51062322891b4c22d577100395d8c02297c5494030d2c550a0fd6c90f73cc211'
59
+ ),
60
+ 'flimage.mod.bin': (
61
+ 'sha256:'
62
+ 'b0312f6f9f1f24e228b2c3a3cb07e18d80b35f31109f8c771b088b54419c5200'
63
+ ),
64
+ 'flimage.phi.bin': (
65
+ 'sha256:'
66
+ 'd593acc698a1226c7a4571fa61f6751128584dcca6ed4449d655283cd231b125'
67
+ ),
68
+ 'flimfast.flif': (
69
+ 'sha256:'
70
+ 'b12cedf299831a46baf80dcfe7bfb9f366fee30fb3e2b3039d4346f1bbaf3e2c'
71
+ ),
72
+ 'flimfast.flif.zip': (
73
+ 'sha256:'
74
+ 'b25642b1a2dbc547f0cdaadc13ce89ecaf372f90a20978910c02b13beb138c2e'
75
+ ),
76
+ 'frequency_domain.ifli': (
77
+ 'sha256:'
78
+ '56015b98a2edaf4ee1262b5e1034305aa29dd8b20e301ced9cd7a109783cd171'
79
+ ),
80
+ 'frequency_domain.ifli.zip': (
81
+ 'sha256:'
82
+ '93066cc48028360582f6e3380d09d2c5a6f540a8f931639da3cfca158926df9b'
83
+ ),
84
+ 'paramecium.lsm': (
85
+ 'sha256:'
86
+ 'b3b3b80be244a41352c56390191a50e4010d52e5ca341dc51bd1d7c89f10cedf'
87
+ ),
88
+ 'paramecium.lsm.zip': (
89
+ 'sha256:'
90
+ '7828a80e878ee7ab88f9bd9a6cda72e5d698394d37f69a7bee5b0b31b3856919'
91
+ ),
92
+ 'simfcs.b64': (
93
+ 'sha256:'
94
+ '5ccccd0bcd46c66ea174b6074975f631bdf163fcb047e35f9310aaf67c320fb8'
95
+ ),
96
+ 'simfcs.b64.zip': (
97
+ 'sha256:'
98
+ 'b176761905fc5916d0770bd6baaa0e31af5981f92ec323e588f9ce398324818e'
99
+ ),
100
+ 'simfcs.b&h': (
101
+ 'sha256:'
102
+ '6a406c4fd862318a51370461c7607390f022afdcb2ce27c4600df4b5af83c26e'
103
+ ),
104
+ 'simfcs.b&h.zip': (
105
+ 'sha256:'
106
+ 'ec14666be76bd5bf2dcaee63435332857795173c8dc94be8778697f32b041aa1'
107
+ ),
108
+ 'simfcs.bhz': (
109
+ 'sha256:'
110
+ '14f8b5287e257514945ca17a8398425fc040c00bfad2d8a3c6adb4790862d211'
111
+ ),
112
+ 'simfcs.r64': (
113
+ 'sha256:'
114
+ 'ead3b2df45c1dff91e91a325f97225f4837c372db04c2e49437ee9ec68532946'
115
+ ),
116
+ 'simfcs.ref': (
117
+ 'sha256:'
118
+ '697dad17fb3a3cf7329a45b43ba9ae5f7220c1f3d5f08749f2ce3eadb0598420'
119
+ ),
120
+ 'simfcs.ref.zip': (
121
+ 'sha256:'
122
+ '482331ec5586973e9eb5c2e4f793d9621cc756ce8f4093f5e21906a7ce5726f8'
123
+ ),
124
+ 'simfcs.z64': (
125
+ 'sha256:'
126
+ 'f1dd861f80528c77bb581023c05c7bf7293d6ad3c4a3d10f9a50b8b5618a8099'
127
+ ),
128
+ 'simfcs_1000.int': (
129
+ 'sha256:'
130
+ 'bb5bde0ecf24243865cdbc2b065358fe8c557696de18567dbb3f75adfb2ab51a'
131
+ ),
132
+ 'simfcs_1000.int.zip': (
133
+ 'sha256:'
134
+ 'f75e211dc344f194a871f0b3af3f6d8a9e4850e9718526f2bfad87ef16c1c377'
135
+ ),
136
+ 'simfcs_1000.mod': (
137
+ 'sha256:'
138
+ '84265df08d48ff56f6844d55392fccac9fa429c481d1ac81b07c23738075d336'
139
+ ),
140
+ 'simfcs_1000.phs': (
141
+ 'sha256:'
142
+ '8a39d2abd3999ab73c34db2476849cddf303ce389b35826850f9a700589b4a90'
143
+ ),
144
+ 'tcspc.sdt': (
145
+ 'sha256:'
146
+ '0ff0b25b36cb9a7657112a3b081ff479bcae487ce8100b8756e5780e0957708d'
147
+ ),
148
+ 'tcspc.sdt.zip': (
149
+ 'sha256:'
150
+ '57a772bc413e85e0f13eb996f8c2484dfb3d15df67ffa6c3b968d3a03c27fdc3'
151
+ ),
152
+ },
153
+ )
154
+
155
+ LFD_WORKSHOP = pooch.create(
156
+ path=pooch.os_cache('phasorpy'),
157
+ base_url=(
158
+ 'https://github.com/phasorpy/phasorpy-data/raw/main/lfd_workshop'
159
+ if DATA_ON_GITHUB
160
+ else 'doi:10.5281/zenodo.8411056'
161
+ ),
162
+ env=ENV,
163
+ registry={
164
+ '4-22-03-2-A5-CHO-CELL3B.tif': (
165
+ 'sha256:'
166
+ '015d4b5a4cbb6cc40ac0c39f7a0b57ff31173df5b3112627b551e4d8ce8c3b02'
167
+ ),
168
+ '1011rac1002.ref': (
169
+ 'sha256:'
170
+ 'b8eb374d21ba74519342187aa0b6f67727983c1e9d02a9b86bde7e323f5545ac'
171
+ ),
172
+ 'CFP and CFP-YFp.ref': (
173
+ 'sha256:'
174
+ 'f4f494d5e71836aeacfa8796dcf9b92bbc0f62b8176d6c10d5ab9ce202313257'
175
+ ),
176
+ 'CFP-YFP many cells with background.ref': (
177
+ 'sha256:'
178
+ '7cb88018be807144edbb2746d0ec6548eeb3ddc4aa176f3fba4223990aa21754'
179
+ ),
180
+ 'CFPpax8651866.ref': (
181
+ 'sha256:'
182
+ 'eda9177f2841229d120782862779e2db295ad773910b308bc2c360c22c75f391'
183
+ ),
184
+ 'Paxillins013.bin': (
185
+ 'sha256:'
186
+ 'b979e3112dda2fa1cc34a351dab7b0c82009ef07eaa34829503fb79f7a6bb7d2'
187
+ ),
188
+ 'capillaries1001.ref': (
189
+ 'sha256:'
190
+ '27f071ae31032ed4e79c365bb2076044876f7fc10ef622aff458945f33e60984'
191
+ ),
192
+ 'pax1023.bin': (
193
+ 'sha256:'
194
+ 'f467e8264bb10fc12a19506693837f384e32ca01c0cac0b25704c19ceb8d7d5a'
195
+ ),
196
+ },
197
+ )
198
+
199
+ FLUTE = pooch.create(
200
+ path=pooch.os_cache('phasorpy'),
201
+ base_url='doi:10.5281/zenodo.8046636',
202
+ env=ENV,
203
+ registry={
204
+ 'Embryo.tif': (
205
+ 'sha256:'
206
+ 'd1107de8d0f3da476e90bcb80ddf40231df343ed9f28340c873cf858ca869e20'
207
+ ),
208
+ 'Fluorescein_Embryo.tif': (
209
+ 'sha256:'
210
+ '53cb66439a6e921aef1aa7f57ef542260c51cdb8fe56a643f80ea88fe2230bc8'
211
+ ),
212
+ 'Fluorescein_hMSC.tif': (
213
+ 'sha256:'
214
+ 'a3f22076e8dc89b639f690146e46ff8a068388cbf381c2f3a9225cdcbbcec605'
215
+ ),
216
+ 'hMSC control.tif': (
217
+ 'sha256:'
218
+ '725570373ee51ee226560ec5ebb57708e2fac53effc94774c03b71c67a42c9f8'
219
+ ),
220
+ 'hMSC-ZOOM.tif': (
221
+ 'sha256:'
222
+ '6ff4be17e9d98a94b44ef13ec57af3c520f8deaeef72a7210ea371b84617ce92'
223
+ ),
224
+ 'hMSC_rotenone.tif': (
225
+ 'sha256:'
226
+ 'cd0d2bd3baddc0f82c84c9624692e51bbbc56a80ac20b5936be0898d619c2bf2'
227
+ ),
228
+ },
229
+ )
230
+
231
+ NAPARI_FLIM_PHASOR_PLOTTER = pooch.create(
232
+ path=pooch.os_cache('phasorpy'),
233
+ base_url='https://github.com/zoccoler/napari-flim-phasor-plotter/'
234
+ 'raw/0.0.6/src/napari_flim_phasor_plotter/data',
235
+ env=ENV,
236
+ registry={
237
+ 'hazelnut_FLIM_single_image.ptu': (
238
+ 'sha256:'
239
+ '262f60ebc0054ba985fdda3032b58419aac07720e5f157800616c864d15fc2d3'
240
+ ),
241
+ 'hazelnut_FLIM_z_stack.zip': (
242
+ 'sha256:'
243
+ '8d26ebc7c758a70ee256d95c06f7921baa3cecbcdde82c7bb54b66bcb8db156e'
244
+ ),
245
+ 'lifetime_cat.tif': (
246
+ 'sha256:'
247
+ '5f2a2d20284a6f32fa3d1d13cb0c535cea5c2ec99c23148d9ee2d1e22d121a34'
248
+ ),
249
+ 'lifetime_cat_labels.tif': (
250
+ 'sha256:'
251
+ '102d74c202171f0ce2821dfbf1c92ead578bafebf99830e0cfa766e7407aadf9'
252
+ ),
253
+ 'lifetime_cat_metadata.yml': (
254
+ 'sha256:'
255
+ '20c447c1251598f255309fa866e58fc0e4abc2b73e824d18727833a05467d8bc'
256
+ ),
257
+ 'seminal_receptacle_FLIM_single_image.sdt': (
258
+ 'sha256:'
259
+ '2ba169495e533235cffcad953e76c7969286aad9181b946f5167390b8ff1a44a'
260
+ ),
261
+ },
262
+ )
263
+
264
+ ZENODO_13625087 = pooch.create(
265
+ path=pooch.os_cache('phasorpy'),
266
+ base_url=(
267
+ 'https://github.com/phasorpy/phasorpy-data/raw/main/zenodo_13625087'
268
+ # if DATA_ON_GITHUB
269
+ # else 'doi:10.1088/2050-6120/ac9ae9'
270
+ ),
271
+ env=ENV,
272
+ registry={
273
+ '33_Hoechst_Golgi_Mito_Lyso_CellMAsk_404_488_561_633_SP.lsm': (
274
+ 'sha256:'
275
+ '68fcefcad4e750e9ec7068820e455258c986f6a9b724e66744a28bbbb689f986'
276
+ ),
277
+ '34_Hoechst_Golgi_Mito_Lyso_CellMAsk_404_488_561_633_SP.lsm': (
278
+ 'sha256:'
279
+ '5c0b7d76c274fd64891fca2507013b7c8c9979d8131ce282fac55fd24fbb38bd'
280
+ ),
281
+ '35_Hoechst_Golgi_Mito_Lyso_CellMAsk_404_488_561_633_SP.lsm': (
282
+ 'sha256:'
283
+ 'df57c178c185f6e271a66e2664dcc09d6f5abf923ee7d9c33add41bafc15214c'
284
+ ),
285
+ '38_Hoechst_Golgi_Mito_Lyso_CellMAsk_404_488_561_633_SP.lsm': (
286
+ 'sha256:'
287
+ '092ac050edf55e26dcda8cba10122408c6f1b81d19accf07214385d6eebfcf3e'
288
+ ),
289
+ },
290
+ )
291
+
292
+ CONVALLARIA_FBD = pooch.create(
293
+ path=pooch.os_cache('phasorpy'),
294
+ base_url='doi:10.5281/zenodo.14026719',
295
+ env=ENV,
296
+ registry={
297
+ 'Convallaria_$EI0S.fbd': (
298
+ 'sha256:'
299
+ '3751891b02e3095fedd53a09688d8a22ff2a0083544dd5c0726b9267d11df1bc'
300
+ ),
301
+ 'Calibration_Rhodamine110_$EI0S.fbd': (
302
+ 'sha256:'
303
+ 'd745cbcdd4a10dbaed83ee9f1b150f0c7ddd313031e18233293582cdf10e4691'
304
+ ),
305
+ },
306
+ )
307
+
308
+
309
+ REPOSITORIES: dict[str, pooch.Pooch] = {
310
+ 'tests': TESTS,
311
+ 'lfd-workshop': LFD_WORKSHOP,
312
+ 'flute': FLUTE,
313
+ 'napari-flim-phasor-plotter': NAPARI_FLIM_PHASOR_PLOTTER,
314
+ 'zenodo-13625087': ZENODO_13625087,
315
+ 'convallaria-fbd': CONVALLARIA_FBD,
316
+ }
317
+ """Pooch repositories."""
318
+
319
+
320
+ def fetch(
321
+ *args: str | Iterable[str | pooch.Pooch] | pooch.Pooch,
322
+ extract_dir: str | None = '.',
323
+ return_scalar: bool = True,
324
+ **kwargs: Any,
325
+ ) -> Any: # str | tuple[str, ...]
326
+ """Return absolute path(s) to sample file(s) in local storage.
327
+
328
+ The files are downloaded from a remote repository if they do not already
329
+ exist in the local storage.
330
+
331
+ Parameters
332
+ ----------
333
+ *args: str or iterable of str, optional
334
+ Name(s) of file(s) or repositories to fetch from local storage.
335
+ If omitted, return files in all repositories.
336
+ extract_dir : str or None, optional
337
+ Path, relative to cache location, where ZIP files will be unpacked.
338
+ return_scalar : bool, optional
339
+ If true (default), return single path as string, else tuple of string.
340
+ **kwargs : optional
341
+ Additional arguments passed to ``pooch.fetch()``.
342
+ For example, ``progressbar=True``.
343
+
344
+ Returns
345
+ -------
346
+ str or tuple of str
347
+ Absolute path(s) of file(s) in local storage.
348
+
349
+ Examples
350
+ --------
351
+ >>> fetch('simfcs.r64')
352
+ '...simfcs.r64'
353
+ >>> fetch('simfcs.r64', 'simfcs.ref')
354
+ ('...simfcs.r64', '...simfcs.ref')
355
+
356
+ """
357
+ filenames: list[str] = []
358
+ if not args:
359
+ args = tuple(REPOSITORIES.keys())
360
+ for arg in args:
361
+ if isinstance(arg, str):
362
+ if arg in REPOSITORIES:
363
+ # fetch all files in repository
364
+ filenames.extend(
365
+ fetch(
366
+ *REPOSITORIES[arg].registry.keys(),
367
+ extract_dir=extract_dir,
368
+ return_scalar=False,
369
+ **kwargs,
370
+ )
371
+ )
372
+ continue
373
+ for repo in REPOSITORIES.values():
374
+ if arg + '.zip' in repo.registry:
375
+ # fetch single file in ZIP
376
+ filenames.append(
377
+ repo.fetch(
378
+ arg + '.zip',
379
+ processor=_Unzip([arg], extract_dir),
380
+ **kwargs,
381
+ )
382
+ )
383
+ break
384
+ if arg in repo.registry:
385
+ if arg.endswith('.zip'):
386
+ # fetch and extract all files in ZIP
387
+ filenames.extend(
388
+ repo.fetch(
389
+ arg,
390
+ processor=pooch.processors.Unzip(
391
+ extract_dir=extract_dir
392
+ ),
393
+ **kwargs,
394
+ )
395
+ )
396
+ else:
397
+ # fetch single file
398
+ filenames.append(repo.fetch(arg, **kwargs))
399
+ break
400
+ else:
401
+ raise ValueError(f'file {arg!r} not found')
402
+ elif isinstance(arg, pooch.Pooch):
403
+ # fetch all files in repository
404
+ filenames.extend(
405
+ fetch(
406
+ *arg.registry.keys(),
407
+ extract_dir=extract_dir,
408
+ return_scalar=False,
409
+ **kwargs,
410
+ )
411
+ )
412
+ else:
413
+ # fetch all files in iterable
414
+ filenames.extend(
415
+ fetch(
416
+ *arg,
417
+ extract_dir=extract_dir,
418
+ return_scalar=False,
419
+ **kwargs,
420
+ )
421
+ )
422
+ if return_scalar and len(filenames) == 1:
423
+ return filenames[0]
424
+ return tuple(filenames)
425
+
426
+
427
+ class _Unzip(pooch.processors.ExtractorProcessor): # type: ignore[misc]
428
+ """Pooch processor that unpacks ZIP archive and returns single file."""
429
+
430
+ def __call__(self, fname: str, action: str, pooch_: pooch.Pooch) -> str:
431
+ pooch.processors.ExtractorProcessor.__call__(
432
+ self, fname, action, pooch_
433
+ )
434
+ return os.path.splitext(fname)[0]
435
+
436
+ @property
437
+ def suffix(self) -> str:
438
+ """String appended to unpacked archive folder name."""
439
+ return '.unzip'
440
+
441
+ def _all_members(self, fname: str) -> list[str]:
442
+ """Return all members from archive."""
443
+ from zipfile import ZipFile
444
+
445
+ with ZipFile(fname, 'r') as zip_file:
446
+ return zip_file.namelist()
447
+
448
+ def _extract_file(self, fname: str, extract_dir: str) -> None:
449
+ """Extract all files from ZIP archive."""
450
+ from zipfile import ZipFile
451
+
452
+ with ZipFile(fname, 'r') as zip_file:
453
+ zip_file.extractall(path=extract_dir)