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