phasorpy 0.12__tar.gz → 0.13__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.
- {phasorpy-0.12/src/phasorpy.egg-info → phasorpy-0.13}/PKG-INFO +6 -6
- {phasorpy-0.12 → phasorpy-0.13}/docs/_static/switcher.json +8 -8
- {phasorpy-0.12 → phasorpy-0.13}/docs/conf.py +32 -2
- {phasorpy-0.12 → phasorpy-0.13}/docs/phasor_approach.rst +2 -2
- {phasorpy-0.12 → phasorpy-0.13}/pyproject.toml +43 -42
- {phasorpy-0.12 → phasorpy-0.13}/setup.py +40 -13
- phasorpy-0.13/src/phasorpy/__init__.py +13 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/__main__.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/_phasorpy.pyx +42 -17
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/_typing.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/_utils.py +31 -13
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/cli.py +53 -25
- phasorpy-0.13/src/phasorpy/cluster.py +430 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/color.py +33 -8
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/component.py +34 -16
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/conftest.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/cursor.py +7 -1
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/datasets.py +47 -41
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/experimental.py +8 -2
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/filter.py +44 -23
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/io/__init__.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/io/_flimlabs.py +22 -10
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/io/_leica.py +17 -6
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/io/_ometiff.py +12 -17
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/io/_other.py +44 -18
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/io/_simfcs.py +36 -10
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/lifetime.py +41 -26
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/phasor.py +32 -14
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/plot/__init__.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/plot/_functions.py +30 -18
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/plot/_lifetime_plots.py +91 -2
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/plot/_phasorplot.py +86 -48
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/plot/_phasorplot_fret.py +8 -4
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/plot/_spectral_plots.py +18 -7
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/utils.py +16 -10
- {phasorpy-0.12 → phasorpy-0.13/src/phasorpy.egg-info}/PKG-INFO +6 -6
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy.egg-info/SOURCES.txt +1 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy.egg-info/requires.txt +5 -6
- {phasorpy-0.12 → phasorpy-0.13}/tests/conftest.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/io/_conftest.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/io/test_flimlabs.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/io/test_leica.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/io/test_ometiff.py +5 -1
- {phasorpy-0.12 → phasorpy-0.13}/tests/io/test_other.py +18 -2
- {phasorpy-0.12 → phasorpy-0.13}/tests/io/test_simfcs.py +14 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/plot/test_functions.py +43 -0
- phasorpy-0.13/tests/plot/test_lifetime_plots.py +196 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/plot/test_phasorplot.py +102 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/plot/test_phasorplot_fret.py +23 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/plot/test_spectral_plots.py +33 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/test__phasorpy.py +52 -1
- {phasorpy-0.12 → phasorpy-0.13}/tests/test__typing.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/test__utils.py +17 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_cli.py +25 -0
- phasorpy-0.13/tests/test_cluster.py +372 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_color.py +19 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_component.py +56 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_cursor.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_datasets.py +24 -1
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_experimental.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_filter.py +91 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_lifetime.py +79 -2
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_nan.py +16 -1
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_phasor.py +76 -5
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_phasorpy.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tests/test_utils.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tools/sha256.py +4 -0
- phasorpy-0.13/tutorials/api/phasorpy_cluster.py +212 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/api/phasorpy_component.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/api/phasorpy_cursor.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/api/phasorpy_filter.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/api/phasorpy_fret.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/api/phasorpy_io.py +8 -4
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/api/phasorpy_lifetime_to_signal.py +6 -2
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/api/phasorpy_multi_harmonic.py +5 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/api/phasorpy_pca.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/api/phasorpy_phasor_from_lifetime.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/api/phasorpy_phasorplot.py +7 -3
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/applications/phasorpy_component_fit.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/applications/phasorpy_fret_efficiency.py +27 -9
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/applications/phasorpy_multidimensional.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/applications/phasorpy_nadh_concentration.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/applications/phasorpy_nadh_fraction.py +21 -12
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/misc/phasorpy_apps.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/misc/phasorpy_logo.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/misc/phasorpy_phasor_from_signal.py +41 -34
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/phasorpy_introduction.py +18 -6
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/phasorpy_lfd_workshop.py +4 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/phasorpy_lifetime_geometry.py +19 -42
- phasorpy-0.12/src/phasorpy/__init__.py +0 -9
- phasorpy-0.12/src/phasorpy/cluster.py +0 -227
- phasorpy-0.12/tests/plot/test_lifetime_plots.py +0 -101
- phasorpy-0.12/tests/test_cluster.py +0 -117
- {phasorpy-0.12 → phasorpy-0.13}/LICENSE.txt +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/MANIFEST.in +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/README.md +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/_static/categorical.png +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/_static/custom-icons.js +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/_static/favicon.ico +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/_static/phasorpy_logo.png +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/_static/phasorpy_logo.svg +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/_static/srgb_spectrum.png +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/about.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/acknowledgments.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/_phasorpy.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/_utils.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/cli.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/cluster.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/color.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/component.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/cursor.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/datasets.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/experimental.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/filter.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/index.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/io.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/lifetime.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/phasor.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/phasorpy.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/plot.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/api/utils.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/code_of_conduct.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/contributing.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/index.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/docs/license.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/setup.cfg +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy/py.typed +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy.egg-info/dependency_links.txt +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy.egg-info/entry_points.txt +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy.egg-info/not-zip-safe +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/src/phasorpy.egg-info/top_level.txt +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/tools/build_manylinux.cmd +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/tools/build_manylinux.sh +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/README.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/api/README.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/applications/README.rst +0 -0
- {phasorpy-0.12 → phasorpy-0.13}/tutorials/misc/README.rst +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: phasorpy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13
|
|
4
4
|
Summary: Analysis of luminescence lifetime and hyperspectral images using the phasor approach
|
|
5
5
|
Author: PhasorPy Contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -21,14 +21,15 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.13
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
24
25
|
Requires-Python: >=3.12
|
|
25
26
|
Description-Content-Type: text/markdown
|
|
26
27
|
License-File: LICENSE.txt
|
|
27
28
|
Requires-Dist: numpy>=2.1.0
|
|
28
|
-
Requires-Dist: matplotlib>=3.
|
|
29
|
-
Requires-Dist: pandas>=2.3.
|
|
29
|
+
Requires-Dist: matplotlib>=3.10.3
|
|
30
|
+
Requires-Dist: pandas>=2.3.2
|
|
30
31
|
Requires-Dist: scikit-learn>=1.5.0
|
|
31
|
-
Requires-Dist: scipy>=1.14.
|
|
32
|
+
Requires-Dist: scipy>=1.14.1
|
|
32
33
|
Requires-Dist: tifffile>=2026.5.2
|
|
33
34
|
Requires-Dist: xarray>=2024.6.0
|
|
34
35
|
Requires-Dist: click
|
|
@@ -42,8 +43,7 @@ Requires-Dist: liffile>=2025.2.10; extra == "all"
|
|
|
42
43
|
Requires-Dist: ptufile>=2024.9.14; extra == "all"
|
|
43
44
|
Requires-Dist: sdtfile>=2024.5.24; extra == "all"
|
|
44
45
|
Requires-Dist: pawflim>=1.0.4; extra == "all"
|
|
45
|
-
Requires-Dist: brighteyes-mcs-reader>=0.1.0; extra == "all"
|
|
46
|
-
Requires-Dist: imagecodecs==2026.6.6; (sys_platform == "darwin" and platform_machine == "x86_64") and extra == "all"
|
|
46
|
+
Requires-Dist: brighteyes-mcs-reader>=0.1.0; python_version < "3.15" and extra == "all"
|
|
47
47
|
Dynamic: license-file
|
|
48
48
|
|
|
49
49
|
# <img src="https://www.phasorpy.org/_static/phasorpy_logo.svg" alt="○" width="48" height="48" align="left"/> PhasorPy
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
3
|
"name": "dev",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.14",
|
|
5
5
|
"url": "https://www.phasorpy.org/docs/dev/"
|
|
6
6
|
},
|
|
7
7
|
{
|
|
8
|
-
"name": "0.
|
|
9
|
-
"version": "0.
|
|
8
|
+
"name": "0.13 (stable)",
|
|
9
|
+
"version": "0.13",
|
|
10
10
|
"url": "https://www.phasorpy.org/docs/stable/",
|
|
11
11
|
"preferred": true
|
|
12
12
|
},
|
|
13
|
+
{
|
|
14
|
+
"name": "0.12",
|
|
15
|
+
"version": "0.12",
|
|
16
|
+
"url": "https://www.phasorpy.org/docs/v0.12/"
|
|
17
|
+
},
|
|
13
18
|
{
|
|
14
19
|
"name": "0.11",
|
|
15
20
|
"version": "0.11",
|
|
@@ -19,10 +24,5 @@
|
|
|
19
24
|
"name": "0.10",
|
|
20
25
|
"version": "0.10",
|
|
21
26
|
"url": "https://www.phasorpy.org/docs/v0.10/"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"name": "0.9",
|
|
25
|
-
"version": "0.9",
|
|
26
|
-
"url": "https://www.phasorpy.org/docs/v0.9/"
|
|
27
27
|
}
|
|
28
28
|
]
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# Copyright (c) PhasorPy Contributors
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
# See LICENSE.txt file in the project root for details.
|
|
4
|
+
|
|
1
5
|
"""Sphinx build configuration file.
|
|
2
6
|
|
|
3
7
|
https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
@@ -13,6 +17,8 @@ sys.path.insert(0, os.path.dirname(__file__))
|
|
|
13
17
|
|
|
14
18
|
# remove the examples header from HTML tutorials
|
|
15
19
|
import sphinx_gallery.gen_rst
|
|
20
|
+
from docutils import nodes
|
|
21
|
+
from sphinx.application import Sphinx
|
|
16
22
|
from sphinx_gallery.sorting import ExplicitOrder
|
|
17
23
|
|
|
18
24
|
sphinx_gallery.gen_rst.EXAMPLE_HEADER = (
|
|
@@ -170,6 +176,7 @@ class TutorialOrder:
|
|
|
170
176
|
'multi_harmonic',
|
|
171
177
|
'phasorplot',
|
|
172
178
|
'cursor',
|
|
179
|
+
'cluster',
|
|
173
180
|
'component',
|
|
174
181
|
'pca',
|
|
175
182
|
# misc
|
|
@@ -206,6 +213,29 @@ intersphinx_mapping = {
|
|
|
206
213
|
# do not show typehints
|
|
207
214
|
autodoc_typehints = 'none'
|
|
208
215
|
|
|
216
|
+
# redirect links to defunct websites, for example, to the Web Archive
|
|
217
|
+
link_redirects = {
|
|
218
|
+
'https://www.lfd.uci.edu': (
|
|
219
|
+
'https://web.archive.org/web/20260926221331/https://www.lfd.uci.edu'
|
|
220
|
+
),
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def redirect_links(app: Sphinx, doctree: nodes.document) -> None:
|
|
225
|
+
"""Replace URL prefixes in links according to link_redirects."""
|
|
226
|
+
del app
|
|
227
|
+
for node in doctree.findall(nodes.reference):
|
|
228
|
+
refuri = node.get('refuri', '')
|
|
229
|
+
for old, new in link_redirects.items():
|
|
230
|
+
if refuri.startswith(old):
|
|
231
|
+
node['refuri'] = new + refuri[len(old) :]
|
|
232
|
+
break
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def setup(app: Sphinx) -> None:
|
|
236
|
+
"""Set up Sphinx app with link redirection."""
|
|
237
|
+
app.connect('doctree-read', redirect_links)
|
|
238
|
+
|
|
209
239
|
|
|
210
240
|
def linkcode_resolve(domain: str, info: dict[str, str]) -> str | None:
|
|
211
241
|
"""Return GitHub URL for Python object."""
|
|
@@ -231,8 +261,8 @@ def linkcode_resolve(domain: str, info: dict[str, str]) -> str | None:
|
|
|
231
261
|
except AttributeError:
|
|
232
262
|
return None
|
|
233
263
|
|
|
234
|
-
if inspect.isfunction(obj):
|
|
235
|
-
obj = inspect.unwrap(obj)
|
|
264
|
+
if inspect.isfunction(obj): # type: ignore[unreachable]
|
|
265
|
+
obj = inspect.unwrap(obj) # type: ignore[unreachable]
|
|
236
266
|
try:
|
|
237
267
|
fn = inspect.getsourcefile(obj)
|
|
238
268
|
except TypeError:
|
|
@@ -148,9 +148,9 @@ luminescence time-resolved or spectral images:
|
|
|
148
148
|
|
|
149
149
|
* - **Library**
|
|
150
150
|
- :ref:`PhasorPy <phasorpy>`,
|
|
151
|
-
:ref:`PyFLI <pyfli>`,
|
|
152
151
|
:ref:`tttrlib <tttrlib>`,
|
|
153
152
|
:ref:`FLIMLib <flimlib>`:sup:`2`,
|
|
153
|
+
:ref:`PyFLI <pyfli>`:sup:`2`,
|
|
154
154
|
:ref:`BrightEyes <brighteyes>`:sup:`2`,
|
|
155
155
|
:ref:`FLIM_tools <flim_tools>`:sup:`2,4`,
|
|
156
156
|
:ref:`Cell-analysis-tools <cell_analysis_tools>`:sup:`2,4`
|
|
@@ -333,7 +333,7 @@ Details:
|
|
|
333
333
|
is an open-source Python platform for Fluorescence Lifetime Imaging
|
|
334
334
|
(FLI) data simulation, processing and visualization, including phasor
|
|
335
335
|
analysis.
|
|
336
|
-
The library is distributed under the
|
|
336
|
+
The library is distributed under the AGPL-3.0 license.
|
|
337
337
|
|
|
338
338
|
-
|
|
339
339
|
.. _flim_tools:
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[build-system]
|
|
2
2
|
requires = [
|
|
3
|
-
"setuptools>=
|
|
3
|
+
"setuptools>=77",
|
|
4
4
|
"numpy>=2.1.0",
|
|
5
|
-
"cython>=3.2.
|
|
5
|
+
"cython>=3.2.9",
|
|
6
6
|
]
|
|
7
7
|
build-backend = "setuptools.build_meta"
|
|
8
8
|
|
|
@@ -15,11 +15,11 @@ dependencies = [
|
|
|
15
15
|
# sync with [dependency-groups.run]
|
|
16
16
|
# https://scientific-python.org/specs/spec-0000/
|
|
17
17
|
"numpy>=2.1.0",
|
|
18
|
-
"matplotlib>=3.
|
|
19
|
-
"pandas>=2.3.
|
|
18
|
+
"matplotlib>=3.10.3",
|
|
19
|
+
"pandas>=2.3.2",
|
|
20
20
|
# "scikit-image>=0.24.0",
|
|
21
21
|
"scikit-learn>=1.5.0",
|
|
22
|
-
"scipy>=1.14.
|
|
22
|
+
"scipy>=1.14.1",
|
|
23
23
|
"tifffile>=2026.5.2",
|
|
24
24
|
"xarray>=2024.6.0",
|
|
25
25
|
"click",
|
|
@@ -39,6 +39,7 @@ classifiers = [
|
|
|
39
39
|
"Programming Language :: Python :: 3.12",
|
|
40
40
|
"Programming Language :: Python :: 3.13",
|
|
41
41
|
"Programming Language :: Python :: 3.14",
|
|
42
|
+
"Programming Language :: Python :: 3.15",
|
|
42
43
|
]
|
|
43
44
|
authors = [{ name = "PhasorPy Contributors" }]
|
|
44
45
|
license = "MIT"
|
|
@@ -65,8 +66,8 @@ all = [
|
|
|
65
66
|
"ptufile>=2024.9.14",
|
|
66
67
|
"sdtfile>=2024.5.24",
|
|
67
68
|
"pawflim>=1.0.4",
|
|
68
|
-
"brighteyes-mcs-reader>=0.1.0",
|
|
69
|
-
"imagecodecs==2026.6.6; sys_platform == 'darwin' and platform_machine == 'x86_64'",
|
|
69
|
+
"brighteyes-mcs-reader>=0.1.0; python_version < '3.15'",
|
|
70
|
+
# "imagecodecs==2026.6.6; sys_platform == 'darwin' and platform_machine == 'x86_64'",
|
|
70
71
|
# "mkl-fft>=2.1.1",
|
|
71
72
|
]
|
|
72
73
|
|
|
@@ -74,10 +75,10 @@ all = [
|
|
|
74
75
|
run = [
|
|
75
76
|
# runtime dependencies; sync with [project.dependencies]
|
|
76
77
|
"numpy>=2.1.0",
|
|
77
|
-
"matplotlib>=3.10.
|
|
78
|
-
"pandas>=2.3.
|
|
78
|
+
"matplotlib>=3.10.3",
|
|
79
|
+
"pandas>=2.3.2",
|
|
79
80
|
"scikit-learn>=1.5.0",
|
|
80
|
-
"scipy>=1.14.
|
|
81
|
+
"scipy>=1.14.1",
|
|
81
82
|
"tifffile>=2026.5.2",
|
|
82
83
|
"xarray>=2024.6.0",
|
|
83
84
|
"click",
|
|
@@ -93,8 +94,8 @@ optional = [
|
|
|
93
94
|
"ptufile>=2024.9.14",
|
|
94
95
|
"sdtfile>=2024.5.24",
|
|
95
96
|
"pawflim>=1.0.4",
|
|
96
|
-
"brighteyes-mcs-reader>=0.1.0",
|
|
97
|
-
"imagecodecs==2026.6.6; sys_platform == 'darwin' and platform_machine == 'x86_64'",
|
|
97
|
+
"brighteyes-mcs-reader>=0.1.0; python_version < '3.15'",
|
|
98
|
+
# "imagecodecs==2026.6.6; sys_platform == 'darwin' and platform_machine == 'x86_64'",
|
|
98
99
|
]
|
|
99
100
|
minimal = [
|
|
100
101
|
# minimal runtime versions for testing against oldest supported versions
|
|
@@ -117,7 +118,7 @@ minimal = [
|
|
|
117
118
|
]
|
|
118
119
|
build = [
|
|
119
120
|
# build requirements
|
|
120
|
-
"cython>=3.2.
|
|
121
|
+
"cython>=3.2.9",
|
|
121
122
|
"numpy>=2.1.0",
|
|
122
123
|
"abi3audit",
|
|
123
124
|
"build",
|
|
@@ -150,7 +151,7 @@ docs = [
|
|
|
150
151
|
lint = [
|
|
151
152
|
# static code analysis requirements
|
|
152
153
|
"autoflake",
|
|
153
|
-
"black",
|
|
154
|
+
"black>=26.10.1",
|
|
154
155
|
"blackdoc",
|
|
155
156
|
# "codespell",
|
|
156
157
|
"cython_lint",
|
|
@@ -262,9 +263,9 @@ typing-modules = ["_typing"]
|
|
|
262
263
|
"__init__.py" = ["F401", "F403"]
|
|
263
264
|
"conftest.py" = ["ARG001"]
|
|
264
265
|
"setup.py" = ["T201"]
|
|
265
|
-
"tests/*" = ["INP001", "PT011", "SLF001", "TC001"]
|
|
266
|
+
"tests/*" = ["INP001", "PT011", "SLF001", "TC001", "PLR0917"]
|
|
266
267
|
"tools/*" = ["ANN", "INP001", "T201"]
|
|
267
|
-
"tutorials/*" = ["ANN", "D", "E402", "INP001", "T201", "
|
|
268
|
+
"tutorials/*" = ["ANN", "D", "E402", "INP001", "T201", "PLR0917"]
|
|
268
269
|
"docs/conf.py" = ["A001", "ANN204", "D102", "E402", "INP001", "RUF012"]
|
|
269
270
|
|
|
270
271
|
[tool.ruff.format]
|
|
@@ -273,6 +274,9 @@ quote-style = "single"
|
|
|
273
274
|
[tool.ruff.lint.flake8-quotes]
|
|
274
275
|
inline-quotes = "single"
|
|
275
276
|
|
|
277
|
+
[tool.ruff.lint.flake8-copyright]
|
|
278
|
+
notice-rgx = "(#\\s*Copyright\\s*\\(c\\)\\s*PhasorPy\\s*Contributors)"
|
|
279
|
+
|
|
276
280
|
[tool.ruff.lint.pydocstyle]
|
|
277
281
|
convention = "numpy"
|
|
278
282
|
|
|
@@ -307,7 +311,7 @@ disable = [
|
|
|
307
311
|
|
|
308
312
|
[tool.black]
|
|
309
313
|
line-length = 79
|
|
310
|
-
target-version = ["py312", "py313", "py314"]
|
|
314
|
+
target-version = ["py312", "py313", "py314", "py315"]
|
|
311
315
|
skip-string-normalization = true
|
|
312
316
|
|
|
313
317
|
[tool.isort]
|
|
@@ -345,6 +349,8 @@ warn_unreachable = true
|
|
|
345
349
|
module = [
|
|
346
350
|
"_conftest",
|
|
347
351
|
"phasorpy._phasorpy",
|
|
352
|
+
"setuptools.*",
|
|
353
|
+
"sphinx_gallery.*",
|
|
348
354
|
"pooch.*",
|
|
349
355
|
"scipy.*",
|
|
350
356
|
"mkl_fft.*",
|
|
@@ -353,6 +359,12 @@ module = [
|
|
|
353
359
|
]
|
|
354
360
|
ignore_missing_imports = true
|
|
355
361
|
|
|
362
|
+
[[tool.mypy.overrides]]
|
|
363
|
+
# PyQt6 6.12 stubs contain syntax errors that block mypy
|
|
364
|
+
module = ["PyQt6.*"]
|
|
365
|
+
follow_imports = "skip"
|
|
366
|
+
follow_imports_for_stubs = true
|
|
367
|
+
|
|
356
368
|
[tool.coverage.run]
|
|
357
369
|
plugins = ["Cython.Coverage"]
|
|
358
370
|
omit = ["conftest.py", "__main__.py"]
|
|
@@ -392,7 +404,6 @@ norecursedirs = [
|
|
|
392
404
|
".pytest_cache",
|
|
393
405
|
".ruff_cache",
|
|
394
406
|
".vscode",
|
|
395
|
-
"htmlcov",
|
|
396
407
|
"adhoc",
|
|
397
408
|
"build",
|
|
398
409
|
"docs/_build",
|
|
@@ -406,30 +417,20 @@ norecursedirs = [
|
|
|
406
417
|
]
|
|
407
418
|
|
|
408
419
|
[tool.cibuildwheel]
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
"cp310*",
|
|
412
|
-
"cp311*",
|
|
413
|
-
"cp313*",
|
|
414
|
-
"cp314-*",
|
|
415
|
-
"cp315*",
|
|
416
|
-
"*musllinux*",
|
|
417
|
-
"*i686*",
|
|
418
|
-
"*ppc64le*",
|
|
419
|
-
"*s390x*",
|
|
420
|
-
]
|
|
420
|
+
build = ["cp312-*", "cp314t-*", "cp315t-*"]
|
|
421
|
+
skip = ["*musllinux*", "*i686*", "*ppc64le*", "*s390x*"]
|
|
421
422
|
test-command = "pytest {project}/tests"
|
|
422
|
-
test-skip = ["
|
|
423
|
+
test-skip = ["cp3*t*"]
|
|
423
424
|
test-requires = [
|
|
424
425
|
# sync with [dependency-groups.optional]
|
|
425
|
-
"brighteyes-mcs-reader",
|
|
426
|
+
"brighteyes-mcs-reader>=0.1.0; python_version < '3.15'",
|
|
426
427
|
"czifile>=2026.4.11",
|
|
427
|
-
"fbdfile",
|
|
428
|
-
"lfdfiles",
|
|
429
|
-
"liffile",
|
|
430
|
-
"ptufile",
|
|
431
|
-
"sdtfile",
|
|
432
|
-
"pawflim",
|
|
428
|
+
"fbdfile>=2025.9.18",
|
|
429
|
+
"lfdfiles>=2026.6.24",
|
|
430
|
+
"liffile>=2025.2.10",
|
|
431
|
+
"ptufile>=2024.9.14",
|
|
432
|
+
"sdtfile>=2024.5.24",
|
|
433
|
+
"pawflim>=1.0.4",
|
|
433
434
|
# sync with [dependency-groups.test]
|
|
434
435
|
"coverage",
|
|
435
436
|
"cython", # for Cython.Coverage plugin
|
|
@@ -439,10 +440,10 @@ test-requires = [
|
|
|
439
440
|
"pytest-runner",
|
|
440
441
|
]
|
|
441
442
|
|
|
442
|
-
[[tool.cibuildwheel.overrides]]
|
|
443
|
-
select = "*-macosx_x86_64"
|
|
444
|
-
inherit.test-requires = "append"
|
|
445
|
-
test-requires = ["imagecodecs==2026.6.6"]
|
|
443
|
+
# [[tool.cibuildwheel.overrides]]
|
|
444
|
+
# select = "*-macosx_x86_64"
|
|
445
|
+
# inherit.test-requires = "append"
|
|
446
|
+
# test-requires = ["imagecodecs==2026.6.6"]
|
|
446
447
|
|
|
447
448
|
[tool.cibuildwheel.test-environment]
|
|
448
449
|
PHASORPY_DATA_ON_GITHUB = "1"
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# Copyright (c) PhasorPy Contributors
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
# See LICENSE.txt file in the project root for details.
|
|
4
|
+
|
|
1
5
|
"""PhasorPy package Setuptools script."""
|
|
2
6
|
|
|
3
7
|
# project metadata are defined in pyproject.toml
|
|
@@ -8,17 +12,38 @@ import sysconfig
|
|
|
8
12
|
import numpy
|
|
9
13
|
from setuptools import Extension, setup
|
|
10
14
|
|
|
11
|
-
DEBUG =
|
|
15
|
+
DEBUG = os.environ.get('PHASORPY_DEBUG', '').strip().lower() in {
|
|
16
|
+
'1',
|
|
17
|
+
'true',
|
|
18
|
+
'yes',
|
|
19
|
+
'on',
|
|
20
|
+
}
|
|
12
21
|
LIMITED_API = not sysconfig.get_config_var('Py_GIL_DISABLED')
|
|
13
22
|
|
|
14
23
|
print()
|
|
15
24
|
print(f'Building with numpy-{numpy.__version__}')
|
|
16
25
|
print()
|
|
17
26
|
|
|
18
|
-
|
|
27
|
+
extra_compile_args: list[str] = []
|
|
28
|
+
extra_link_args: list[str] = []
|
|
29
|
+
|
|
30
|
+
if 'PYODIDE' in os.environ or 'PYODIDE_ROOT' in os.environ:
|
|
31
|
+
# OpenMP/threads not available in Pyodide
|
|
32
|
+
pass
|
|
33
|
+
elif sys.platform == 'darwin':
|
|
34
|
+
# OpenMP not available in Xcode
|
|
35
|
+
# https://mac.r-project.org/openmp/
|
|
36
|
+
# extra_compile_args = ['-Xclang', '-fopenmp']
|
|
37
|
+
# extra_link_args = ['-lomp']
|
|
38
|
+
pass
|
|
39
|
+
elif sys.platform == 'win32':
|
|
19
40
|
extra_compile_args = ['/openmp']
|
|
20
|
-
|
|
21
|
-
|
|
41
|
+
else:
|
|
42
|
+
extra_compile_args = ['-fopenmp']
|
|
43
|
+
extra_link_args = ['-fopenmp']
|
|
44
|
+
|
|
45
|
+
if DEBUG:
|
|
46
|
+
if sys.platform == 'win32':
|
|
22
47
|
extra_compile_args += [
|
|
23
48
|
'/Zi',
|
|
24
49
|
'/Od',
|
|
@@ -26,14 +51,9 @@ if sys.platform == 'win32':
|
|
|
26
51
|
# '/DCYTHON_TRACE_NOGIL=1', # too slow
|
|
27
52
|
]
|
|
28
53
|
extra_link_args += ['-debug:full']
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
extra_compile_args = [] # ['-Xclang', '-fopenmp']
|
|
33
|
-
extra_link_args = [] # ['-lomp']
|
|
34
|
-
else:
|
|
35
|
-
extra_compile_args = ['-fopenmp']
|
|
36
|
-
extra_link_args = ['-fopenmp']
|
|
54
|
+
else:
|
|
55
|
+
extra_compile_args += ['-g', '-O0', '-DCYTHON_TRACE=1']
|
|
56
|
+
extra_link_args += ['-g']
|
|
37
57
|
|
|
38
58
|
ext_modules = [
|
|
39
59
|
Extension(
|
|
@@ -44,7 +64,7 @@ ext_modules = [
|
|
|
44
64
|
extra_link_args=extra_link_args,
|
|
45
65
|
define_macros=[
|
|
46
66
|
# ('CYTHON_TRACE_NOGIL', '1'),
|
|
47
|
-
('NPY_NO_DEPRECATED_API', '
|
|
67
|
+
('NPY_NO_DEPRECATED_API', 'NPY_2_1_API_VERSION'),
|
|
48
68
|
]
|
|
49
69
|
+ (
|
|
50
70
|
[('Py_LIMITED_API', 0x030C0000), ('CYTHON_LIMITED_API', '1')]
|
|
@@ -55,6 +75,13 @@ ext_modules = [
|
|
|
55
75
|
)
|
|
56
76
|
]
|
|
57
77
|
|
|
78
|
+
if DEBUG:
|
|
79
|
+
from Cython.Build import cythonize
|
|
80
|
+
|
|
81
|
+
ext_modules = cythonize(
|
|
82
|
+
ext_modules, compiler_directives={'linetrace': True}
|
|
83
|
+
) # type: ignore[no-untyped-call]
|
|
84
|
+
|
|
58
85
|
|
|
59
86
|
setup(
|
|
60
87
|
ext_modules=ext_modules,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright (c) PhasorPy Contributors
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
# See LICENSE.txt file in the project root for details.
|
|
4
|
+
|
|
5
|
+
"""PhasorPy package."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
__all__ = ['__version__']
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__version__ = '0.13'
|
|
13
|
+
"""PhasorPy version string."""
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# Copyright (c) PhasorPy Contributors
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
# See LICENSE.txt file in the project root for details.
|
|
4
|
+
|
|
1
5
|
# distutils: language = c
|
|
2
6
|
# cython: boundscheck = False
|
|
3
7
|
# cython: wraparound = False
|
|
@@ -31,6 +35,7 @@ from libc.math cimport (
|
|
|
31
35
|
fmax,
|
|
32
36
|
fmin,
|
|
33
37
|
hypot,
|
|
38
|
+
isinf,
|
|
34
39
|
isnan,
|
|
35
40
|
sin,
|
|
36
41
|
sqrt,
|
|
@@ -132,6 +137,8 @@ def _phasor_from_signal(
|
|
|
132
137
|
# TODO: use NumPy iterator API?
|
|
133
138
|
# https://numpy.org/devdocs/reference/c-api/iterator.html
|
|
134
139
|
|
|
140
|
+
# allow samples=2: the calculation is mathematically defined, but
|
|
141
|
+
# the imaginary component is always zero and phase information is lost
|
|
135
142
|
if (
|
|
136
143
|
samples < 2
|
|
137
144
|
or harmonics > samples // 2
|
|
@@ -295,6 +302,11 @@ def _phasor_from_lifetime(
|
|
|
295
302
|
|
|
296
303
|
if nfreq == 1 and ntau == 1 and nfrac == 1 and ncomp == 1:
|
|
297
304
|
# scalar
|
|
305
|
+
frac = fraction[0, 0]
|
|
306
|
+
if isnan(frac) or fabs(frac) < 1e-15:
|
|
307
|
+
phasor[0, 0, 0] = <float_t> NAN
|
|
308
|
+
phasor[1, 0, 0] = <float_t> NAN
|
|
309
|
+
return
|
|
298
310
|
tau = lifetime[0, 0] * frequency[0] * twopi # omega_tau
|
|
299
311
|
gs = 1.0 / (1.0 + tau * tau)
|
|
300
312
|
phasor[0, 0, 0] = <float_t> gs
|
|
@@ -440,14 +452,14 @@ def _gaussian_signal(
|
|
|
440
452
|
if samples < 1:
|
|
441
453
|
return
|
|
442
454
|
|
|
443
|
-
if folds < 0:
|
|
444
|
-
folds = <ssize_t> (-floor(-6.0 * stdev / <double> samples))
|
|
445
|
-
|
|
446
455
|
with nogil:
|
|
447
|
-
if isnan(mean) or isnan(stdev) or stdev <= 0.0:
|
|
456
|
+
if isnan(mean) or isnan(stdev) or isinf(stdev) or stdev <= 0.0:
|
|
448
457
|
for i in range(samples):
|
|
449
458
|
signal[i] = <float_t> NAN
|
|
450
459
|
else:
|
|
460
|
+
if folds < 0:
|
|
461
|
+
folds = <ssize_t> (-floor(-6.0 * stdev / <double> samples))
|
|
462
|
+
|
|
451
463
|
c = 1.0 / (sqrt(2.0 * M_PI) * stdev)
|
|
452
464
|
|
|
453
465
|
for i in range(-folds * samples, (folds + 1) * samples):
|
|
@@ -766,7 +778,7 @@ cdef (float_t, float_t) _phasor_to_apparent_lifetime(
|
|
|
766
778
|
double taumod = INFINITY
|
|
767
779
|
double t
|
|
768
780
|
|
|
769
|
-
if isnan(real) or isnan(imag):
|
|
781
|
+
if isnan(real) or isnan(imag) or isnan(omega):
|
|
770
782
|
return <float_t> NAN, <float_t> NAN
|
|
771
783
|
|
|
772
784
|
t = real * real + imag * imag
|
|
@@ -816,7 +828,7 @@ cdef float_t _phasor_to_normal_lifetime(
|
|
|
816
828
|
double taunorm = INFINITY
|
|
817
829
|
double t
|
|
818
830
|
|
|
819
|
-
if isnan(real) or isnan(imag):
|
|
831
|
+
if isnan(real) or isnan(imag) or isnan(omega):
|
|
820
832
|
return <float_t> NAN
|
|
821
833
|
|
|
822
834
|
omega *= omega
|
|
@@ -1162,6 +1174,7 @@ cdef unsigned char _is_inside_polar_rectangle(
|
|
|
1162
1174
|
"""Return whether point is inside polar rectangle.
|
|
1163
1175
|
|
|
1164
1176
|
Angles should be in the range [-pi, pi]. Otherwise performance is degraded.
|
|
1177
|
+
If angle_min > angle_max, the angular range wraps around +/- pi.
|
|
1165
1178
|
|
|
1166
1179
|
"""
|
|
1167
1180
|
cdef:
|
|
@@ -1180,10 +1193,11 @@ cdef unsigned char _is_inside_polar_rectangle(
|
|
|
1180
1193
|
angle_min = <float_t> atan2(sin(angle_min), cos(angle_min))
|
|
1181
1194
|
if angle_max < -M_PI or angle_max > M_PI:
|
|
1182
1195
|
angle_max = <float_t> atan2(sin(angle_max), cos(angle_max))
|
|
1183
|
-
if angle_min > angle_max:
|
|
1184
|
-
angle_min, angle_max = angle_max, angle_min
|
|
1185
1196
|
t = <float_t> atan2(y, x)
|
|
1186
|
-
if
|
|
1197
|
+
if angle_min <= angle_max:
|
|
1198
|
+
if t < angle_min or t > angle_max:
|
|
1199
|
+
return False
|
|
1200
|
+
elif t < angle_min and t > angle_max:
|
|
1187
1201
|
return False
|
|
1188
1202
|
|
|
1189
1203
|
return True
|
|
@@ -1504,7 +1518,7 @@ cdef float_t _fraction_on_segment(
|
|
|
1504
1518
|
# square of line length
|
|
1505
1519
|
t = x0 * x0 + y0 * y0
|
|
1506
1520
|
if t <= 0.0:
|
|
1507
|
-
#
|
|
1521
|
+
# degenerate segment, return fraction at (x1, y1)
|
|
1508
1522
|
return 0.0
|
|
1509
1523
|
# projection of point on line
|
|
1510
1524
|
t = (x * x0 + y * y0) / t
|
|
@@ -1549,8 +1563,8 @@ cdef float_t _fraction_on_line(
|
|
|
1549
1563
|
# square of line length
|
|
1550
1564
|
t = x0 * x0 + y0 * y0
|
|
1551
1565
|
if t <= 0.0:
|
|
1552
|
-
#
|
|
1553
|
-
return
|
|
1566
|
+
# degenerate line, return fraction at (x1, y1)
|
|
1567
|
+
return 0.0
|
|
1554
1568
|
# projection of point on line
|
|
1555
1569
|
t = (x * x0 + y * y0) / t
|
|
1556
1570
|
return t
|
|
@@ -1891,7 +1905,7 @@ def _lifetime_search_2(
|
|
|
1891
1905
|
raise ValueError('invalid lifetime shape')
|
|
1892
1906
|
if fraction.shape[0] != 2 or fraction.shape[1] != real.shape[1]:
|
|
1893
1907
|
raise ValueError('invalid fraction shape')
|
|
1894
|
-
if real.shape[0] != imag.shape[0] != 2:
|
|
1908
|
+
if real.shape[0] != 2 or imag.shape[0] != 2:
|
|
1895
1909
|
raise ValueError('invalid phasor harmonics')
|
|
1896
1910
|
if real.shape[1] != imag.shape[1]:
|
|
1897
1911
|
raise ValueError('invalid phasor size')
|
|
@@ -2103,7 +2117,7 @@ def _mean_value_coordinates(
|
|
|
2103
2117
|
"""
|
|
2104
2118
|
cdef:
|
|
2105
2119
|
ssize_t i, j, k, p, nv
|
|
2106
|
-
double x, y, alpha, weight, weight_sum
|
|
2120
|
+
double x, y, alpha, weight, weight_sum, weight_abs_sum
|
|
2107
2121
|
double* weights = NULL
|
|
2108
2122
|
double* sigma = NULL
|
|
2109
2123
|
double* length = NULL
|
|
@@ -2147,6 +2161,7 @@ def _mean_value_coordinates(
|
|
|
2147
2161
|
length[i] = hypot(vx[i] - x, vy[i] - y)
|
|
2148
2162
|
|
|
2149
2163
|
weight_sum = 0.0
|
|
2164
|
+
weight_abs_sum = 0.0
|
|
2150
2165
|
for i in range(nv):
|
|
2151
2166
|
j = (i + 1) % nv # next vertex, wrapped around
|
|
2152
2167
|
k = (i - 1 + nv) % nv # previous vertex, wrapped around
|
|
@@ -2162,9 +2177,11 @@ def _mean_value_coordinates(
|
|
|
2162
2177
|
if j != k and j != i:
|
|
2163
2178
|
weight = weight * length[j] * sin(fabs(sigma[j]) * 0.5)
|
|
2164
2179
|
weight_sum = weight_sum + weight
|
|
2180
|
+
weight_abs_sum = weight_abs_sum + fabs(weight)
|
|
2165
2181
|
weights[i] = weight
|
|
2166
2182
|
|
|
2167
|
-
|
|
2183
|
+
# weights scale with polygon size. use relative threshold
|
|
2184
|
+
if fabs(weight_sum) > 1e-12 * weight_abs_sum:
|
|
2168
2185
|
for i in range(nv):
|
|
2169
2186
|
fraction[order[i], p] = <float_t> (weights[i] / weight_sum)
|
|
2170
2187
|
else:
|
|
@@ -2323,11 +2340,13 @@ cdef (float_t, float_t, float_t) _phasor_threshold_open(
|
|
|
2323
2340
|
if not isnan(imag_max) and imag >= imag_max:
|
|
2324
2341
|
return <float_t> NAN, <float_t> NAN, <float_t> NAN
|
|
2325
2342
|
|
|
2326
|
-
if not isnan(modulation_min):
|
|
2343
|
+
if not isnan(modulation_min) and modulation_min >= 0.0:
|
|
2327
2344
|
mod = real * real + imag * imag
|
|
2328
2345
|
if mod <= modulation_min * modulation_min:
|
|
2329
2346
|
return <float_t> NAN, <float_t> NAN, <float_t> NAN
|
|
2330
2347
|
if not isnan(modulation_max):
|
|
2348
|
+
if modulation_max <= 0.0:
|
|
2349
|
+
return <float_t> NAN, <float_t> NAN, <float_t> NAN
|
|
2331
2350
|
if isnan(mod):
|
|
2332
2351
|
mod = real * real + imag * imag
|
|
2333
2352
|
if mod >= modulation_max * modulation_max:
|
|
@@ -2385,11 +2404,13 @@ cdef (float_t, float_t, float_t) _phasor_threshold_closed(
|
|
|
2385
2404
|
if not isnan(imag_max) and imag > imag_max:
|
|
2386
2405
|
return <float_t> NAN, <float_t> NAN, <float_t> NAN
|
|
2387
2406
|
|
|
2388
|
-
if not isnan(modulation_min):
|
|
2407
|
+
if not isnan(modulation_min) and modulation_min > 0.0:
|
|
2389
2408
|
mod = real * real + imag * imag
|
|
2390
2409
|
if mod < modulation_min * modulation_min:
|
|
2391
2410
|
return <float_t> NAN, <float_t> NAN, <float_t> NAN
|
|
2392
2411
|
if not isnan(modulation_max):
|
|
2412
|
+
if modulation_max < 0.0:
|
|
2413
|
+
return <float_t> NAN, <float_t> NAN, <float_t> NAN
|
|
2393
2414
|
if isnan(mod):
|
|
2394
2415
|
mod = real * real + imag * imag
|
|
2395
2416
|
if mod > modulation_max * modulation_max:
|
|
@@ -2832,6 +2853,8 @@ def _flimlabs_signal(
|
|
|
2832
2853
|
for pixels in channels:
|
|
2833
2854
|
signal_ = signal[c, i]
|
|
2834
2855
|
for h, count in pixels:
|
|
2856
|
+
if count < 0 or <ssize_t> <uint_t> count != count:
|
|
2857
|
+
raise ValueError(f'{count=} overflows signal dtype')
|
|
2835
2858
|
signal_[h] = <uint_t> count
|
|
2836
2859
|
i += 1
|
|
2837
2860
|
c += 1
|
|
@@ -2840,6 +2863,8 @@ def _flimlabs_signal(
|
|
|
2840
2863
|
for pixels in data[channel]:
|
|
2841
2864
|
signal_ = signal[0, i]
|
|
2842
2865
|
for h, count in pixels:
|
|
2866
|
+
if count < 0 or <ssize_t> <uint_t> count != count:
|
|
2867
|
+
raise ValueError(f'{count=} overflows signal dtype')
|
|
2843
2868
|
signal_[h] = <uint_t> count
|
|
2844
2869
|
i += 1
|
|
2845
2870
|
|