phasorpy 0.3__cp313-cp313-win_arm64.whl → 0.4__cp313-cp313-win_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
phasorpy/phasor.py CHANGED
@@ -149,7 +149,7 @@ from ._phasorpy import (
149
149
  _polar_from_single_lifetime,
150
150
  _polar_to_apparent_lifetime,
151
151
  )
152
- from ._utils import parse_harmonic
152
+ from ._utils import parse_harmonic, parse_signal_axis
153
153
  from .utils import number_threads
154
154
 
155
155
 
@@ -157,7 +157,7 @@ def phasor_from_signal(
157
157
  signal: ArrayLike,
158
158
  /,
159
159
  *,
160
- axis: int = -1,
160
+ axis: int | str | None = None,
161
161
  harmonic: int | Sequence[int] | Literal['all'] | str | None = None,
162
162
  sample_phase: ArrayLike | None = None,
163
163
  use_fft: bool | None = None,
@@ -174,9 +174,10 @@ def phasor_from_signal(
174
174
  Frequency-domain, time-domain, or hyperspectral data.
175
175
  A minimum of three samples are required along `axis`.
176
176
  The samples must be uniformly spaced.
177
- axis : int, optional
177
+ axis : int or str, optional
178
178
  Axis over which to compute phasor coordinates.
179
- The default is the last axis (-1).
179
+ By default, the 'H' or 'C' axes if signal contains such dimension
180
+ names, else the last axis (-1).
180
181
  harmonic : int, sequence of int, or 'all', optional
181
182
  Harmonics to return.
182
183
  If `'all'`, return all harmonics for `signal` samples along `axis`.
@@ -287,6 +288,9 @@ def phasor_from_signal(
287
288
  """
288
289
  # TODO: C-order not required by rfft?
289
290
  # TODO: preserve array subtypes?
291
+
292
+ axis, _ = parse_signal_axis(signal, axis)
293
+
290
294
  signal = numpy.asarray(signal, order='C')
291
295
  if signal.dtype.kind not in 'uif':
292
296
  raise TypeError(f'signal must be real valued, not {signal.dtype=}')
@@ -1243,7 +1247,14 @@ def phasor_calibrate(
1243
1247
 
1244
1248
  has_harmonic_axis = reference_mean.ndim + 1 == reference_real.ndim
1245
1249
  harmonic, _ = parse_harmonic(
1246
- harmonic, reference_real.shape[0] if has_harmonic_axis else None
1250
+ harmonic,
1251
+ (
1252
+ reference_real.shape[0]
1253
+ if has_harmonic_axis
1254
+ and isinstance(harmonic, str)
1255
+ and harmonic == 'all'
1256
+ else None
1257
+ ),
1247
1258
  )
1248
1259
 
1249
1260
  if has_harmonic_axis:
@@ -1966,6 +1977,7 @@ def lifetime_fraction_from_amplitude(
1966
1977
  array([0.8, 0.2])
1967
1978
 
1968
1979
  """
1980
+ t: NDArray[numpy.float64]
1969
1981
  t = numpy.multiply(amplitude, lifetime, dtype=numpy.float64)
1970
1982
  t /= numpy.sum(t, axis=axis, keepdims=True)
1971
1983
  return t
phasorpy/plot.py CHANGED
@@ -43,6 +43,7 @@ from ._phasorpy import _intersection_circle_circle, _intersection_circle_line
43
43
  from ._utils import (
44
44
  dilate_coordinates,
45
45
  parse_kwargs,
46
+ parse_signal_axis,
46
47
  phasor_from_polar_scalar,
47
48
  phasor_to_polar_scalar,
48
49
  sort_coordinates,
@@ -217,7 +218,7 @@ class PhasorPlot:
217
218
  /,
218
219
  fmt: str = 'o',
219
220
  *,
220
- label: str | Sequence[str] | None = None,
221
+ label: Sequence[str] | None = None,
221
222
  **kwargs: Any,
222
223
  ) -> list[Line2D]:
223
224
  """Plot imag versus real coordinates as markers and/or lines.
@@ -232,7 +233,7 @@ class PhasorPlot:
232
233
  Must be of same shape as `real`.
233
234
  fmt : str, optional, default: 'o'
234
235
  Matplotlib style format string.
235
- label : str or sequence of str, optional
236
+ label : sequence of str, optional
236
237
  Plot label.
237
238
  May be a sequence if phasor coordinates are two dimensional arrays.
238
239
  **kwargs
@@ -1858,7 +1859,7 @@ def plot_signal_image(
1858
1859
  signal: ArrayLike,
1859
1860
  /,
1860
1861
  *,
1861
- axis: int | None = None,
1862
+ axis: int | str | None = None,
1862
1863
  percentile: float | Sequence[float] | None = None,
1863
1864
  title: str | None = None,
1864
1865
  show: bool = True,
@@ -1876,9 +1877,10 @@ def plot_signal_image(
1876
1877
  ----------
1877
1878
  signal : array_like
1878
1879
  Image stack. Must be three or more dimensional.
1879
- axis : int, optional, default: -1
1880
+ axis : int or str, optional
1880
1881
  Axis over which phasor coordinates would be computed.
1881
- The default is the last axis (-1).
1882
+ By default, the 'H' or 'C' axes if signal contains such dimension
1883
+ names, else the last axis (-1).
1882
1884
  percentile : float or [float, float], optional
1883
1885
  The [q, 100-q] percentiles of image data are covered by colormaps.
1884
1886
  By default, the complete value range of `mean` is covered,
@@ -1899,13 +1901,22 @@ def plot_signal_image(
1899
1901
  """
1900
1902
  # TODO: add option to separate channels?
1901
1903
  # TODO: add option to plot non-images?
1904
+
1905
+ axis, axis_label = parse_signal_axis(signal, axis)
1906
+ if (
1907
+ axis_label
1908
+ and hasattr(signal, 'coords')
1909
+ and axis_label in signal.coords
1910
+ ):
1911
+ axis_coords = signal.coords[axis_label]
1912
+ else:
1913
+ axis_coords = None
1914
+
1902
1915
  update_kwargs(kwargs, interpolation='nearest')
1903
1916
  signal = numpy.asarray(signal)
1904
1917
  if signal.ndim < 3:
1905
1918
  raise ValueError(f'not an image stack {signal.ndim=} < 3')
1906
1919
 
1907
- if axis is None:
1908
- axis = -1
1909
1920
  axis %= signal.ndim
1910
1921
 
1911
1922
  # for MyPy
@@ -1922,8 +1933,13 @@ def plot_signal_image(
1922
1933
  axes = list(range(signal.ndim))
1923
1934
  del axes[axis]
1924
1935
  ax = fig.add_subplot(gs[0, 1])
1925
- ax.set_title(f'mean, axis {axis}')
1926
- ax.plot(numpy.nanmean(signal, axis=tuple(axes)))
1936
+
1937
+ if axis_coords is not None:
1938
+ ax.set_title(f'{axis=} {axis_label!r}')
1939
+ ax.plot(axis_coords, numpy.nanmean(signal, axis=tuple(axes)))
1940
+ else:
1941
+ ax.set_title(f'{axis=}')
1942
+ ax.plot(numpy.nanmean(signal, axis=tuple(axes)))
1927
1943
 
1928
1944
  # image
1929
1945
  axes = list(sorted(axes[:-2] + [axis]))
phasorpy/version.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = '0.3'
5
+ __version__ = '0.4'
6
6
 
7
7
 
8
8
  def versions(
@@ -44,6 +44,7 @@ def versions(
44
44
  'lfdfiles',
45
45
  'sdtfile',
46
46
  'ptufile',
47
+ 'liffile',
47
48
  'matplotlib',
48
49
  'scipy',
49
50
  'skimage',
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022-2024 PhasorPy Contributors
3
+ Copyright (c) 2022-2025 PhasorPy Contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: phasorpy
3
- Version: 0.3
3
+ Version: 0.4
4
4
  Summary: Analysis of fluorescence lifetime and hyperspectral images using the phasor approach
5
5
  Author: PhasorPy Contributors
6
6
  License: MIT
@@ -52,6 +52,7 @@ Provides-Extra: all
52
52
  Requires-Dist: lfdfiles>=2024.5.24; extra == "all"
53
53
  Requires-Dist: sdtfile>=2024.5.24; extra == "all"
54
54
  Requires-Dist: ptufile>=2024.9.14; extra == "all"
55
+ Requires-Dist: liffile>=2025.1.30; extra == "all"
55
56
 
56
57
  # PhasorPy
57
58
 
@@ -61,7 +62,7 @@ lifetime and hyperspectral images using the phasor approach.
61
62
  - [Homepage](https://www.phasorpy.org)
62
63
  - [Documentation](https://www.phasorpy.org/docs/stable/)
63
64
  - [Source code](https://github.com/phasorpy/phasorpy)
64
- - [Download releases](https://pypi.org/project/phasorpy/#files)
65
+ - [Install with pip](https://pypi.org/project/phasorpy/) or [conda](https://anaconda.org/conda-forge/phasorpy).
65
66
  - [Data files](https://zenodo.org/communities/phasorpy/)
66
67
  - [Issues and questions](https://github.com/phasorpy/phasorpy/issues)
67
68
 
@@ -0,0 +1,25 @@
1
+ phasorpy/__init__.py,sha256=SwOTreV7wd8ZEL3waXQlgbNnsErWJ0dh6A2d77DWp0Y,254
2
+ phasorpy/__main__.py,sha256=0u6C98HYfajV1RoUww8kAc0CxdsON0ijgEyTYExCSLM,149
3
+ phasorpy/_io.py,sha256=m_GbMezQSOpaDSq_ZY3OtanDKnK7o7HIQUPjcfw5C3c,79239
4
+ phasorpy/_phasorpy.cp313-win_arm64.pyd,sha256=1Y-AuUrl5ghQM_JnQ5p_tFC6drwR4nJL8P2wjgYu93o,783872
5
+ phasorpy/_phasorpy.pyx,sha256=ukl9_qjzWy-YqnCSZj9ErMohxIObh1JG7U7U25sL-jE,63909
6
+ phasorpy/_typing.py,sha256=ii-5-8KTs2BZq0Ytu3yJl8ejSQj1V06c1_Jcwa_2Snk,1324
7
+ phasorpy/_utils.py,sha256=33KkcMssK9xnQRQMWQ5L9do4I5093FdpNrgLdRmUc7I,15128
8
+ phasorpy/cli.py,sha256=orN_31JOTzIUEfySwTo_Kr24UUzPKdA-DkemsmM8IHk,1977
9
+ phasorpy/color.py,sha256=vb0Vet_BSMz1El3aQeQWpXm-hRcARnx0qRdOUK3OkvI,17264
10
+ phasorpy/components.py,sha256=0ZuUaJllf4c2UFbiTOse5PYXkMLNF8q5VSUxvSgPjy8,10415
11
+ phasorpy/conftest.py,sha256=BywY24LnrOhaTHZIYkVAQ09JmvKZXevNKoshdLeL9nA,949
12
+ phasorpy/cursors.py,sha256=sUZ-9PJ5faJLWewRuENhF7nRJ-drPtW8Ui8YWD6UOw4,15546
13
+ phasorpy/datasets.py,sha256=PZqzvwWw18I8yYzDSG7ehRzXYoxbm9zedYscyaALzUI,18679
14
+ phasorpy/io.py,sha256=LbvRCZrn8A4ttUthTb7OYbKmYGl2c4uiGCX98ZOz494,164
15
+ phasorpy/phasor.py,sha256=FN-98HU3kMaAfHTSos2X462qn0q6GTLQWf2jNILArdU,113485
16
+ phasorpy/plot.py,sha256=M3amG2LeC5cqFyW7er-7Lqi5ZeVpnMLQXqo6fqNICr0,70431
17
+ phasorpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ phasorpy/utils.py,sha256=an_dOCZM9WCNUxI3GFuxdjrF8BRVQIc0OnQStgiXF7A,11675
19
+ phasorpy/version.py,sha256=NjmVRZIUgPJtVP7pRSDzkQUzunBbApGY1YefTbIuDzs,1820
20
+ phasorpy-0.4.dist-info/LICENSE.txt,sha256=KVzeDa0MBRSUYPFFNuo7Atn6v62TiJTgGzHigltEX0o,1104
21
+ phasorpy-0.4.dist-info/METADATA,sha256=_DzagbItN_FIcE0rahtlAp1IXIx1TyCCd5WoH5eJdf0,3563
22
+ phasorpy-0.4.dist-info/WHEEL,sha256=8fM9UDBVBwZGW1kTy_FyUxqZHRhRuIJmTQgtV8rHzvE,101
23
+ phasorpy-0.4.dist-info/entry_points.txt,sha256=VRhsl3qGiIKwtMraKapmduchTMbdReUi1AoVTe9f3ss,47
24
+ phasorpy-0.4.dist-info/top_level.txt,sha256=4Y0uYzya5R2loleAxZ6s2n53_FysUbgFTfFaU0i9rbo,9
25
+ phasorpy-0.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp313-cp313-win_arm64
5
5
 
@@ -1,24 +0,0 @@
1
- phasorpy/__init__.py,sha256=SwOTreV7wd8ZEL3waXQlgbNnsErWJ0dh6A2d77DWp0Y,254
2
- phasorpy/__main__.py,sha256=0u6C98HYfajV1RoUww8kAc0CxdsON0ijgEyTYExCSLM,149
3
- phasorpy/_phasorpy.cp313-win_arm64.pyd,sha256=w297BQVRtG8eMr5Oc6X-H1OH9p5P3OsLD3gxO1qcRto,720896
4
- phasorpy/_phasorpy.pyx,sha256=1jHkJGcsdzCSLMGdpmvjFuSbg1A4w0XBa4Jy4udXzm4,62066
5
- phasorpy/_typing.py,sha256=ii-5-8KTs2BZq0Ytu3yJl8ejSQj1V06c1_Jcwa_2Snk,1324
6
- phasorpy/_utils.py,sha256=0c3d8D69wG7mTUzc-qh4GDff64FXJK9vFzRrZ0-XOqw,13255
7
- phasorpy/cli.py,sha256=orN_31JOTzIUEfySwTo_Kr24UUzPKdA-DkemsmM8IHk,1977
8
- phasorpy/color.py,sha256=axzL2b0d_g_6pG1wgHSdbiNtn7wAooYl3t-zaUNOBTE,17313
9
- phasorpy/components.py,sha256=0ZuUaJllf4c2UFbiTOse5PYXkMLNF8q5VSUxvSgPjy8,10415
10
- phasorpy/conftest.py,sha256=BywY24LnrOhaTHZIYkVAQ09JmvKZXevNKoshdLeL9nA,949
11
- phasorpy/cursors.py,sha256=sUZ-9PJ5faJLWewRuENhF7nRJ-drPtW8Ui8YWD6UOw4,15546
12
- phasorpy/datasets.py,sha256=AvZcR9hVgW5m7blKt51tFPC7zd1HBJ46GjfCeBb2r9E,15523
13
- phasorpy/io.py,sha256=8kes4ebfbiu1bpNOA7cfbuZhCX39sMyRn86vnRh00i0,58340
14
- phasorpy/phasor.py,sha256=zYCbg_KPw_JXRbrOjhinp9iUt51wE7M15DEovN9Z_RE,113150
15
- phasorpy/plot.py,sha256=mkNcXN7caXHPBiBJazo5mEZawUitnGny8xbFsHS3u9c,69959
16
- phasorpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- phasorpy/utils.py,sha256=an_dOCZM9WCNUxI3GFuxdjrF8BRVQIc0OnQStgiXF7A,11675
18
- phasorpy/version.py,sha256=LDRHtMREhlYztKP-wHgHhtANbGj-bBz7rnICDjQ9Trw,1800
19
- phasorpy-0.3.dist-info/LICENSE.txt,sha256=bxzmxrql9vHNenjAb0m7dSkLbEQJW9zJi2E0WjkAI68,1104
20
- phasorpy-0.3.dist-info/METADATA,sha256=OwEDIpNLNxk2BM1IQnfkQihI3CGlgZF7uv_XnFpo7Pg,3464
21
- phasorpy-0.3.dist-info/WHEEL,sha256=bV70lsaGY9jfXNj9t8tkxF-9TzLZ40j0DQYQVgq_KDk,101
22
- phasorpy-0.3.dist-info/entry_points.txt,sha256=VRhsl3qGiIKwtMraKapmduchTMbdReUi1AoVTe9f3ss,47
23
- phasorpy-0.3.dist-info/top_level.txt,sha256=4Y0uYzya5R2loleAxZ6s2n53_FysUbgFTfFaU0i9rbo,9
24
- phasorpy-0.3.dist-info/RECORD,,