phasorpy 0.7__tar.gz → 0.8__tar.gz

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.
Files changed (131) hide show
  1. {phasorpy-0.7 → phasorpy-0.8}/MANIFEST.in +1 -2
  2. {phasorpy-0.7/src/phasorpy.egg-info → phasorpy-0.8}/PKG-INFO +8 -7
  3. {phasorpy-0.7 → phasorpy-0.8}/docs/_static/switcher.json +8 -8
  4. phasorpy-0.8/docs/api/_phasorpy.rst +8 -0
  5. phasorpy-0.8/docs/api/_utils.rst +5 -0
  6. phasorpy-0.8/docs/api/filter.rst +5 -0
  7. {phasorpy-0.7 → phasorpy-0.8}/docs/api/index.rst +1 -0
  8. {phasorpy-0.7 → phasorpy-0.8}/docs/conf.py +72 -3
  9. {phasorpy-0.7 → phasorpy-0.8}/docs/phasor_approach.rst +15 -0
  10. {phasorpy-0.7 → phasorpy-0.8}/docs/release.rst +51 -12
  11. {phasorpy-0.7 → phasorpy-0.8}/pyproject.toml +13 -12
  12. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/__init__.py +1 -1
  13. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/_phasorpy.pyx +39 -1
  14. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/_utils.py +13 -5
  15. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/cluster.py +2 -2
  16. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/component.py +10 -6
  17. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/datasets.py +1 -1
  18. phasorpy-0.8/src/phasorpy/experimental.py +148 -0
  19. phasorpy-0.8/src/phasorpy/filter.py +966 -0
  20. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/io/__init__.py +2 -1
  21. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/io/_flimlabs.py +6 -6
  22. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/io/_leica.py +36 -34
  23. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/io/_ometiff.py +8 -6
  24. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/io/_other.py +3 -3
  25. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/io/_simfcs.py +11 -8
  26. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/lifetime.py +16 -16
  27. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/phasor.py +122 -642
  28. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/plot/_functions.py +6 -6
  29. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/plot/_lifetime_plots.py +1 -1
  30. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/plot/_phasorplot.py +17 -20
  31. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/plot/_phasorplot_fret.py +1 -1
  32. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/utils.py +1 -0
  33. {phasorpy-0.7 → phasorpy-0.8/src/phasorpy.egg-info}/PKG-INFO +8 -7
  34. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy.egg-info/SOURCES.txt +13 -0
  35. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy.egg-info/requires.txt +5 -4
  36. phasorpy-0.8/tests/io/_conftest.py +67 -0
  37. phasorpy-0.8/tests/io/test_flimlabs.py +239 -0
  38. phasorpy-0.8/tests/io/test_leica.py +137 -0
  39. phasorpy-0.8/tests/io/test_ometiff.py +305 -0
  40. phasorpy-0.8/tests/io/test_other.py +333 -0
  41. phasorpy-0.8/tests/io/test_simfcs.py +421 -0
  42. phasorpy-0.8/tests/plot/test_functions.py +304 -0
  43. phasorpy-0.8/tests/plot/test_lifetime_plots.py +105 -0
  44. phasorpy-0.8/tests/plot/test_phasorplot.py +494 -0
  45. phasorpy-0.8/tests/plot/test_phasorplot_fret.py +53 -0
  46. {phasorpy-0.7 → phasorpy-0.8}/tests/test__utils.py +1 -1
  47. phasorpy-0.8/tests/test_experimental.py +37 -0
  48. phasorpy-0.8/tests/test_filter.py +1333 -0
  49. {phasorpy-0.7 → phasorpy-0.8}/tests/test_nan.py +1 -2
  50. {phasorpy-0.7 → phasorpy-0.8}/tests/test_phasor.py +84 -1192
  51. {phasorpy-0.7 → phasorpy-0.8}/tutorials/api/phasorpy_cursor.py +2 -1
  52. {phasorpy-0.7 → phasorpy-0.8}/tutorials/api/phasorpy_filter.py +4 -4
  53. {phasorpy-0.7 → phasorpy-0.8}/tutorials/api/phasorpy_io.py +17 -18
  54. {phasorpy-0.7 → phasorpy-0.8}/tutorials/api/phasorpy_multi_harmonic.py +2 -5
  55. {phasorpy-0.7 → phasorpy-0.8}/tutorials/applications/phasorpy_component_fit.py +2 -6
  56. {phasorpy-0.7 → phasorpy-0.8}/tutorials/applications/phasorpy_fret_efficiency.py +3 -9
  57. {phasorpy-0.7 → phasorpy-0.8}/tutorials/applications/phasorpy_multidimensional.py +2 -5
  58. {phasorpy-0.7 → phasorpy-0.8}/tutorials/misc/phasorpy_phasor_from_signal.py +2 -2
  59. {phasorpy-0.7 → phasorpy-0.8}/tutorials/phasorpy_introduction.py +6 -3
  60. {phasorpy-0.7 → phasorpy-0.8}/tutorials/phasorpy_lfd_workshop.py +2 -5
  61. phasorpy-0.7/docs/api/_phasorpy.rst +0 -12
  62. phasorpy-0.7/docs/api/_utils.rst +0 -9
  63. phasorpy-0.7/src/phasorpy/experimental.py +0 -310
  64. phasorpy-0.7/tests/test_experimental.py +0 -117
  65. {phasorpy-0.7 → phasorpy-0.8}/LICENSE.txt +0 -0
  66. {phasorpy-0.7 → phasorpy-0.8}/README.md +0 -0
  67. {phasorpy-0.7 → phasorpy-0.8}/docs/_static/categorical.png +0 -0
  68. {phasorpy-0.7 → phasorpy-0.8}/docs/_static/custom-icons.js +0 -0
  69. {phasorpy-0.7 → phasorpy-0.8}/docs/_static/favicon.ico +0 -0
  70. {phasorpy-0.7 → phasorpy-0.8}/docs/_static/phasorpy_logo.png +0 -0
  71. {phasorpy-0.7 → phasorpy-0.8}/docs/_static/phasorpy_logo.svg +0 -0
  72. {phasorpy-0.7 → phasorpy-0.8}/docs/_static/srgb_spectrum.png +0 -0
  73. {phasorpy-0.7 → phasorpy-0.8}/docs/acknowledgments.rst +0 -0
  74. {phasorpy-0.7 → phasorpy-0.8}/docs/api/cli.rst +0 -0
  75. {phasorpy-0.7 → phasorpy-0.8}/docs/api/cluster.rst +0 -0
  76. {phasorpy-0.7 → phasorpy-0.8}/docs/api/color.rst +0 -0
  77. {phasorpy-0.7 → phasorpy-0.8}/docs/api/component.rst +0 -0
  78. {phasorpy-0.7 → phasorpy-0.8}/docs/api/cursor.rst +0 -0
  79. {phasorpy-0.7 → phasorpy-0.8}/docs/api/datasets.rst +0 -0
  80. {phasorpy-0.7 → phasorpy-0.8}/docs/api/experimental.rst +0 -0
  81. {phasorpy-0.7 → phasorpy-0.8}/docs/api/io.rst +0 -0
  82. {phasorpy-0.7 → phasorpy-0.8}/docs/api/lifetime.rst +0 -0
  83. {phasorpy-0.7 → phasorpy-0.8}/docs/api/phasor.rst +0 -0
  84. {phasorpy-0.7 → phasorpy-0.8}/docs/api/phasorpy.rst +0 -0
  85. {phasorpy-0.7 → phasorpy-0.8}/docs/api/plot.rst +0 -0
  86. {phasorpy-0.7 → phasorpy-0.8}/docs/api/utils.rst +0 -0
  87. {phasorpy-0.7 → phasorpy-0.8}/docs/code_of_conduct.rst +0 -0
  88. {phasorpy-0.7 → phasorpy-0.8}/docs/contributing.rst +0 -0
  89. {phasorpy-0.7 → phasorpy-0.8}/docs/index.rst +0 -0
  90. {phasorpy-0.7 → phasorpy-0.8}/docs/license.rst +0 -0
  91. {phasorpy-0.7 → phasorpy-0.8}/setup.cfg +0 -0
  92. {phasorpy-0.7 → phasorpy-0.8}/setup.py +0 -0
  93. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/__main__.py +0 -0
  94. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/_typing.py +0 -0
  95. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/cli.py +0 -0
  96. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/color.py +0 -0
  97. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/conftest.py +0 -0
  98. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/cursor.py +0 -0
  99. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/plot/__init__.py +0 -0
  100. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy/py.typed +0 -0
  101. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy.egg-info/dependency_links.txt +0 -0
  102. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy.egg-info/entry_points.txt +0 -0
  103. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy.egg-info/not-zip-safe +0 -0
  104. {phasorpy-0.7 → phasorpy-0.8}/src/phasorpy.egg-info/top_level.txt +0 -0
  105. {phasorpy-0.7 → phasorpy-0.8}/tests/conftest.py +0 -0
  106. {phasorpy-0.7 → phasorpy-0.8}/tests/test__phasorpy.py +0 -0
  107. {phasorpy-0.7 → phasorpy-0.8}/tests/test__typing.py +0 -0
  108. {phasorpy-0.7 → phasorpy-0.8}/tests/test_cli.py +0 -0
  109. {phasorpy-0.7 → phasorpy-0.8}/tests/test_cluster.py +0 -0
  110. {phasorpy-0.7 → phasorpy-0.8}/tests/test_color.py +0 -0
  111. {phasorpy-0.7 → phasorpy-0.8}/tests/test_component.py +0 -0
  112. {phasorpy-0.7 → phasorpy-0.8}/tests/test_cursor.py +0 -0
  113. {phasorpy-0.7 → phasorpy-0.8}/tests/test_datasets.py +0 -0
  114. {phasorpy-0.7 → phasorpy-0.8}/tests/test_lifetime.py +0 -0
  115. {phasorpy-0.7 → phasorpy-0.8}/tests/test_phasorpy.py +0 -0
  116. {phasorpy-0.7 → phasorpy-0.8}/tests/test_utils.py +0 -0
  117. {phasorpy-0.7 → phasorpy-0.8}/tools/build_manylinux.cmd +0 -0
  118. {phasorpy-0.7 → phasorpy-0.8}/tools/build_manylinux.sh +0 -0
  119. {phasorpy-0.7 → phasorpy-0.8}/tools/sha256.py +0 -0
  120. {phasorpy-0.7 → phasorpy-0.8}/tutorials/README.rst +0 -0
  121. {phasorpy-0.7 → phasorpy-0.8}/tutorials/api/README.rst +0 -0
  122. {phasorpy-0.7 → phasorpy-0.8}/tutorials/api/phasorpy_component.py +0 -0
  123. {phasorpy-0.7 → phasorpy-0.8}/tutorials/api/phasorpy_fret.py +0 -0
  124. {phasorpy-0.7 → phasorpy-0.8}/tutorials/api/phasorpy_lifetime_to_signal.py +0 -0
  125. {phasorpy-0.7 → phasorpy-0.8}/tutorials/api/phasorpy_pca.py +0 -0
  126. {phasorpy-0.7 → phasorpy-0.8}/tutorials/api/phasorpy_phasor_from_lifetime.py +0 -0
  127. {phasorpy-0.7 → phasorpy-0.8}/tutorials/api/phasorpy_phasorplot.py +0 -0
  128. {phasorpy-0.7 → phasorpy-0.8}/tutorials/applications/README.rst +0 -0
  129. {phasorpy-0.7 → phasorpy-0.8}/tutorials/misc/README.rst +0 -0
  130. {phasorpy-0.7 → phasorpy-0.8}/tutorials/misc/phasorpy_logo.py +0 -0
  131. {phasorpy-0.7 → phasorpy-0.8}/tutorials/phasorpy_lifetime_geometry.py +0 -0
@@ -1,13 +1,12 @@
1
1
  include LICENSE.txt
2
2
  include README.md
3
3
 
4
- include tests/*.py
5
-
6
4
  include docs/*.py
7
5
  include docs/*.rst
8
6
  include docs/api/*.rst
9
7
  include docs/_static/*.*
10
8
 
9
+ recursive-include tests *.py
11
10
  recursive-include tutorials *.py
12
11
  recursive-include tutorials *.rst
13
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: phasorpy
3
- Version: 0.7
3
+ Version: 0.8
4
4
  Summary: Analysis of fluorescence lifetime and hyperspectral images using the phasor approach
5
5
  Author: PhasorPy Contributors
6
6
  License-Expression: MIT
@@ -18,20 +18,20 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
18
  Classifier: Operating System :: OS Independent
19
19
  Classifier: Programming Language :: Python :: 3
20
20
  Classifier: Programming Language :: Python :: 3 :: Only
21
- Classifier: Programming Language :: Python :: 3.11
22
21
  Classifier: Programming Language :: Python :: 3.12
23
22
  Classifier: Programming Language :: Python :: 3.13
24
- Requires-Python: >=3.11
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Requires-Python: >=3.12
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: LICENSE.txt
27
- Requires-Dist: numpy>=1.26.0
28
- Requires-Dist: matplotlib>=3.8.0
29
- Requires-Dist: scipy>=1.11.0
27
+ Requires-Dist: numpy>=2.0.0
28
+ Requires-Dist: matplotlib>=3.9.0
29
+ Requires-Dist: scipy>=1.13.0
30
30
  Requires-Dist: click
31
31
  Requires-Dist: pooch
32
32
  Requires-Dist: tqdm
33
33
  Requires-Dist: scikit-learn>=1.5.0
34
- Requires-Dist: xarray>=2023.4.0
34
+ Requires-Dist: xarray>=2024.6.0
35
35
  Requires-Dist: tifffile>=2024.8.30
36
36
  Provides-Extra: docs
37
37
  Requires-Dist: sphinx; extra == "docs"
@@ -46,6 +46,7 @@ Requires-Dist: lfdfiles>=2024.5.24; extra == "all"
46
46
  Requires-Dist: sdtfile>=2024.5.24; extra == "all"
47
47
  Requires-Dist: ptufile>=2024.9.14; extra == "all"
48
48
  Requires-Dist: liffile>=2025.2.10; extra == "all"
49
+ Requires-Dist: fbdfile>=2025.9.18; extra == "all"
49
50
  Requires-Dist: pawflim; extra == "all"
50
51
  Dynamic: license-file
51
52
 
@@ -1,23 +1,23 @@
1
1
  [
2
2
  {
3
3
  "name": "dev",
4
- "version": "0.8",
4
+ "version": "0.9",
5
5
  "url": "https://www.phasorpy.org/docs/dev/"
6
6
  },
7
7
  {
8
- "name": "0.7 (stable)",
9
- "version": "0.7",
8
+ "name": "0.8 (stable)",
9
+ "version": "0.8",
10
10
  "url": "https://www.phasorpy.org/docs/stable/",
11
11
  "preferred": true
12
12
  },
13
+ {
14
+ "name": "0.7",
15
+ "version": "0.7",
16
+ "url": "https://www.phasorpy.org/docs/v0.7/"
17
+ },
13
18
  {
14
19
  "name": "0.6",
15
20
  "version": "0.6",
16
21
  "url": "https://www.phasorpy.org/docs/v0.6/"
17
- },
18
- {
19
- "name": "0.5",
20
- "version": "0.5",
21
- "url": "https://www.phasorpy.org/docs/v0.5/"
22
22
  }
23
23
  ]
@@ -0,0 +1,8 @@
1
+ phasorpy._phasorpy
2
+ ------------------
3
+
4
+ .. automodule:: phasorpy._phasorpy
5
+ :members:
6
+ :undoc-members:
7
+ :private-members:
8
+ :special-members:
@@ -0,0 +1,5 @@
1
+ phasorpy._utils
2
+ ---------------
3
+
4
+ .. automodule:: phasorpy._utils
5
+ :members:
@@ -0,0 +1,5 @@
1
+ phasorpy.filter
2
+ ---------------
3
+
4
+ .. automodule:: phasorpy.filter
5
+ :members:
@@ -14,6 +14,7 @@ PhasorPy library version |version|.
14
14
  phasorpy
15
15
  phasor
16
16
  lifetime
17
+ filter
17
18
  component
18
19
  cluster
19
20
  cursor
@@ -26,7 +26,7 @@ import phasorpy
26
26
 
27
27
  version = phasorpy.__version__
28
28
  release = phasorpy.__version__
29
- version_match = version.replace('.dev', '').replace('.rc', '')
29
+ version_match = version.split('.dev')[0].split('.rc')[0]
30
30
 
31
31
  # general configuration
32
32
 
@@ -35,7 +35,8 @@ extensions = [
35
35
  'sphinx.ext.autodoc',
36
36
  'sphinx.ext.autosummary',
37
37
  'sphinx.ext.doctest',
38
- 'sphinx.ext.viewcode',
38
+ # 'sphinx.ext.viewcode', # include source code in documentation
39
+ 'sphinx.ext.linkcode', # link to source code on GitHub
39
40
  'sphinx.ext.todo',
40
41
  # don't enable intersphinx since tutorials are getting littered with links
41
42
  # 'sphinx.ext.intersphinx',
@@ -60,6 +61,7 @@ html_static_path = ['_static']
60
61
  html_js_files = ['custom-icons.js']
61
62
  html_show_sourcelink = False
62
63
 
64
+ html_title = f'PhasorPy {version} documentation'
63
65
  html_logo = '_static/phasorpy_logo.svg'
64
66
  html_favicon = '_static/favicon.ico'
65
67
 
@@ -125,6 +127,11 @@ sphinx_gallery_conf = {
125
127
  'reference_url': {'phasorpy': None},
126
128
  'matplotlib_animations': True,
127
129
  'within_subsection_order': 'conf.TutorialOrder',
130
+ 'show_memory': False,
131
+ 'show_api_usage': False,
132
+ 'remove_config_comments': True,
133
+ # 'min_reported_time': 0.5,
134
+ # 'backreferences_dir': None,
128
135
  }
129
136
 
130
137
 
@@ -176,7 +183,69 @@ intersphinx_mapping = {
176
183
  'skimage': ('https://scikit-image.org/docs/stable/', None),
177
184
  }
178
185
 
179
- intersphinx_disabled_reftypes = ['*']
186
+ # limit intersphinx linking to avoid "littering" tutorials
187
+ # disable doc links but allow function links
188
+ # intersphinx_disabled_reftypes = ['std:doc']
180
189
 
181
190
  # do not show typehints
182
191
  autodoc_typehints = 'none'
192
+
193
+
194
+ def linkcode_resolve(domain: str, info: dict[str, str]) -> str | None:
195
+ """Return GitHub URL for Python object."""
196
+ # adapted from
197
+ # https://github.com/matplotlib/matplotlib/blob/main/doc/conf.py
198
+ import inspect
199
+ from pathlib import Path
200
+
201
+ if domain != 'py':
202
+ return None
203
+
204
+ modname = info['module']
205
+ fullname = info['fullname']
206
+
207
+ submod = sys.modules.get(modname)
208
+ if submod is None:
209
+ return None
210
+
211
+ obj = submod
212
+ for part in fullname.split('.'):
213
+ try:
214
+ obj = getattr(obj, part)
215
+ except AttributeError:
216
+ return None
217
+
218
+ if inspect.isfunction(obj):
219
+ obj = inspect.unwrap(obj)
220
+ try:
221
+ fn = inspect.getsourcefile(obj)
222
+ except TypeError:
223
+ fn = None
224
+ if not fn or fn.endswith('__init__.py'):
225
+ try:
226
+ fn = inspect.getsourcefile(sys.modules[obj.__module__])
227
+ except (TypeError, AttributeError, KeyError):
228
+ fn = None
229
+ if not fn:
230
+ return None
231
+
232
+ try:
233
+ source, lineno = inspect.getsourcelines(obj)
234
+ except (OSError, TypeError):
235
+ lineno = None
236
+
237
+ linespec = f"#L{lineno:d}-L{lineno + len(source) - 1:d}" if lineno else ''
238
+
239
+ startdir = Path(phasorpy.__file__).parent.parent
240
+ try:
241
+ fn = os.path.relpath(fn, start=startdir).replace(os.path.sep, '/')
242
+ except ValueError:
243
+ return None
244
+
245
+ if '.dev' in version or '.rc' in version:
246
+ tag = 'main'
247
+ else:
248
+ tag = f'v{version}'
249
+ return (
250
+ f'https://github.com/phasorpy/phasorpy/blob/{tag}/src/{fn}{linespec}'
251
+ )
@@ -166,12 +166,20 @@ approach to analyze fluorescence time-resolved or spectral images:
166
166
  images using the phasor approach. The software is distributed under an
167
167
  unknown license and was last updated in 2013.
168
168
 
169
+ -
170
+ .. _napari_phasors:
171
+
172
+ `Napari-phasors <https://github.com/napari-phasors/napari-phasors>`_
173
+ is a napari plugin for phasor analysis based on PhasorPy.
174
+ The plugin is distributed under the BSD-3-Clause license.
175
+
169
176
  -
170
177
  .. _napari_flim_phasor_plotter:
171
178
 
172
179
  `Napari-flim-phasor-plotter <https://github.com/zoccoler/napari-flim-phasor-plotter>`_
173
180
  is a napari plugin to interactively load and show raw FLIM single images
174
181
  and series and generate phasor plots.
182
+ The plugin is distributed under the BSD-3-Clause license.
175
183
 
176
184
  -
177
185
  .. _napari_live_flim:
@@ -263,6 +271,13 @@ approach to analyze fluorescence time-resolved or spectral images:
263
271
  "instant FLIM" system. It supports image segmentation based on phasor plot
264
272
  regions of interest and K-means clustering.
265
273
 
274
+ .. _cell_analysis_tools:
275
+
276
+ - `Cell-analysis-tools <https://github.com/skalalab/cell-analysis-tools>`_
277
+ is an open-source Python library for the analysis of single cell imaging
278
+ data, including phasor analysis of FLIM data.
279
+ The library is distributed under the GPL v3.
280
+
266
281
  -
267
282
  .. _flim_studio:
268
283
 
@@ -9,8 +9,47 @@ documentation and maintenance changes.
9
9
  The PhasorPy library is still under construction. Backwards-incompatible
10
10
  changes may occur between revisions.
11
11
 
12
- 0.7 (2025.8.22)
13
- ---------------
12
+ 0.8 (2025-10-10)
13
+ ----------------
14
+
15
+ This is the eighth alpha release of the PhasorPy library.
16
+ It contains several improvements and breaking changes.
17
+
18
+ Filter-related functions have moved from the ``phasor`` module to the new
19
+ ``filter`` module.
20
+ A new ``signal_filter_ncpca`` function has been added that filters signals
21
+ using noise-corrected principal component analysis.
22
+ The ``experimental.spectral_vector_denoise`` function has been renamed to
23
+ ``filter.signal_filter_svd``.
24
+
25
+ The ``signal_from_fbd`` function has been updated to use the ``fbdfile``
26
+ package.
27
+
28
+ This release supports Python 3.12 to 3.14. Python 3.11 is no longer supported.
29
+
30
+ What's Changed
31
+ ..............
32
+
33
+ * Bump version by @cgohlke in https://github.com/phasorpy/phasorpy/pull/287
34
+ * Fix sdist does not contain all tests by @cgohlke in https://github.com/phasorpy/phasorpy/pull/288
35
+ * Improve documentation by @cgohlke in https://github.com/phasorpy/phasorpy/pull/295
36
+ * Mention cell-analysis-tools library by @cgohlke in https://github.com/phasorpy/phasorpy/pull/296
37
+ * Add filter module by @cgohlke in https://github.com/phasorpy/phasorpy/pull/290
38
+ * Document how to calibrate LIF Fast FLIM lifetimes by @cgohlke in https://github.com/phasorpy/phasorpy/pull/289
39
+ * Add signal_filter_ncpca function by @cgohlke in https://github.com/phasorpy/phasorpy/pull/297
40
+ * Raise minimum version requirements by @cgohlke in https://github.com/phasorpy/phasorpy/pull/298
41
+ * Mention napari-phasors software by @cgohlke in https://github.com/phasorpy/phasorpy/pull/301
42
+ * Add phasor_combine function by @cgohlke in https://github.com/phasorpy/phasorpy/pull/300
43
+ * Bump the github-actions group with 2 updates by @dependabot[bot] in https://github.com/phasorpy/phasorpy/pull/299
44
+ * Update to mkl_fft 2.0 by @cgohlke in https://github.com/phasorpy/phasorpy/pull/302
45
+ * Use fbdfile package to read FBD files by @cgohlke in https://github.com/phasorpy/phasorpy/pull/303
46
+ * Support Python 3.14 and drop Python 3.11 by @cgohlke in https://github.com/phasorpy/phasorpy/pull/304
47
+ * Release v0.8 by @cgohlke in https://github.com/phasorpy/phasorpy/pull/306
48
+
49
+ **Full Changelog**: https://github.com/phasorpy/phasorpy/compare/v0.7...v0.8
50
+
51
+ 0.7 (2025-08-22)
52
+ ----------------
14
53
 
15
54
  This is the seventh alpha release of the PhasorPy library.
16
55
  It contains several bug fixes, improvements, and breaking changes.
@@ -77,8 +116,8 @@ What's Changed
77
116
 
78
117
  **Full Changelog**: https://github.com/phasorpy/phasorpy/compare/v0.6...v0.7
79
118
 
80
- 0.6 (2025.6.22)
81
- ---------------
119
+ 0.6 (2025-06-22)
120
+ ----------------
82
121
 
83
122
  This is the sixth alpha release of the PhasorPy library.
84
123
  It contains several bug fixes, improvements, and breaking changes.
@@ -141,8 +180,8 @@ What's Changed
141
180
 
142
181
  **Full Changelog**: https://github.com/phasorpy/phasorpy/compare/v0.5...v0.6
143
182
 
144
- 0.5 (2025.4.11)
145
- ---------------
183
+ 0.5 (2025-04-11)
184
+ ----------------
146
185
 
147
186
  This is the fifth alpha release of the PhasorPy library.
148
187
  It contains several bug fixes and improvements.
@@ -193,8 +232,8 @@ What's Changed
193
232
 
194
233
  **Full Changelog**: https://github.com/phasorpy/phasorpy/compare/v0.4...v0.5
195
234
 
196
- 0.4 (2025.1.30)
197
- ---------------
235
+ 0.4 (2025-01-30)
236
+ ----------------
198
237
 
199
238
  This is the fourth alpha release of the PhasorPy library.
200
239
  It contains several bug fixes and many improvements, mostly to the
@@ -226,7 +265,7 @@ What's Changed
226
265
 
227
266
  **Full Changelog**: https://github.com/phasorpy/phasorpy/compare/v0.3...v0.4
228
267
 
229
- 0.3 (2024.12.16)
268
+ 0.3 (2024-12-16)
230
269
  ----------------
231
270
 
232
271
  This is the third alpha release of the PhasorPy library.
@@ -251,7 +290,7 @@ What's Changed
251
290
 
252
291
  **Full Changelog**: https://github.com/phasorpy/phasorpy/compare/v0.2...v0.3
253
292
 
254
- 0.2 (2024.11.30)
293
+ 0.2 (2024-11-30)
255
294
  ----------------
256
295
 
257
296
  This is the second alpha release of the PhasorPy library.
@@ -285,8 +324,8 @@ What's Changed
285
324
 
286
325
  **Full Changelog**: https://github.com/phasorpy/phasorpy/compare/v0.1...v0.2
287
326
 
288
- 0.1 (2024.9.30)
289
- ---------------
327
+ 0.1 (2024-09-30)
328
+ ----------------
290
329
 
291
330
  This is the first alpha release of the PhasorPy library.
292
331
  It contains over 70 documented and tested functions and class methods to
@@ -2,7 +2,7 @@
2
2
  requires = [
3
3
  "setuptools>=68",
4
4
  "numpy",
5
- "cython>=3.1.0",
5
+ "cython>=3.1.4",
6
6
  ]
7
7
  build-backend = "setuptools.build_meta"
8
8
 
@@ -14,19 +14,19 @@ dynamic = ["version"]
14
14
  dependencies = [
15
15
  # sync with requirements_min.txt
16
16
  # https://scientific-python.org/specs/spec-0000/
17
- "numpy>=1.26.0",
18
- "matplotlib>=3.8.0",
19
- "scipy>=1.11.0",
17
+ "numpy>=2.0.0",
18
+ "matplotlib>=3.9.0",
19
+ "scipy>=1.13.0",
20
20
  "click",
21
21
  "pooch",
22
22
  "tqdm",
23
23
  "scikit-learn>=1.5.0",
24
- # "scikit-image>=0.21.0",
25
- # "pandas>=2.1.0",
26
- "xarray>=2023.4.0",
24
+ # "scikit-image>=0.23.0",
25
+ # "pandas>=2.2.0",
26
+ "xarray>=2024.6.0",
27
27
  "tifffile>=2024.8.30",
28
28
  ]
29
- requires-python = ">=3.11"
29
+ requires-python = ">=3.12"
30
30
  classifiers = [
31
31
  "Development Status :: 3 - Alpha",
32
32
  "Intended Audience :: Developers",
@@ -36,9 +36,9 @@ classifiers = [
36
36
  "Operating System :: OS Independent",
37
37
  "Programming Language :: Python :: 3",
38
38
  "Programming Language :: Python :: 3 :: Only",
39
- "Programming Language :: Python :: 3.11",
40
39
  "Programming Language :: Python :: 3.12",
41
40
  "Programming Language :: Python :: 3.13",
41
+ "Programming Language :: Python :: 3.14",
42
42
  ]
43
43
  authors = [{ name = "PhasorPy Contributors" }]
44
44
  license = "MIT"
@@ -70,6 +70,7 @@ all = [
70
70
  "sdtfile>=2024.5.24",
71
71
  "ptufile>=2024.9.14",
72
72
  "liffile>=2025.2.10",
73
+ "fbdfile>=2025.9.18",
73
74
  "pawflim",
74
75
  ]
75
76
 
@@ -113,7 +114,7 @@ disable = [
113
114
 
114
115
  [tool.black]
115
116
  line-length = 79
116
- target-version = ["py311", "py312", "py313"]
117
+ target-version = ["py312", "py313"]
117
118
  skip-string-normalization = true
118
119
 
119
120
  [tool.isort]
@@ -178,7 +179,7 @@ norecursedirs = [
178
179
  ]
179
180
 
180
181
  [tool.cibuildwheel]
181
- skip = "cp38* cp39* cp310* *musllinux* *i686 *ppc64le *s390x"
182
- test-requires = ["scikit-learn", "lfdfiles", "sdtfile", "ptufile", "liffile", "pawflim", "pytest", "pytest-cov", "pytest-runner", "pytest-doctestplus", "coverage"]
182
+ skip = "cp38* cp39* cp310* cp311* *musllinux* *i686 *ppc64le *s390x"
183
+ test-requires = ["scikit-learn", "lfdfiles", "fbdfile", "sdtfile", "ptufile", "liffile", "pawflim", "pytest", "pytest-cov", "pytest-runner", "pytest-doctestplus", "coverage"]
183
184
  test-command = "pytest {project}/tests"
184
185
  test-environment = "SKIP_FETCH=1"
@@ -5,5 +5,5 @@ from __future__ import annotations
5
5
  __all__ = ['__version__']
6
6
 
7
7
 
8
- __version__ = '0.7'
8
+ __version__ = '0.8'
9
9
  """PhasorPy version string."""
@@ -6,7 +6,13 @@
6
6
  # cython: nonecheck = False
7
7
  # cython: freethreading_compatible = True
8
8
 
9
- """Cython implementation of low-level functions for the PhasorPy library."""
9
+ """Private functions implemented in Cython for performance.
10
+
11
+ .. note::
12
+ This module and its functions are not part of the public interface.
13
+ They are intended to facilitate the development of the PhasorPy library.
14
+
15
+ """
10
16
 
11
17
  cimport cython
12
18
 
@@ -1005,6 +1011,38 @@ cdef (float_t, float_t) _phasor_divide(
1005
1011
  )
1006
1012
 
1007
1013
 
1014
+ @cython.ufunc
1015
+ cdef (float_t, float_t, float_t) _phasor_combine(
1016
+ float_t int0,
1017
+ float_t real0,
1018
+ float_t imag0,
1019
+ float_t int1,
1020
+ float_t real1,
1021
+ float_t imag1,
1022
+ float_t fraction0,
1023
+ float_t fraction1,
1024
+ ) noexcept nogil:
1025
+ """Return linear combination of two phasor coordinates."""
1026
+ cdef:
1027
+ float_t intensity
1028
+
1029
+ fraction1 += fraction0
1030
+ if fraction1 == 0.0:
1031
+ return <float_t> 0.0, <float_t> NAN, <float_t> NAN
1032
+ fraction0 /= fraction1
1033
+
1034
+ int0 *= fraction0
1035
+ int1 *= <float_t> 1.0 - fraction0
1036
+ intensity = int0 + int1
1037
+
1038
+ if intensity == 0.0:
1039
+ return <float_t> 0.0, <float_t> NAN, <float_t> NAN
1040
+
1041
+ int0 /= intensity
1042
+ int1 /= intensity
1043
+ return intensity, int0 * real0 + int1 * real1, int0 * imag0 + int1 * imag1
1044
+
1045
+
1008
1046
  ###############################################################################
1009
1047
  # Geometry ufuncs
1010
1048
 
@@ -1,4 +1,10 @@
1
- """Private auxiliary and convenience functions."""
1
+ """Private auxiliary and convenience functions.
2
+
3
+ .. note::
4
+ This module and its functions are not part of the public interface.
5
+ They are intended to facilitate the development of the PhasorPy library.
6
+
7
+ """
2
8
 
3
9
  from __future__ import annotations
4
10
 
@@ -667,7 +673,7 @@ def chunk_iter(
667
673
 
668
674
 
669
675
  def init_module(globs: dict[str, Any], /) -> None:
670
- """Add names in module to ``__all__`` and set ``__module__`` attributes.
676
+ """Add names in module to ``__all__`` attribute.
671
677
 
672
678
  Parameters
673
679
  ----------
@@ -690,9 +696,11 @@ def init_module(globs: dict[str, Any], /) -> None:
690
696
  }:
691
697
  continue
692
698
  names.append(name)
693
- obj = getattr(module, name)
694
- if hasattr(obj, '__module__'):
695
- obj.__module__ = module_name
699
+ # do not change __module__ attributes because that may interfere
700
+ # with introspection and pickling
701
+ # obj = getattr(module, name)
702
+ # if hasattr(obj, '__module__'):
703
+ # obj.__module__ = module_name
696
704
  globs['__all__'] = sorted(set(names))
697
705
 
698
706
 
@@ -1,6 +1,6 @@
1
1
  """Cluster phasor coordinates.
2
2
 
3
- The `phasorpy.cluster` module provides functions to:
3
+ The ``phasorpy.cluster`` module provides functions to:
4
4
 
5
5
  - fit elliptic clusters to phasor coordinates using a
6
6
  Gaussian Mixture Model (GMM):
@@ -66,7 +66,7 @@ def phasor_cluster_gmm(
66
66
  - 'area': Sort by inverse area of ellipse (-major * minor).
67
67
 
68
68
  **kwargs
69
- Additional keyword arguments passed to
69
+ Optional arguments passed to
70
70
  :py:class:`sklearn.mixture.GaussianMixture`.
71
71
 
72
72
  Common options include:
@@ -1,4 +1,4 @@
1
- """Component analysis of phasor coordinates.
1
+ """Analyze components in phasor coordinates.
2
2
 
3
3
  The ``phasorpy.component`` module provides functions to:
4
4
 
@@ -53,7 +53,7 @@ from ._phasorpy import (
53
53
  _segment_direction_and_length,
54
54
  )
55
55
  from ._utils import sort_coordinates
56
- from .phasor import phasor_threshold
56
+ from .filter import phasor_threshold
57
57
  from .utils import number_threads
58
58
 
59
59
 
@@ -95,6 +95,10 @@ def phasor_from_component(
95
95
  imag : ndarray
96
96
  Imaginary component of phasor coordinates.
97
97
 
98
+ See Also
99
+ --------
100
+ phasorpy.phasor.phasor_combine
101
+
98
102
  Examples
99
103
  --------
100
104
  Calculate phasor coordinates from two components and their fractional
@@ -110,7 +114,7 @@ def phasor_from_component(
110
114
  if dtype.char not in {'f', 'd'}:
111
115
  raise ValueError(f'{dtype=} is not a floating point type')
112
116
 
113
- fraction = numpy.array(fraction, dtype=dtype, copy=True)
117
+ fraction = numpy.asarray(fraction, dtype=dtype, copy=True)
114
118
  if fraction.ndim < 1:
115
119
  raise ValueError(f'{fraction.ndim=} < 1')
116
120
  if fraction.shape[axis] < 2:
@@ -362,7 +366,7 @@ def phasor_component_graphical(
362
366
 
363
367
  dtype = numpy.min_scalar_type(real.size)
364
368
  counts = numpy.empty(
365
- (1 if num_components == 2 else 3, fractions.size), dtype
369
+ (1 if num_components == 2 else 3, fractions.size), dtype=dtype
366
370
  )
367
371
 
368
372
  c = 0
@@ -438,8 +442,8 @@ def phasor_component_fit(
438
442
  component_imag : array_like
439
443
  Imaginary coordinates of components.
440
444
  Must be one or two-dimensional with harmonics in the first dimension.
441
- **kwargs : optional
442
- Additional arguments passed to :py:func:`scipy.linalg.lstsq()`.
445
+ **kwargs
446
+ Optional arguments passed to :py:func:`scipy.linalg.lstsq`.
443
447
 
444
448
  Returns
445
449
  -------
@@ -600,7 +600,7 @@ def fetch(
600
600
  return_scalar : bool, optional
601
601
  If true (default), return single path as string, else tuple of string.
602
602
  **kwargs
603
- Additional arguments passed to ``pooch.fetch()``.
603
+ Optional arguments passed to :py:func:`pooch.fetch`.
604
604
  For example, ``progressbar=True``.
605
605
 
606
606
  Returns