-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix phasor_calibrate
to handle multi harmonic calibration
#69
Fix phasor_calibrate
to handle multi harmonic calibration
#69
Conversation
Pull main branch from PhasorPy with phasor module
…phasor_center' to handle multiple harmonics. Modified 'phasorpy_introduction' tutorial to add multiple harmonic calibration.
@cgohlke, I implemented some changes to Finally, I modified the |
Yes, I think this case should be supported by the
Right now it looks out of place. However, if you think the tutorial will make use of the second harmonic later, for example, to calculate multiple components, this section should replace the single harmonic calibration.
Good idea. The one issue I can see is passing through the |
src/phasorpy/phasor.py
Outdated
if isinstance(skip_axes, int): | ||
skip_axes = [skip_axes] | ||
elif skip_axes is None: | ||
skip_axes = [] | ||
dim_diff = numpy.ndim(re) - numpy.ndim(phase_zero) | ||
if dim_diff > 0: | ||
phase_zero = numpy.expand_dims( | ||
phase_zero, | ||
axis=tuple(i for i in range(-dim_diff, 0) if i not in skip_axes), | ||
) | ||
modulation_zero = numpy.expand_dims( | ||
modulation_zero, | ||
axis=tuple(i for i in range(-dim_diff, 0) if i not in skip_axes), | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to move this into the phasor_calibrate
function.
axis=tuple(...)
is calculated twice. Anyway, it looks to me that this would not work correctly if skip_axes are not the first axes?
There is some code in phasor_center
that looks related. Maybe the checking/normalization of skip_axes
can be refactored into a helper function?
phasorpy/src/phasorpy/phasor.py
Lines 1988 to 1996 in 8e9b123
if skip_axes is None: | |
axis = None | |
else: | |
if not isinstance(skip_axes, Sequence): | |
skip_axes = (skip_axes,) | |
if any(i >= real.ndim for i in skip_axes): | |
raise IndexError(f'{skip_axes=} out of range {real.ndim=}') | |
skip_axes = tuple(i % real.ndim for i in skip_axes) | |
axis = tuple(i for i in range(real.ndim) if i not in skip_axes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @cgohlke ! Your suggestions are excelent, I haven't realized I calculated the axis twice and your way is much more cleaner an efficent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I tried and it works for different axis, not just the first one.
…ransform`. Updated tests and removed example of multiple harmonic calibration from `phasorpy_introduction`.
I totally agree with you @cgohlke! I don't know why i didn't think first to change the I removed the example from Regarding the out argument passed to numpy functions, I don't know how we can approach that. Maybe a check or a warning or something in the description of the function? Maybe it is too much, specially if we add other methods and we need to consider more exceptions. |
I will refactor the axis determination code so that it can be used for both |
…nd `phasor_calibrate`.
phasor_calibrate
and phasor_transform
to handle multi harmonic calibrationphasor_calibrate
to handle multi harmonic calibration
I would prefer the helper function to also validate and "normalize" the Should we rename The helper function should be tested. How about something like: def _parse_skip_axis(
skip_axis: int | Sequence[int] | None,
/,
ndim: int,
) -> tuple[tuple[int, ...], tuple[int, ...]]:
"""Return axes to skip and not to skip.
This helper function is used to validate and parse `skip_axis`
parameters.
Parameters
----------
skip_axis : Sequence of int, or None
Axes to skip. If None, no axes are skipped.
ndim : int
Dimensionality of array in which to skip axes.
Returns
-------
skip_axis
Ordered, positive values of `skip_axis`.
other_axis
Axes indices not included in `skip_axis`.
Raises
------
IndexError
If any `skip_axis` value is out of bounds of `ndim`.
Examples
--------
>>> _parse_skip_axis((1, -2), 5)
(1, 3), (0, 2, 4)
"""
if ndim < 0:
raise ValueError(f'invalid {ndim=}')
if skip_axis is None:
return (), tuple(range(ndim))
if not isinstance(skip_axis, Sequence):
skip_axis = (skip_axis,)
if any(i >= ndim or i < -ndim for i in skip_axis):
raise IndexError(f"skip_axis={skip_axis} out of range for {ndim=}")
skip_axis = tuple(sorted(int(i % ndim) for i in skip_axis))
other_axis = tuple(i for i in range(ndim) if i not in skip_axis)
return skip_axis, other_axis and def test_parse_skip_axis():
"""Test _parse_skip_axis function."""
assert _parse_skip_axis(None, 0) == ((), ())
assert _parse_skip_axis(None, 1) == ((), (0,))
assert _parse_skip_axis((), 1) == ((), (0,))
assert _parse_skip_axis(0, 1) == ((0,), ())
assert _parse_skip_axis(0, 2) == ((0,), (1,))
assert _parse_skip_axis(-1, 2) == ((1,), (0,))
assert _parse_skip_axis((1, -2), 5) == ((1, 3), (0, 2, 4))
with pytest.raises(ValueError):
_parse_skip_axis(0, -1)
with pytest.raises(IndexError):
_parse_skip_axis(0, 0)
with pytest.raises(IndexError):
_parse_skip_axis(1, 1)
with pytest.raises(IndexError):
_parse_skip_axis(-2, 1) |
Thanks @cgohlke, that is a nice improvement and you are right to add the test! I also think it makes sense to change to I think now it is ready, but please let me know if there is anything worth improving. |
Description
This PR fixes the issue of
phasor_calibrate
being unable to handle correctly multiple harmonic calibration. This is related to issue #68.Not related, but also fixed a minor issue related to #67, to allow
phasor_center
to pass other keyword arguments other thanaxis
to numpy functions used in methods....
Release note
Summarize the changes in the code block below to be included in the
release notes:
Checklist