phasorpy 0.5__tar.gz → 0.6__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.5/src/phasorpy.egg-info → phasorpy-0.6}/PKG-INFO +2 -2
- {phasorpy-0.5 → phasorpy-0.6}/README.md +1 -1
- {phasorpy-0.5 → phasorpy-0.6}/docs/_static/switcher.json +8 -8
- phasorpy-0.6/docs/acknowledgments.rst +42 -0
- phasorpy-0.6/docs/api/experimental.rst +5 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/index.rst +1 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/code_of_conduct.rst +4 -3
- {phasorpy-0.5 → phasorpy-0.6}/docs/conf.py +37 -3
- {phasorpy-0.5 → phasorpy-0.6}/docs/contributing.rst +6 -4
- {phasorpy-0.5 → phasorpy-0.6}/docs/index.rst +0 -1
- {phasorpy-0.5 → phasorpy-0.6}/docs/phasor_approach.rst +2 -2
- {phasorpy-0.5 → phasorpy-0.6}/docs/release.rst +64 -0
- {phasorpy-0.5 → phasorpy-0.6}/pyproject.toml +3 -3
- phasorpy-0.6/src/phasorpy/__init__.py +9 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/_phasorpy.pyx +185 -2
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/_utils.py +121 -9
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/cli.py +56 -3
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/cluster.py +42 -6
- phasorpy-0.6/src/phasorpy/components.py +484 -0
- phasorpy-0.5/src/phasorpy/utils.py → phasorpy-0.6/src/phasorpy/experimental.py +132 -193
- phasorpy-0.6/src/phasorpy/io/__init__.py +137 -0
- phasorpy-0.6/src/phasorpy/io/_flimlabs.py +350 -0
- phasorpy-0.6/src/phasorpy/io/_leica.py +329 -0
- phasorpy-0.6/src/phasorpy/io/_ometiff.py +445 -0
- phasorpy-0.6/src/phasorpy/io/_other.py +782 -0
- phasorpy-0.6/src/phasorpy/io/_simfcs.py +627 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/phasor.py +307 -1
- phasorpy-0.6/src/phasorpy/plot/__init__.py +27 -0
- phasorpy-0.6/src/phasorpy/plot/_functions.py +717 -0
- phasorpy-0.6/src/phasorpy/plot/_lifetime_plots.py +553 -0
- phasorpy-0.6/src/phasorpy/plot/_phasorplot.py +1119 -0
- phasorpy-0.6/src/phasorpy/plot/_phasorplot_fret.py +559 -0
- phasorpy-0.6/src/phasorpy/utils.py +161 -0
- {phasorpy-0.5 → phasorpy-0.6/src/phasorpy.egg-info}/PKG-INFO +2 -2
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy.egg-info/SOURCES.txt +17 -6
- {phasorpy-0.5 → phasorpy-0.6}/tests/conftest.py +1 -2
- {phasorpy-0.5 → phasorpy-0.6}/tests/test__phasorpy.py +78 -18
- {phasorpy-0.5 → phasorpy-0.6}/tests/test__utils.py +3 -3
- {phasorpy-0.5 → phasorpy-0.6}/tests/test_cli.py +15 -1
- {phasorpy-0.5 → phasorpy-0.6}/tests/test_cluster.py +13 -9
- {phasorpy-0.5 → phasorpy-0.6}/tests/test_components.py +153 -32
- phasorpy-0.5/tests/test_utils.py → phasorpy-0.6/tests/test_experimental.py +11 -34
- {phasorpy-0.5 → phasorpy-0.6}/tests/test_nan.py +17 -8
- {phasorpy-0.5 → phasorpy-0.6}/tests/test_phasor.py +230 -7
- phasorpy-0.6/tests/test_phasorpy.py +12 -0
- phasorpy-0.6/tests/test_utils.py +52 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/api/phasorpy_components.py +69 -32
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/api/phasorpy_io.py +2 -4
- phasorpy-0.6/tutorials/applications/phasorpy_component_fit.py +191 -0
- phasorpy-0.6/tutorials/applications/phasorpy_fret_efficiency.py +150 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/benchmarks/phasorpy_phasor_from_signal.py +31 -30
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/phasorpy_introduction.py +3 -1
- phasorpy-0.6/tutorials/phasorpy_lifetime_geometry.py +306 -0
- phasorpy-0.5/docs/acknowledgments.rst +0 -36
- phasorpy-0.5/src/phasorpy/__init__.py +0 -10
- phasorpy-0.5/src/phasorpy/_io.py +0 -2655
- phasorpy-0.5/src/phasorpy/components.py +0 -313
- phasorpy-0.5/src/phasorpy/io.py +0 -9
- phasorpy-0.5/src/phasorpy/plot.py +0 -2318
- phasorpy-0.5/src/phasorpy/version.py +0 -80
- phasorpy-0.5/tests/test_io.py +0 -1324
- phasorpy-0.5/tests/test_phasorpy.py +0 -18
- phasorpy-0.5/tests/test_plot.py +0 -633
- {phasorpy-0.5 → phasorpy-0.6}/LICENSE.txt +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/MANIFEST.in +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/_static/categorical.png +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/_static/custom-icons.js +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/_static/logo.png +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/_static/srgb_spectrum.png +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/_phasorpy.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/_utils.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/cli.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/cluster.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/color.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/components.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/cursors.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/datasets.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/io.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/phasor.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/phasorpy.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/plot.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/api/utils.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/docs/license.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/setup.cfg +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/setup.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/__main__.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/_typing.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/color.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/conftest.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/cursors.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/datasets.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy/py.typed +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy.egg-info/dependency_links.txt +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy.egg-info/entry_points.txt +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy.egg-info/not-zip-safe +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy.egg-info/requires.txt +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/src/phasorpy.egg-info/top_level.txt +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tests/test__typing.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tests/test_color.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tests/test_cursors.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tests/test_datasets.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/README.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/api/README.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/api/phasorpy_cursors.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/api/phasorpy_filtering.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/api/phasorpy_fret.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/api/phasorpy_lifetime_to_signal.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/api/phasorpy_multi-harmonic.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/api/phasorpy_pca.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/api/phasorpy_phasor_from_lifetime.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/api/phasorpy_phasorplot.py +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/applications/README.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/benchmarks/README.rst +0 -0
- {phasorpy-0.5 → phasorpy-0.6}/tutorials/phasorpy_lfd_workshop.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: phasorpy
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.6
|
4
4
|
Summary: Analysis of fluorescence lifetime and hyperspectral images using the phasor approach
|
5
5
|
Author: PhasorPy Contributors
|
6
6
|
License-Expression: MIT
|
@@ -66,7 +66,7 @@ PhasorPy is a community-maintained project.
|
|
66
66
|
in the form of bug reports, bug fixes, feature implementations, documentation,
|
67
67
|
datasets, and enhancement proposals are welcome.
|
68
68
|
|
69
|
-
This software project
|
69
|
+
This software project was supported in part by the
|
70
70
|
[Essential Open Source Software for Science (EOSS)](https://chanzuckerberg.com/eoss/)
|
71
71
|
program at
|
72
72
|
[Chan Zuckerberg Initiative](https://chanzuckerberg.com/).
|
@@ -15,7 +15,7 @@ PhasorPy is a community-maintained project.
|
|
15
15
|
in the form of bug reports, bug fixes, feature implementations, documentation,
|
16
16
|
datasets, and enhancement proposals are welcome.
|
17
17
|
|
18
|
-
This software project
|
18
|
+
This software project was supported in part by the
|
19
19
|
[Essential Open Source Software for Science (EOSS)](https://chanzuckerberg.com/eoss/)
|
20
20
|
program at
|
21
21
|
[Chan Zuckerberg Initiative](https://chanzuckerberg.com/).
|
@@ -1,23 +1,23 @@
|
|
1
1
|
[
|
2
2
|
{
|
3
3
|
"name": "dev",
|
4
|
-
"version": "0.
|
4
|
+
"version": "0.7",
|
5
5
|
"url": "https://www.phasorpy.org/docs/dev/"
|
6
6
|
},
|
7
7
|
{
|
8
|
-
"name": "0.
|
9
|
-
"version": "0.
|
8
|
+
"name": "0.6 (stable)",
|
9
|
+
"version": "0.6",
|
10
10
|
"url": "https://www.phasorpy.org/docs/stable/",
|
11
11
|
"preferred": true
|
12
12
|
},
|
13
|
+
{
|
14
|
+
"name": "0.5",
|
15
|
+
"version": "0.5",
|
16
|
+
"url": "https://www.phasorpy.org/docs/v0.5/"
|
17
|
+
},
|
13
18
|
{
|
14
19
|
"name": "0.4",
|
15
20
|
"version": "0.4",
|
16
21
|
"url": "https://www.phasorpy.org/docs/v0.4/"
|
17
|
-
},
|
18
|
-
{
|
19
|
-
"name": "0.3",
|
20
|
-
"version": "0.3",
|
21
|
-
"url": "https://www.phasorpy.org/docs/v0.3/"
|
22
22
|
}
|
23
23
|
]
|
@@ -0,0 +1,42 @@
|
|
1
|
+
Acknowledgments
|
2
|
+
===============
|
3
|
+
|
4
|
+
The PhasorPy project was established by the
|
5
|
+
`Advanced Bioimaging Unit <https://pasteur.uy/en/units/advanced-bioimaging>`_
|
6
|
+
at the University of the Republic and Institut Pasteur de Montevideo and the
|
7
|
+
`Laboratory for Fluorescence Dynamics <https://www.lfd.uci.edu>`_
|
8
|
+
at the University of California, Irvine.
|
9
|
+
|
10
|
+
PhasorPy was inspired by the
|
11
|
+
`Globals for Images · SimFCS <https://www.lfd.uci.edu/globals/>`_ software by
|
12
|
+
Enrico Gratton.
|
13
|
+
|
14
|
+
This software project was supported in part by the
|
15
|
+
`Essential Open Source Software for Science (EOSS)
|
16
|
+
<https://chanzuckerberg.com/eoss/>`_ program at
|
17
|
+
`Chan Zuckerberg Initiative <https://chanzuckerberg.com/>`_
|
18
|
+
(grant number 2022-252604, 2022-2024).
|
19
|
+
|
20
|
+
.. _contributors:
|
21
|
+
|
22
|
+
Contributors
|
23
|
+
------------
|
24
|
+
|
25
|
+
PhasorPy is developed by `contributors to the PhasorPy repository
|
26
|
+
<https://github.com/phasorpy/phasorpy/graphs/contributors>`_
|
27
|
+
and
|
28
|
+
`members of the PhasorPy organization
|
29
|
+
<https://github.com/orgs/phasorpy/people>`_.
|
30
|
+
|
31
|
+
User Community
|
32
|
+
--------------
|
33
|
+
|
34
|
+
Many thanks to the PhasorPy user community for their feedback, bug reports,
|
35
|
+
feature suggestions, and data files that have helped improve the library.
|
36
|
+
|
37
|
+
Citation
|
38
|
+
--------
|
39
|
+
|
40
|
+
If PhasorPy contributes to a project that leads to a publication,
|
41
|
+
please cite
|
42
|
+
`doi: 10.5281/zenodo.13862586 <https://doi.org/10.5281/zenodo.13862586>`_.
|
@@ -1,3 +1,5 @@
|
|
1
|
+
:orphan:
|
2
|
+
|
1
3
|
Code of conduct
|
2
4
|
===============
|
3
5
|
|
@@ -68,9 +70,8 @@ Enforcement
|
|
68
70
|
-----------
|
69
71
|
|
70
72
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
71
|
-
reported to
|
72
|
-
|
73
|
-
- `Leonel Malacrida <conduct@phasorpy.org>`_
|
73
|
+
reported to `<conduct@phasorpy.org>`_ and `PhasorPy organization members
|
74
|
+
<https://github.com/orgs/phasorpy/people>`_.
|
74
75
|
|
75
76
|
All complaints will be reviewed and investigated promptly and fairly.
|
76
77
|
|
@@ -2,9 +2,10 @@
|
|
2
2
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
3
3
|
# pylint: skip-file
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
import os
|
6
|
+
import sys
|
7
|
+
|
8
|
+
sys.path.insert(0, os.path.dirname(__file__))
|
8
9
|
|
9
10
|
# remove the examples header from HTML tutorials
|
10
11
|
import sphinx_gallery.gen_rst
|
@@ -123,8 +124,41 @@ sphinx_gallery_conf = {
|
|
123
124
|
'gallery_dirs': 'tutorials',
|
124
125
|
'reference_url': {'phasorpy': None},
|
125
126
|
'matplotlib_animations': True,
|
127
|
+
'within_subsection_order': 'conf.TutorialOrder',
|
126
128
|
}
|
127
129
|
|
130
|
+
|
131
|
+
class TutorialOrder:
|
132
|
+
"""Order tutorials in gallery subsections."""
|
133
|
+
|
134
|
+
tutorials = [
|
135
|
+
'introduction',
|
136
|
+
'lifetime_geometry',
|
137
|
+
'lfd_workshop',
|
138
|
+
# api
|
139
|
+
'io',
|
140
|
+
'phasor_from_lifetime',
|
141
|
+
'multi-harmonic',
|
142
|
+
'filtering',
|
143
|
+
'phasorplot',
|
144
|
+
'cursors',
|
145
|
+
'components',
|
146
|
+
'fret',
|
147
|
+
'lifetime_to_signal',
|
148
|
+
'pca',
|
149
|
+
# applications
|
150
|
+
'component_fit',
|
151
|
+
'fret_efficiency',
|
152
|
+
# benchmarks
|
153
|
+
'phasor_from_signal',
|
154
|
+
]
|
155
|
+
|
156
|
+
def __init__(self, srcdir: str): ...
|
157
|
+
|
158
|
+
def __call__(self, filename: str) -> int:
|
159
|
+
return self.tutorials.index(filename[9:-3])
|
160
|
+
|
161
|
+
|
128
162
|
copybutton_prompt_text = (
|
129
163
|
r'>>> |\.\.\. |\$ |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: '
|
130
164
|
)
|
@@ -61,9 +61,9 @@ and include the following items in the bug report:
|
|
61
61
|
of::
|
62
62
|
|
63
63
|
$ python -m phasorpy versions
|
64
|
-
Python
|
65
|
-
phasorpy
|
66
|
-
numpy
|
64
|
+
Python-3.13.3
|
65
|
+
phasorpy-0.5
|
66
|
+
numpy-2.2.6
|
67
67
|
...
|
68
68
|
|
69
69
|
Contribute code or documentation
|
@@ -289,4 +289,6 @@ and must pass before code or documentation can be accepted.
|
|
289
289
|
Other PhasorPy developers will review the pull request to check and help
|
290
290
|
to improve its implementation, documentation, and style.
|
291
291
|
|
292
|
-
Pull requests must be approved by a
|
292
|
+
Pull requests must be approved by a
|
293
|
+
`PhasorPy organization member <https://github.com/orgs/phasorpy/people>`_
|
294
|
+
before merging.
|
@@ -200,8 +200,8 @@ approach to analyze fluorescence time-resolved or spectral images:
|
|
200
200
|
microscopy written in MATLAB by Alexander Vallmitjana, released under
|
201
201
|
the CC BY 4.0 license.
|
202
202
|
|
203
|
-
- `AlliGator <https://
|
204
|
-
is
|
203
|
+
- `AlliGator <https://github.com/smXplorer/AlliGator>`_
|
204
|
+
is an open-source software for fluorescence lifetime image data
|
205
205
|
analysis using the phasor approach and standard nonlinear fitting.
|
206
206
|
The software is written in LabVIEW for Windows by Xavier Michalet.
|
207
207
|
|
@@ -9,6 +9,70 @@ 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.6 (2025.6.22)
|
13
|
+
---------------
|
14
|
+
|
15
|
+
This is the sixth alpha release of the PhasorPy library.
|
16
|
+
It contains several bug fixes, improvements, and breaking changes.
|
17
|
+
|
18
|
+
The new ``phasor_component_fit`` function fits fractions of multiple
|
19
|
+
components to phasor coordinates.
|
20
|
+
The ``phasor_nearest_neighbor`` function returns nearest neighbors in phasor
|
21
|
+
coordinates.
|
22
|
+
The ``phasor_to_normal_lifetime`` function returns single lifetimes closest
|
23
|
+
to phasor coordinates.
|
24
|
+
The ``phasor_semicircle_intersect`` function returns intersections of lines
|
25
|
+
with the universal semicircle.
|
26
|
+
|
27
|
+
The ``LifetimePlots`` class interactively plots lifetimes in the time domain,
|
28
|
+
frequency domain, and phasor plot. It can be invoked from the command line
|
29
|
+
with ``python -m phasorpy lifetime``.
|
30
|
+
|
31
|
+
The ``two_fractions_from_phasor`` and ``graphical_component_analysis``
|
32
|
+
functions are renamed to ``phasor_component_fraction`` and
|
33
|
+
``phasor_component_graphical``, respectively.
|
34
|
+
The ``versions`` function has moved to the ``phasorpy.utils`` namespace.
|
35
|
+
The ``spectral_vector_denoise``, ``anscombe_transform``, and
|
36
|
+
``anscombe_transform_inverse`` functions have moved to the
|
37
|
+
``phasorpy.experimental`` namespace.
|
38
|
+
|
39
|
+
Functions in the ``io`` module now return only the first channel by default.
|
40
|
+
|
41
|
+
Three new tutorials are added: "Geometrical interpretation of lifetimes",
|
42
|
+
"Multi-component fit", and "FRET efficiency image".
|
43
|
+
This release supports Python 3.11 to 3.13.
|
44
|
+
|
45
|
+
What's Changed
|
46
|
+
..............
|
47
|
+
|
48
|
+
* Bump version by @cgohlke in https://github.com/phasorpy/phasorpy/pull/221
|
49
|
+
* Bump pypa/cibuildwheel from 2.23.2 to 2.23.3 in the github-actions group by @dependabot in https://github.com/phasorpy/phasorpy/pull/223
|
50
|
+
* Update description of AlliGator software by @cgohlke in https://github.com/phasorpy/phasorpy/pull/225
|
51
|
+
* Cython 3.1.0 is released by @cgohlke in https://github.com/phasorpy/phasorpy/pull/226
|
52
|
+
* Add phasor_to_normal_lifetime function by @cgohlke in https://github.com/phasorpy/phasorpy/pull/228
|
53
|
+
* Read first channel from files by default by @cgohlke in https://github.com/phasorpy/phasorpy/pull/229
|
54
|
+
* Update acknowledgments by @cgohlke in https://github.com/phasorpy/phasorpy/pull/230
|
55
|
+
* Use importlib to get package versions by @cgohlke in https://github.com/phasorpy/phasorpy/pull/231
|
56
|
+
* Use Windows Server 2022 in GitHub Actions by @cgohlke in https://github.com/phasorpy/phasorpy/pull/232
|
57
|
+
* Add tutorial about geometrical interpretation of lifetimes by @cgohlke in https://github.com/phasorpy/phasorpy/pull/233
|
58
|
+
* Update reference phasor_from_signal benchmark results by @cgohlke in https://github.com/phasorpy/phasorpy/pull/234
|
59
|
+
* Sort clusters returned by phasor_cluster_gmm by @cgohlke in https://github.com/phasorpy/phasorpy/pull/236
|
60
|
+
* Reorganize io module by @cgohlke in https://github.com/phasorpy/phasorpy/pull/235
|
61
|
+
* Update pre-commit configuration by @cgohlke in https://github.com/phasorpy/phasorpy/pull/237
|
62
|
+
* Fix test failing with numpy 2.3.0 by @cgohlke in https://github.com/phasorpy/phasorpy/pull/239
|
63
|
+
* Add phasor_component_fit function by @cgohlke in https://github.com/phasorpy/phasorpy/pull/238
|
64
|
+
* Rename functions in components module by @cgohlke in https://github.com/phasorpy/phasorpy/pull/240
|
65
|
+
* Add phasor_semicircle_intersect function by @cgohlke in https://github.com/phasorpy/phasorpy/pull/241
|
66
|
+
* Add private helper functions to mask universal semicircle by @cgohlke in https://github.com/phasorpy/phasorpy/pull/242
|
67
|
+
* Add private _distance_from_semicircle function by @cgohlke in https://github.com/phasorpy/phasorpy/pull/244
|
68
|
+
* Reorganize plot module by @cgohlke in https://github.com/phasorpy/phasorpy/pull/245
|
69
|
+
* Add interactive LifetimePlots class by @cgohlke in https://github.com/phasorpy/phasorpy/pull/247
|
70
|
+
* Reorganize version, utils, and experimental modules by @cgohlke in https://github.com/phasorpy/phasorpy/pull/248
|
71
|
+
* Add phasor_nearest_neighbor function by @bruno-pannunzio in https://github.com/phasorpy/phasorpy/pull/243
|
72
|
+
* Release v0.6 by @cgohlke in https://github.com/phasorpy/phasorpy/pull/244
|
73
|
+
|
74
|
+
**Full Changelog**: https://github.com/phasorpy/phasorpy/compare/v0.5...v0.6
|
75
|
+
|
12
76
|
0.5 (2025.4.11)
|
13
77
|
---------------
|
14
78
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
requires = [
|
3
3
|
"setuptools>=68",
|
4
4
|
"numpy",
|
5
|
-
"cython>=3.1.
|
5
|
+
"cython>=3.1.0",
|
6
6
|
]
|
7
7
|
build-backend = "setuptools.build_meta"
|
8
8
|
|
@@ -77,7 +77,7 @@ all = [
|
|
77
77
|
zip-safe = false
|
78
78
|
|
79
79
|
[tool.setuptools.dynamic]
|
80
|
-
version = { attr = "phasorpy.
|
80
|
+
version = { attr = "phasorpy.__version__" }
|
81
81
|
|
82
82
|
[tool.setuptools.package-data]
|
83
83
|
phasorpy = ["py.typed"]
|
@@ -151,7 +151,7 @@ minversion = "7"
|
|
151
151
|
log_cli_level = "INFO"
|
152
152
|
# filterwarnings = ["error"] # breaks debugging tests in VSCode (Sept. 2024)
|
153
153
|
xfail_strict = true
|
154
|
-
addopts = "-rfEXs --strict-config --strict-markers --doctest-modules --doctest-glob=*.py --doctest-glob=*.rst
|
154
|
+
addopts = "-rfEXs --strict-config --strict-markers --doctest-modules --doctest-glob=*.py --doctest-glob=*.rst"
|
155
155
|
doctest_optionflags = [
|
156
156
|
"NORMALIZE_WHITESPACE",
|
157
157
|
"ELLIPSIS",
|
@@ -50,6 +50,12 @@ ctypedef fused uint_t:
|
|
50
50
|
uint32_t
|
51
51
|
uint64_t
|
52
52
|
|
53
|
+
ctypedef fused int_t:
|
54
|
+
int8_t
|
55
|
+
int16_t
|
56
|
+
int32_t
|
57
|
+
int64_t
|
58
|
+
|
53
59
|
ctypedef fused signal_t:
|
54
60
|
uint8_t
|
55
61
|
uint16_t
|
@@ -767,6 +773,33 @@ cdef (float_t, float_t) _phasor_from_apparent_lifetime(
|
|
767
773
|
return <float_t> (mod * cos(phi)), <float_t> (mod * sin(phi))
|
768
774
|
|
769
775
|
|
776
|
+
@cython.ufunc
|
777
|
+
cdef float_t _phasor_to_normal_lifetime(
|
778
|
+
float_t real,
|
779
|
+
float_t imag,
|
780
|
+
float_t omega,
|
781
|
+
) noexcept nogil:
|
782
|
+
"""Return normal lifetimes from phasor coordinates."""
|
783
|
+
cdef:
|
784
|
+
double taunorm = INFINITY
|
785
|
+
double t
|
786
|
+
|
787
|
+
if isnan(real) or isnan(imag):
|
788
|
+
return <float_t> NAN
|
789
|
+
|
790
|
+
omega *= omega
|
791
|
+
if omega > 0.0:
|
792
|
+
t = 0.5 * (1.0 + cos(atan2(imag, real - 0.5)))
|
793
|
+
if t <= 0.0:
|
794
|
+
taunorm = INFINITY
|
795
|
+
elif t > 1.0:
|
796
|
+
taunorm = NAN
|
797
|
+
else:
|
798
|
+
taunorm = sqrt((1.0 - t) / (omega * t))
|
799
|
+
|
800
|
+
return <float_t> taunorm
|
801
|
+
|
802
|
+
|
770
803
|
@cython.ufunc
|
771
804
|
cdef (float_t, float_t) _phasor_from_single_lifetime(
|
772
805
|
float_t lifetime,
|
@@ -1204,6 +1237,44 @@ cdef unsigned char _is_inside_stadium(
|
|
1204
1237
|
_is_near_segment = _is_inside_stadium
|
1205
1238
|
|
1206
1239
|
|
1240
|
+
@cython.ufunc
|
1241
|
+
cdef unsigned char _is_inside_semicircle(
|
1242
|
+
float_t x, # point
|
1243
|
+
float_t y,
|
1244
|
+
float_t r, # distance
|
1245
|
+
) noexcept nogil:
|
1246
|
+
"""Return whether point is inside universal semicircle."""
|
1247
|
+
if r < 0.0 or isnan(x) or isnan(y):
|
1248
|
+
return False
|
1249
|
+
if y < -r:
|
1250
|
+
return False
|
1251
|
+
if y <= 0.0:
|
1252
|
+
if x >= 0.0 and x <= 1.0:
|
1253
|
+
return True
|
1254
|
+
# near endpoints?
|
1255
|
+
if x > 0.5:
|
1256
|
+
x -= <float_t> 1.0
|
1257
|
+
return x * x + y * y <= r * r
|
1258
|
+
return hypot(x - 0.5, y) <= r + 0.5
|
1259
|
+
|
1260
|
+
|
1261
|
+
@cython.ufunc
|
1262
|
+
cdef unsigned char _is_near_semicircle(
|
1263
|
+
float_t x, # point
|
1264
|
+
float_t y,
|
1265
|
+
float_t r, # distance
|
1266
|
+
) noexcept nogil:
|
1267
|
+
"""Return whether point is near universal semicircle."""
|
1268
|
+
if r < 0.0 or isnan(x) or isnan(y):
|
1269
|
+
return False
|
1270
|
+
if y < 0.0:
|
1271
|
+
# near endpoints?
|
1272
|
+
if x > 0.5:
|
1273
|
+
x -= <float_t> 1.0
|
1274
|
+
return x * x + y * y <= r * r
|
1275
|
+
return fabs(hypot(x - 0.5, y) - 0.5) <= r
|
1276
|
+
|
1277
|
+
|
1207
1278
|
@cython.ufunc
|
1208
1279
|
cdef unsigned char _is_near_line(
|
1209
1280
|
float_t x, # point
|
@@ -1470,6 +1541,22 @@ cdef float_t _distance_from_line(
|
|
1470
1541
|
return <float_t> hypot(x, y)
|
1471
1542
|
|
1472
1543
|
|
1544
|
+
@cython.ufunc
|
1545
|
+
cdef float_t _distance_from_semicircle(
|
1546
|
+
float_t x, # point
|
1547
|
+
float_t y,
|
1548
|
+
) noexcept nogil:
|
1549
|
+
"""Return distance from universal semicircle."""
|
1550
|
+
if isnan(x) or isnan(y):
|
1551
|
+
return NAN
|
1552
|
+
if y < 0.0:
|
1553
|
+
# distance to endpoints
|
1554
|
+
if x > 0.5:
|
1555
|
+
x -= <float_t> 1.0
|
1556
|
+
return <float_t> hypot(x, y)
|
1557
|
+
return <float_t> fabs(hypot(x - 0.5, y) - 0.5)
|
1558
|
+
|
1559
|
+
|
1473
1560
|
@cython.ufunc
|
1474
1561
|
cdef (float_t, float_t, float_t) _segment_direction_and_length(
|
1475
1562
|
float_t x0, # segment start
|
@@ -1495,7 +1582,7 @@ cdef (float_t, float_t, float_t) _segment_direction_and_length(
|
|
1495
1582
|
|
1496
1583
|
|
1497
1584
|
@cython.ufunc
|
1498
|
-
cdef (float_t, float_t, float_t, float_t)
|
1585
|
+
cdef (float_t, float_t, float_t, float_t) _intersect_circle_circle(
|
1499
1586
|
float_t x0, # circle 0
|
1500
1587
|
float_t y0,
|
1501
1588
|
float_t r0,
|
@@ -1541,7 +1628,7 @@ cdef (float_t, float_t, float_t, float_t) _intersection_circle_circle(
|
|
1541
1628
|
|
1542
1629
|
|
1543
1630
|
@cython.ufunc
|
1544
|
-
cdef (float_t, float_t, float_t, float_t)
|
1631
|
+
cdef (float_t, float_t, float_t, float_t) _intersect_circle_line(
|
1545
1632
|
float_t x, # circle
|
1546
1633
|
float_t y,
|
1547
1634
|
float_t r,
|
@@ -1583,10 +1670,106 @@ cdef (float_t, float_t, float_t, float_t) _intersection_circle_line(
|
|
1583
1670
|
)
|
1584
1671
|
|
1585
1672
|
|
1673
|
+
@cython.ufunc
|
1674
|
+
cdef (float_t, float_t, float_t, float_t) _intersect_semicircle_line(
|
1675
|
+
float_t x0, # line start
|
1676
|
+
float_t y0,
|
1677
|
+
float_t x1, # line end
|
1678
|
+
float_t y1,
|
1679
|
+
) noexcept nogil:
|
1680
|
+
"""Return coordinates of intersections of line and universal semicircle."""
|
1681
|
+
cdef:
|
1682
|
+
double dx, dy, dr, dd, rdd
|
1683
|
+
|
1684
|
+
if isnan(x0) or isnan(x1) or isnan(y0) or isnan(y1):
|
1685
|
+
return NAN, NAN, NAN, NAN
|
1686
|
+
|
1687
|
+
dx = x1 - x0
|
1688
|
+
dy = y1 - y0
|
1689
|
+
dr = dx * dx + dy * dy
|
1690
|
+
dd = (x0 - 0.5) * y1 - (x1 - 0.5) * y0
|
1691
|
+
rdd = 0.25 * dr - dd * dd # discriminant
|
1692
|
+
if rdd < 0.0 or dr <= 0.0:
|
1693
|
+
# no intersection
|
1694
|
+
return NAN, NAN, NAN, NAN
|
1695
|
+
rdd = sqrt(rdd)
|
1696
|
+
x0 = <float_t> ((dd * dy - copysign(1.0, dy) * dx * rdd) / dr + 0.5)
|
1697
|
+
y0 = <float_t> ((-dd * dx - fabs(dy) * rdd) / dr)
|
1698
|
+
x1 = <float_t> ((dd * dy + copysign(1.0, dy) * dx * rdd) / dr + 0.5)
|
1699
|
+
y1 = <float_t> ((-dd * dx + fabs(dy) * rdd) / dr)
|
1700
|
+
if y0 < 0.0:
|
1701
|
+
x0 = NAN
|
1702
|
+
y0 = NAN
|
1703
|
+
if y1 < 0.0:
|
1704
|
+
x1 = NAN
|
1705
|
+
y1 = NAN
|
1706
|
+
return x0, y0, x1, y1
|
1707
|
+
|
1708
|
+
|
1709
|
+
def _nearest_neighbor_2d(
|
1710
|
+
int_t[::1] indices,
|
1711
|
+
const float_t[::1] x0,
|
1712
|
+
const float_t[::1] y0,
|
1713
|
+
const float_t[::1] x1,
|
1714
|
+
const float_t[::1] y1,
|
1715
|
+
const float_t distance_max,
|
1716
|
+
const int num_threads
|
1717
|
+
):
|
1718
|
+
"""Find nearest neighbors in 2D.
|
1719
|
+
|
1720
|
+
For each point in the first set of arrays (x0, y0) find the nearest point
|
1721
|
+
in the second set of arrays (x1, y1) and store the index of the nearest
|
1722
|
+
point in the second array in the indices array.
|
1723
|
+
If any coordinates are NaN, or the distance to the nearest point
|
1724
|
+
is larger than distance_max, the index is set to -1.
|
1725
|
+
|
1726
|
+
"""
|
1727
|
+
cdef:
|
1728
|
+
ssize_t i, j, index
|
1729
|
+
float_t x, y, dmin
|
1730
|
+
float_t distance_max_squared = distance_max * distance_max
|
1731
|
+
|
1732
|
+
if (
|
1733
|
+
indices.shape[0] != x0.shape[0]
|
1734
|
+
or x0.shape[0] != y0.shape[0]
|
1735
|
+
or x1.shape[0] != y1.shape[0]
|
1736
|
+
):
|
1737
|
+
raise ValueError('input array size mismatch')
|
1738
|
+
|
1739
|
+
with nogil, parallel(num_threads=num_threads):
|
1740
|
+
for i in prange(x0.shape[0]):
|
1741
|
+
x = x0[i]
|
1742
|
+
y = y0[i]
|
1743
|
+
if isnan(x) or isnan(y):
|
1744
|
+
indices[i] = -1
|
1745
|
+
continue
|
1746
|
+
index = -1
|
1747
|
+
dmin = INFINITY
|
1748
|
+
for j in range(x1.shape[0]):
|
1749
|
+
x = x0[i] - x1[j]
|
1750
|
+
y = y0[i] - y1[j]
|
1751
|
+
x = x * x + y * y
|
1752
|
+
if x < dmin:
|
1753
|
+
dmin = x
|
1754
|
+
index = j
|
1755
|
+
indices[i] = -1 if dmin > distance_max_squared else <int_t> index
|
1756
|
+
|
1757
|
+
|
1586
1758
|
###############################################################################
|
1587
1759
|
# Blend ufuncs
|
1588
1760
|
|
1589
1761
|
|
1762
|
+
@cython.ufunc
|
1763
|
+
cdef float_t _blend_and(
|
1764
|
+
float_t a, # base layer
|
1765
|
+
float_t b, # blend layer
|
1766
|
+
) noexcept nogil:
|
1767
|
+
"""Return blended layers using `and` mode."""
|
1768
|
+
if isnan(a):
|
1769
|
+
return NAN
|
1770
|
+
return b
|
1771
|
+
|
1772
|
+
|
1590
1773
|
@cython.ufunc
|
1591
1774
|
cdef float_t _blend_normal(
|
1592
1775
|
float_t a, # base layer
|