phasorpy 0.6__cp311-cp311-win_arm64.whl → 0.7__cp311-cp311-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/cluster.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The `phasorpy.cluster` module provides functions to:
4
4
 
5
- - fit elliptic clusters to phasor coordinates using
5
+ - fit elliptic clusters to phasor coordinates using a
6
6
  Gaussian Mixture Model (GMM):
7
7
 
8
8
  - :py:func:`phasor_cluster_gmm`
@@ -21,7 +21,6 @@ if TYPE_CHECKING:
21
21
  import math
22
22
 
23
23
  import numpy
24
- from sklearn.mixture import GaussianMixture
25
24
 
26
25
 
27
26
  def phasor_cluster_gmm(
@@ -52,14 +51,14 @@ def phasor_cluster_gmm(
52
51
  Real component of phasor coordinates.
53
52
  imag : array_like
54
53
  Imaginary component of phasor coordinates.
55
- sigma: float, default = 2.0
54
+ sigma : float, optional
56
55
  Scaling factor for radii of major and minor axes.
57
- Defaults to 2, which corresponds to the scaling of eigenvalues for a
58
- 95% confidence ellipse.
56
+ Defaults to 2.0, which corresponds to the scaling of eigenvalues for
57
+ a 95% confidence ellipse.
59
58
  clusters : int, optional
60
59
  Number of Gaussian distributions to fit to phasor coordinates.
61
60
  Defaults to 1.
62
- sort: {'polar', 'phasor', 'area'}, optional
61
+ sort : {'polar', 'phasor', 'area'}, optional
63
62
  Sorting method for output clusters. Defaults to 'polar'.
64
63
 
65
64
  - 'polar': Sort by polar coordinates (phase, then modulation).
@@ -89,19 +88,12 @@ def phasor_cluster_gmm(
89
88
  angle : tuple of float
90
89
  Rotation angles of major axes in radians, within range [0, pi].
91
90
 
92
- Raises
93
- ------
94
- ValueError
95
- If the array shapes of `real` and `imag` do not match.
96
- If `clusters` is not a positive integer.
97
-
98
-
99
91
  References
100
92
  ----------
101
93
  .. [1] Vallmitjana A, Torrado B, and Gratton E.
102
94
  `Phasor-based image segmentation: machine learning clustering techniques
103
95
  <https://doi.org/10.1364/BOE.422766>`_.
104
- *Biomed Opt Express*, 12(6): 3410-3422 (2021).
96
+ *Biomed Opt Express*, 12(6): 3410-3422 (2021)
105
97
 
106
98
  Examples
107
99
  --------
@@ -119,11 +111,13 @@ def phasor_cluster_gmm(
119
111
  >>> center_real, center_imag, radius_major, radius_minor, angle = (
120
112
  ... phasor_cluster_gmm(real, imag, clusters=2)
121
113
  ... )
122
- >>> centers_real # doctest: +SKIP
114
+ >>> center_real # doctest: +SKIP
123
115
  (0.2, 0.4)
124
116
 
125
117
  """
126
- coords = numpy.stack((real, imag), axis=-1).reshape(-1, 2)
118
+ from sklearn.mixture import GaussianMixture
119
+
120
+ coords = numpy.stack([real, imag], axis=-1).reshape(-1, 2)
127
121
 
128
122
  valid_data = ~numpy.isnan(coords).any(axis=1)
129
123
  coords = coords[valid_data]
phasorpy/color.py CHANGED
@@ -1,4 +1,4 @@
1
- """Color palettes and manipulation."""
1
+ """Color palettes and color manipulation utilities."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -19,20 +19,22 @@ def wavelength2rgb(
19
19
  ) -> tuple[float, float, float] | NDArray[Any]:
20
20
  """Return approximate sRGB color components of visible wavelength(s).
21
21
 
22
- Wavelengths are clipped to range [360, 750] nm, rounded, and used to
22
+ Wavelengths are clipped to the range [360, 750] nm, rounded, and used to
23
23
  index the :py:attr:`SRGB_SPECTRUM` palette.
24
24
 
25
25
  Parameters
26
26
  ----------
27
27
  wavelength : array_like
28
28
  Scalar or array of wavelengths in nm.
29
- dtype : data-type, optional
29
+ dtype : dtype_like, optional
30
30
  Data-type of return value. The default is ``float32``.
31
31
 
32
32
  Returns
33
33
  -------
34
- ndarray or tuple
35
- Approximate sRGB color components of visible wavelength.
34
+ ndarray or tuple of float
35
+ Approximate sRGB color components of visible wavelength(s).
36
+ If input is scalar, return tuple of three floats.
37
+ If input is array, return ndarray with shape (..., 3).
36
38
  Floating-point values are in range [0.0, 1.0].
37
39
  Integer values are scaled to the dtype's maximum value.
38
40
 
@@ -74,7 +76,7 @@ def float2int(
74
76
  ----------
75
77
  rgb : array_like
76
78
  Scalar or array of normalized floating-point color components.
77
- dtype : data-type, optional
79
+ dtype : dtype_like, optional
78
80
  Data type of return value. The default is ``uint8``.
79
81
 
80
82
  Returns
@@ -169,7 +171,7 @@ CATEGORICAL: NDArray[numpy.float32] = numpy.array([
169
171
  ], dtype=numpy.float32)
170
172
  """Categorical sRGB color palette inspired by C. Glasbey.
171
173
 
172
- Contains 64 maximally distinct colours for visualization.
174
+ Contains 64 maximally distinct colors for visualization.
173
175
 
174
176
  Generated using the `glasbey <https://glasbey.readthedocs.io>`_ package::
175
177
 
@@ -575,6 +577,8 @@ SRGB_SPECTRUM: NDArray[numpy.float32] = numpy.array([
575
577
  ], dtype=numpy.float32)
576
578
  """sRGB color components for wavelengths of visible light (360-750 nm).
577
579
 
580
+ Array of shape (391, 3) containing normalized sRGB color components
581
+ for wavelengths from 360 to 750 nm in 1 nm increments.
578
582
  Based on the CIE 1931 2° Standard Observer.
579
583
 
580
584
  Generated using the `colour <https://colour.readthedocs.io>`_ package::
@@ -1,6 +1,6 @@
1
1
  """Component analysis of phasor coordinates.
2
2
 
3
- The ``phasorpy.components`` module provides functions to:
3
+ The ``phasorpy.component`` module provides functions to:
4
4
 
5
5
  - calculate fractions of two known components by projecting onto the
6
6
  line between the components (:py:func:`phasor_component_fraction`)
@@ -14,9 +14,15 @@ The ``phasorpy.components`` module provides functions to:
14
14
  - calculate fractions of two or three known components by resolving
15
15
  graphically with histogram (:py:func:`phasor_component_graphical`)
16
16
 
17
+ - calculate mean value coordinates of phasor coordinates with respect
18
+ to three or more components (:py:func:`phasor_component_mvc`)
19
+
17
20
  - blindly resolve fractions of multiple components by using harmonic
18
21
  information (:py:func:`phasor_component_blind`, not implemented)
19
22
 
23
+ - calculate phasor coordinates from fractional intensities of
24
+ components (:py:func:`phasor_from_component`)
25
+
20
26
  """
21
27
 
22
28
  from __future__ import annotations
@@ -26,13 +32,15 @@ __all__ = [
26
32
  'phasor_component_fit',
27
33
  'phasor_component_fraction',
28
34
  'phasor_component_graphical',
35
+ 'phasor_component_mvc',
36
+ 'phasor_from_component',
29
37
  ]
30
38
 
31
39
  import numbers
32
40
  from typing import TYPE_CHECKING
33
41
 
34
42
  if TYPE_CHECKING:
35
- from ._typing import Any, ArrayLike, NDArray
43
+ from ._typing import Any, ArrayLike, DTypeLike, NDArray
36
44
 
37
45
  import numpy
38
46
 
@@ -41,9 +49,88 @@ from ._phasorpy import (
41
49
  _fraction_on_segment,
42
50
  _is_inside_circle,
43
51
  _is_inside_stadium,
52
+ _mean_value_coordinates,
44
53
  _segment_direction_and_length,
45
54
  )
55
+ from ._utils import sort_coordinates
46
56
  from .phasor import phasor_threshold
57
+ from .utils import number_threads
58
+
59
+
60
+ def phasor_from_component(
61
+ component_real: ArrayLike,
62
+ component_imag: ArrayLike,
63
+ fraction: ArrayLike,
64
+ /,
65
+ axis: int = 0,
66
+ dtype: DTypeLike | None = None,
67
+ ) -> tuple[NDArray[Any], NDArray[Any]]:
68
+ """Return phasor coordinates from fractional intensities of components.
69
+
70
+ Return the dot products of the fractional intensities of components
71
+ with the real and imaginary phasor coordinates of the components.
72
+
73
+ Multi-dimensional component arrays are currently not supported.
74
+
75
+ Parameters
76
+ ----------
77
+ component_real : array_like, shape (n,)
78
+ Real coordinates of components.
79
+ At least two components are required.
80
+ component_imag : array_like, shape (n,)
81
+ Imaginary coordinates of components.
82
+ fraction : array_like
83
+ Fractional intensities of components.
84
+ Fractions are normalized to sum to one along `axis`.
85
+ axis : int, optional, default: 0
86
+ Axis of components in `fraction`.
87
+ dtype : dtype_like, optional
88
+ Floating point data type used for calculation and output values.
89
+ Either `float32` or `float64`. The default is `float64`.
90
+
91
+ Returns
92
+ -------
93
+ real : ndarray
94
+ Real component of phasor coordinates.
95
+ imag : ndarray
96
+ Imaginary component of phasor coordinates.
97
+
98
+ Examples
99
+ --------
100
+ Calculate phasor coordinates from two components and their fractional
101
+ intensities:
102
+
103
+ >>> phasor_from_component(
104
+ ... [0.6, 0.4], [0.3, 0.2], [[1.0, 0.2, 0.9], [0.0, 0.8, 0.1]]
105
+ ... )
106
+ (array([0.6, 0.44, 0.58]), array([0.3, 0.22, 0.29]))
107
+
108
+ """
109
+ dtype = numpy.dtype(dtype)
110
+ if dtype.char not in {'f', 'd'}:
111
+ raise ValueError(f'{dtype=} is not a floating point type')
112
+
113
+ fraction = numpy.array(fraction, dtype=dtype, copy=True)
114
+ if fraction.ndim < 1:
115
+ raise ValueError(f'{fraction.ndim=} < 1')
116
+ if fraction.shape[axis] < 2:
117
+ raise ValueError(f'{fraction.shape[axis]=} < 2')
118
+ with numpy.errstate(divide='ignore', invalid='ignore'):
119
+ fraction /= fraction.sum(axis=axis, keepdims=True)
120
+
121
+ component_real = numpy.asarray(component_real, dtype=dtype)
122
+ component_imag = numpy.asarray(component_imag, dtype=dtype)
123
+ if component_real.shape != component_imag.shape:
124
+ raise ValueError(f'{component_real.shape=} != {component_imag.shape=}')
125
+ if component_real.ndim != 1:
126
+ raise ValueError(f'{component_real.ndim=} != 1')
127
+ if component_real.size != fraction.shape[axis]:
128
+ raise ValueError(f'{component_real.size=} != {fraction.shape[axis]=}')
129
+
130
+ fraction = numpy.moveaxis(fraction, axis, -1)
131
+ real = numpy.dot(fraction, component_real)
132
+ imag = numpy.dot(fraction, component_imag)
133
+ return real, imag
47
134
 
48
135
 
49
136
  def phasor_component_fraction(
@@ -83,7 +170,7 @@ def phasor_component_fraction(
83
170
 
84
171
  See Also
85
172
  --------
86
- :ref:`sphx_glr_tutorials_api_phasorpy_components.py`
173
+ :ref:`sphx_glr_tutorials_api_phasorpy_component.py`
87
174
 
88
175
  Notes
89
176
  -----
@@ -97,7 +184,7 @@ def phasor_component_fraction(
97
184
  --------
98
185
  >>> phasor_component_fraction(
99
186
  ... [0.6, 0.5, 0.4], [0.4, 0.3, 0.2], [0.2, 0.9], [0.4, 0.3]
100
- ... ) # doctest: +NUMBER
187
+ ... )
101
188
  array([0.44, 0.56, 0.68])
102
189
 
103
190
  """
@@ -132,7 +219,7 @@ def phasor_component_graphical(
132
219
  *,
133
220
  radius: float = 0.05,
134
221
  fractions: ArrayLike | None = None,
135
- ) -> tuple[NDArray[Any], ...]:
222
+ ) -> NDArray[Any]:
136
223
  r"""Return fractions of two or three components from phasor coordinates.
137
224
 
138
225
  The graphical method is based on moving circular cursors along the line
@@ -162,9 +249,11 @@ def phasor_component_graphical(
162
249
 
163
250
  Returns
164
251
  -------
165
- counts : tuple of ndarray
252
+ counts : ndarray
166
253
  Counts along each line segment connecting components.
167
254
  Ordered 0-1 (2 components) or 0-1, 0-2, 1-2 (3 components).
255
+ Shaped `(number fractions,)` (2 components) or
256
+ `(3, number fractions)` (3 components).
168
257
 
169
258
  Raises
170
259
  ------
@@ -176,7 +265,7 @@ def phasor_component_graphical(
176
265
 
177
266
  See Also
178
267
  --------
179
- :ref:`sphx_glr_tutorials_api_phasorpy_components.py`
268
+ :ref:`sphx_glr_tutorials_api_phasorpy_component.py`
180
269
 
181
270
  Notes
182
271
  -----
@@ -202,7 +291,6 @@ def phasor_component_graphical(
202
291
 
203
292
  References
204
293
  ----------
205
-
206
294
  .. [1] Ranjit S, Datta R, Dvornikov A, and Gratton E.
207
295
  `Multicomponent analysis of phasor plot in a single pixel to
208
296
  calculate changes of metabolic trajectory in biological systems
@@ -215,8 +303,8 @@ def phasor_component_graphical(
215
303
 
216
304
  >>> phasor_component_graphical(
217
305
  ... [0.6, 0.3], [0.35, 0.38], [0.2, 0.9], [0.4, 0.3], fractions=6
218
- ... ) # doctest: +NUMBER
219
- (array([0, 0, 1, 0, 1, 0], dtype=uint64),)
306
+ ... )
307
+ array([0, 0, 1, 0, 1, 0], dtype=uint8)
220
308
 
221
309
  Count the number of phasors between the combinations of three components:
222
310
 
@@ -226,10 +314,10 @@ def phasor_component_graphical(
226
314
  ... [0.0, 0.2, 0.9],
227
315
  ... [0.0, 0.4, 0.3],
228
316
  ... fractions=6,
229
- ... ) # doctest: +NUMBER +NORMALIZE_WHITESPACE
230
- (array([0, 1, 1, 1, 1, 0], dtype=uint64),
231
- array([0, 1, 0, 0, 0, 0], dtype=uint64),
232
- array([0, 1, 2, 0, 0, 0], dtype=uint64))
317
+ ... )
318
+ array([[0, 1, 1, 1, 1, 0],
319
+ [0, 1, 0, 0, 0, 0],
320
+ [0, 1, 2, 0, 0, 0]], dtype=uint8)
233
321
 
234
322
  """
235
323
  real = numpy.asarray(real)
@@ -272,7 +360,12 @@ def phasor_component_graphical(
272
360
  if fractions.ndim != 1:
273
361
  raise ValueError('fractions is not a one-dimensional array')
274
362
 
275
- counts = []
363
+ dtype = numpy.min_scalar_type(real.size)
364
+ counts = numpy.empty(
365
+ (1 if num_components == 2 else 3, fractions.size), dtype
366
+ )
367
+
368
+ c = 0
276
369
  for i in range(num_components):
277
370
  a_real = component_real[i]
278
371
  a_imag = component_imag[i]
@@ -282,8 +375,7 @@ def phasor_component_graphical(
282
375
  ab_real = a_real - b_real
283
376
  ab_imag = a_imag - b_imag
284
377
 
285
- component_counts = []
286
- for f in fractions:
378
+ for k, f in enumerate(fractions):
287
379
  if f < 0.0 or f > 1.0:
288
380
  raise ValueError(f'fraction {f} out of bounds [0.0, 1.0]')
289
381
  if num_components == 2:
@@ -305,12 +397,10 @@ def phasor_component_graphical(
305
397
  component_imag[3 - i - j], # c_imag
306
398
  radius,
307
399
  )
308
- fraction_counts = numpy.sum(mask, dtype=numpy.uint64)
309
- component_counts.append(fraction_counts)
400
+ counts[c, k] = numpy.sum(mask, dtype=dtype)
401
+ c += 1
310
402
 
311
- counts.append(numpy.asarray(component_counts))
312
-
313
- return tuple(counts)
403
+ return counts[0] if num_components == 2 else counts
314
404
 
315
405
 
316
406
  def phasor_component_fit(
@@ -321,7 +411,7 @@ def phasor_component_fit(
321
411
  component_imag: ArrayLike,
322
412
  /,
323
413
  **kwargs: Any,
324
- ) -> tuple[NDArray[Any], ...]:
414
+ ) -> NDArray[Any]:
325
415
  """Return fractions of multiple components from phasor coordinates.
326
416
 
327
417
  Component fractions are obtained from the least-squares solution of a
@@ -353,8 +443,8 @@ def phasor_component_fit(
353
443
 
354
444
  Returns
355
445
  -------
356
- fractions : tuple of ndarray
357
- Component fractions, one array per component.
446
+ fractions : ndarray
447
+ Component fractions.
358
448
  Fractions may not exactly add up to 1.0.
359
449
 
360
450
  Raises
@@ -369,7 +459,7 @@ def phasor_component_fit(
369
459
 
370
460
  See Also
371
461
  --------
372
- :ref:`sphx_glr_tutorials_api_phasorpy_components.py`
462
+ :ref:`sphx_glr_tutorials_api_phasorpy_component.py`
373
463
  :ref:`sphx_glr_tutorials_applications_phasorpy_component_fit.py`
374
464
 
375
465
  Notes
@@ -392,12 +482,13 @@ def phasor_component_fit(
392
482
  imaging <https://doi.org/10.1088/2050-6120/ac9ae9>`_.
393
483
  *Methods Appl Fluoresc*, 11(1): 014001 (2022)
394
484
 
395
- Example
396
- -------
485
+ Examples
486
+ --------
397
487
  >>> phasor_component_fit(
398
488
  ... [1, 1, 1], [0.6, 0.5, 0.4], [0.4, 0.3, 0.2], [0.2, 0.9], [0.4, 0.3]
399
- ... ) # doctest: +NUMBER
400
- (array([0.4644, 0.5356, 0.6068]), array([0.5559, 0.4441, 0.3322]))
489
+ ... )
490
+ array([[0.4644, 0.5356, 0.6068],
491
+ [0.5559, 0.4441, 0.3322]])
401
492
 
402
493
  """
403
494
  from scipy.linalg import lstsq
@@ -464,7 +555,9 @@ def phasor_component_fit(
464
555
  # [real coordinates (for each harmonic)] +
465
556
  # [imaginary coordinates (for each harmonic)] +
466
557
  # [ones for intensity constraint]
467
- coords = numpy.ones((2 * num_harmonics + 1,) + real.shape[1:])
558
+ coords = numpy.ones(
559
+ (2 * num_harmonics + 1,) + real.shape[1:] # type: ignore[union-attr]
560
+ )
468
561
  coords[:num_harmonics] = real
469
562
  coords[num_harmonics : 2 * num_harmonics] = imag
470
563
 
@@ -481,4 +574,134 @@ def phasor_component_fit(
481
574
  # restore NaN values in fractions from mean
482
575
  _blend_and(mean, fractions, out=fractions)
483
576
 
484
- return tuple(fractions)
577
+ return numpy.asarray(fractions)
578
+
579
+
580
+ def phasor_component_mvc(
581
+ real: ArrayLike,
582
+ imag: ArrayLike,
583
+ component_real: ArrayLike,
584
+ component_imag: ArrayLike,
585
+ /,
586
+ *,
587
+ dtype: DTypeLike = None,
588
+ num_threads: int | None = None,
589
+ ) -> NDArray[Any]:
590
+ """Return mean value coordinates of phasor coordinates from components.
591
+
592
+ The mean value coordinates of phasor coordinates with respect to three or
593
+ more components spanning an arbitrary simple polygon are computed using
594
+ the stable method described in [3]_.
595
+ For three components, mean value coordinates are equivalent to
596
+ barycentric coordinates.
597
+
598
+ Parameters
599
+ ----------
600
+ real : array_like
601
+ Real component of phasor coordinates.
602
+ imag : array_like
603
+ Imaginary component of phasor coordinates.
604
+ component_real : array_like
605
+ Real coordinates of at least three components.
606
+ component_imag : array_like
607
+ Imaginary coordinates of at least three components.
608
+ dtype : dtype_like, optional
609
+ Floating point data type used for calculation and output values.
610
+ Either `float32` or `float64`. The default is `float64`.
611
+ num_threads : int, optional
612
+ Number of OpenMP threads to use for parallelization.
613
+ By default, multi-threading is disabled.
614
+ If zero, up to half of logical CPUs are used.
615
+ OpenMP may not be available on all platforms.
616
+
617
+ Returns
618
+ -------
619
+ fractions : ndarray
620
+ Mean value coordinates for each phasor coordinate.
621
+
622
+ Raises
623
+ ------
624
+ ValueError
625
+ The array shapes of `real` and `imag` do not match.
626
+ The array shapes of `component_real` and `component_imag` do not match.
627
+
628
+ Notes
629
+ -----
630
+ Calculation of mean value coordinates for different channels,
631
+ frequencies, or harmonics is not supported. Only one set of components
632
+ can be analyzed and is broadcast to all channels/frequencies/harmonics.
633
+
634
+ For three components, this function returns the same result as
635
+ :py:func:`phasor_component_fit`. For more than three components,
636
+ the system is underdetermined and the mean value coordinates represent
637
+ one of multiple solutions. However, the special properties of the mean
638
+ value coordinates make them particularly useful for interpolating and
639
+ visualizing multi-component data.
640
+
641
+ References
642
+ ----------
643
+ .. [3] Fuda C and Hormann K.
644
+ `A new stable method to compute mean value coordinates
645
+ <https://doi.org/10.1016/j.cagd.2024.102310>`_.
646
+ *Computer Aided Geometric Design*, 111: 102310 (2024)
647
+
648
+ Examples
649
+ --------
650
+ Calculate the barycentric coordinates of a phasor coordinate
651
+ in a triangle defined by three components:
652
+
653
+ >>> phasor_component_mvc(0.6, 0.3, [0.0, 1.0, 0.0], [1.0, 0.0, 0.0])
654
+ array([0.3, 0.6, 0.1])
655
+
656
+ The barycentric coordinates of phasor coordinates outside the polygon
657
+ defined by the components may be outside the range [0.0, 1.0]:
658
+
659
+ >>> phasor_component_mvc(0.6, 0.6, [0.0, 1.0, 0.0], [1.0, 0.0, 0.0])
660
+ array([0.6, 0.6, -0.2])
661
+
662
+ """
663
+ num_threads = number_threads(num_threads)
664
+
665
+ dtype = numpy.dtype(dtype)
666
+ if dtype.char not in {'f', 'd'}:
667
+ raise ValueError(f'{dtype=} is not a floating point type')
668
+
669
+ real = numpy.ascontiguousarray(real, dtype=dtype)
670
+ imag = numpy.ascontiguousarray(imag, dtype=dtype)
671
+ component_real = numpy.ascontiguousarray(component_real, dtype=dtype)
672
+ component_imag = numpy.ascontiguousarray(component_imag, dtype=dtype)
673
+
674
+ if real.shape != imag.shape:
675
+ raise ValueError(f'{real.shape=} != {imag.shape=}')
676
+ if component_real.shape != component_imag.shape:
677
+ raise ValueError(f'{component_real.shape=} != {component_imag.shape=}')
678
+ if component_real.ndim != 1 or component_real.size < 3:
679
+ raise ValueError('number of components must be three or more')
680
+ if numpy.isnan(component_real).any() or numpy.isnan(component_imag).any():
681
+ raise ValueError('component coordinates must not contain NaN values')
682
+ if numpy.isinf(component_real).any() or numpy.isinf(component_imag).any():
683
+ raise ValueError(
684
+ 'component coordinates must not contain infinite values'
685
+ )
686
+
687
+ # TODO:: sorting not strictly required for three components?
688
+ component_real, component_imag, indices = sort_coordinates(
689
+ component_real, component_imag
690
+ )
691
+
692
+ shape = real.shape
693
+ real = real.reshape(-1)
694
+ imag = imag.reshape(-1)
695
+ fraction = numpy.zeros((component_real.size, real.size), dtype=dtype)
696
+
697
+ _mean_value_coordinates(
698
+ fraction,
699
+ indices,
700
+ real,
701
+ imag,
702
+ component_real,
703
+ component_imag,
704
+ num_threads,
705
+ )
706
+
707
+ return numpy.asarray(fraction.reshape((-1, *shape)).squeeze())