Skip to content
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

2550 wedge slicer #2566

Merged
merged 24 commits into from
Aug 1, 2023
Merged

2550 wedge slicer #2566

merged 24 commits into from
Aug 1, 2023

Conversation

ehewins
Copy link
Contributor

@ehewins ehewins commented Jul 27, 2023

Description

This PR addresses issue #2550, implementing the Wedge Slicer. The desired functionality is present, and the ideas behind RadiusInteractor.py could be applied to simplify SectorSlicer.py if the slicers are ever refactored. Also included are the cherry-picked commits from branch 2482-problem-with-dragging-slicer-elements-on-plot, which served as a base for my work here.

Closes #2550 and also closes #2482

How Has This Been Tested?

The slicer interactor elements were adjusted in various sequences, through both the GUI and the Edit Slicer Parameters window accessible via the right-click menu. It was found that these parameters behaved consistently, and each of the averaging directions produced convincing-looking 1D plots.
Whether the 1D plot results produced by the slicer are accurate depends on whether the classes SectorQ and SectorPhi from sasdata/sasdata/data_util/manipulations.py are working as intended. They should be sufficient for high resolution data, but there may be further work necessary to improve their reliability with lower resolution data.

Review Checklist (please remove items if they don't apply):

  • Code has been reviewed
  • Functionality has been tested
  • Windows installer (GH artifact) has been tested (installed and worked)
  • MacOSX installer (GH artifact) has been tested (installed and worked)
  • User documentation is available and complete (if required)
  • Developers documentation is available and complete (if required)
  • The introduced changes comply with SasView license (BSD 3-Clause)

butlerpd and others added 21 commits July 18, 2023 09:10
This fixes the error due to the confusion between base and base.base which had all interactors redraw the plot first and updating from the move second. This was resolved in the "moveend" method but made using the mouse to set the interactor rather difficult to do precisely. This was also cleanded up in the three interactor/slicer modules not currently used but that probably will be for the needs of the magnetic/crystal scattering communities. Duplicate draws were removed when appropriate.
First pass at fixing the slicer classes docstrings.
There are three unused slicer modules that are set up for wedge type slicers. These were never implemented. I suspect that in fact it was orinally planed to use this for sector averaging where perhaps the wedge became a sector by making r1=0 and r2 = qmax. However as it stands it left two slicers classes called SectorInteractor.  This unused class is renamed to the more appropriate WedgeInteractor in preparation for being used for crystal type data.
…'left' and 'right' are set correctly when calling SideInteractor.update().
…Also added back a superfluous self.update() call for consistency with the other slicers.
…r sets them for better consistency with the other interactor elements.
…w, fixed slicer plotting bugs, and corrected the nbins and npts implementations.
…teractor to draw line from origin instead of across the whole plot.
@ehewins
Copy link
Contributor Author

ehewins commented Jul 28, 2023

Following some further testing, I've discovered a bug in the SectorPhi class in manipulations.py (in sasdata) which prevents certain phi and delta_phi angles from being set when attempting to perform "Wedge Averaging in Phi" . Considering this class has been unimplemented before now, I guess it's not surprising it has undiscovered bugs. Will update this post when I've found a fix.

…o corrected the angles being sent to manipulations.py
@butlerpd butlerpd added the Discuss At The Call Issues to be discussed at the fortnightly call label Jul 31, 2023
Copy link
Contributor

@lucas-wilkins lucas-wilkins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of my comments are very minor, but there's a couple of things around inheritance that I think could perhaps be written a little better. Can you check that you're overriding the right methods.

"""
def __init__(self, base, axes, color='black', zorder=5, r=1.0,
theta=np.pi / 3, phi=np.pi / 8):
BaseInteractor.__init__(self, base, axes, color=color)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super().__init__(base, axes, color=color) is perhaps more appropriate here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I can see the sense in that. All of the slicer interactors call BaseInteractor.__init__() however, would you advise making this change universally or just in WedgeInteractor, ArcInteractor and RadiusInteractor?

src/sas/qtgui/Plotting/Slicers/ArcInteractor.py Outdated Show resolved Hide resolved
src/sas/qtgui/Plotting/Slicers/WedgeSlicer.py Show resolved Hide resolved
src/sas/qtgui/Plotting/Slicers/WedgeSlicer.py Outdated Show resolved Hide resolved
@lucas-wilkins lucas-wilkins self-requested a review August 1, 2023 10:43
@rozyczko
Copy link
Member

rozyczko commented Aug 1, 2023

I started looking at the functionality.

Loaded P123_D2O_30_percent.dat from the 2D examples and attempted to invoke the Phi wedge averaging.
The slicer shows up but throws.

Granted, I was being silly and started the slicer on the residuals plot, without the err_data attribute, which is likely the issue, but the code should at least check for the field.

  File "C:\projects\sasview\src\sas\qtgui\Plotting\Slicers\BaseInteractor.py", line 129, in onRelease
    self.moveend(ev)
  File "C:\projects\sasview\src\sas\qtgui\Plotting\Slicers\RadiusInteractor.py", line 132, in moveend
    self.base.moveend(ev)
  File "C:\projects\sasview\src\sas\qtgui\Plotting\Slicers\WedgeSlicer.py", line 253, in moveend
    self._post_data()
  File "C:\projects\sasview\src\sas\qtgui\Plotting\Slicers\WedgeSlicer.py", line 344, in _post_data
    super()._post_data(SectorPhi)
  File "C:\projects\sasview\src\sas\qtgui\Plotting\Slicers\WedgeSlicer.py", line 168, in _post_data
    sector = sect(self.data)
  File "C:\Users\piotrrozyczko\.conda\envs\sasview\lib\site-packages\sasdata\data_util\manipulations.py", line 1000, in __call__
    return self._agv(data2D, 'phi')
  File "C:\Users\piotrrozyczko\.conda\envs\sasview\lib\site-packages\sasdata\data_util\manipulations.py", line 848, in _agv
    err_data = data2D.err_data[np.isfinite(data2D.data)]
TypeError: 'NoneType' object is not subscriptable

Copy link
Member

@rozyczko rozyczko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good code, just some minor comments not influencing the overall picture.

Great job of adding and correcting lots of comments in the code!

The only issue is the runtime exception when applying the slicer onto a residual plot, but this applies to all slicers, so needs to be made a separate GH issue.

label='pick', zorder=zorder,
visible=True)[0]
# Define the arc
[self.arc] = self.axes.plot([], [], linestyle='-', marker='', color=self.color)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a small lack of consistency
a = method()[0] vs [a] = method()
Both unpack the first plot so please choose one way of doing it

self.arc.remove()
except:
# Old version of matplotlib
for item in range(len(self.axes.lines)):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we be worrying about this "old version" path anymore? remove() is available in >3.0, which we have standardized on for quite some time now.

yval = 1.0 * self.radius * np.sin(angleval)
x.append(xval)
y.append(yval)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be improved (performance) by taking out the factor and offset calculations out of the loop.
precalculate

angle_factor = 2 * self.phi / (self.npts - 1)
angle_offset = self.theta - self.phi

and just use those in the loop, e.g. with

x = [self.radius * np.cos(angle_factor * i + angle_offset) for i in range(self.npts)]
y = [self.radius * np.sin(angle_factor * i + angle_offset) for i in range(self.npts)]

MIN_PHI_DIFFERENCE = 0.01
isValid = True

# Stitched together from other slicers. There could be a neater way.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could probably invent something fancy here but maybe readability is better?

    """
    Validate input from user.
    Values get checked at apply time.
    """
    
    def check_radius_difference(param_name, other_radius_name, param_value):
        if np.fabs(param_value - self.getParams()[other_radius_name]) < self.dqmin:
            return f"Inner and outer radii too close. Please adjust."
        elif param_value > self.qmax:
            return f"{param_name.capitalize()} exceeds maximum range. Please adjust."
        return None

    def check_phi_difference(param_value):
        if np.fabs(param_value) < 0.01:
            return "Sector angles too close. Please adjust."
        return None

    def check_bins(param_value):
        if param_value < 1:
            return "Number of bins cannot be <= 0. Please adjust."
        return None

    validators = {
        'r_min': lambda value: check_radius_difference('r_min', 'r_max', value),
        'r_max': lambda value: check_radius_difference('r_max', 'r_min', value),
        'delta_phi [deg]': check_phi_difference,
        'nbins': check_bins
    }

    if param_name in validators:
        error_message = validators[param_name](param_value)
        if error_message:
            print(error_message)
            return False

    return True

@butlerpd butlerpd merged commit 229f483 into main Aug 1, 2023
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Discuss At The Call Issues to be discussed at the fortnightly call
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wedge/Annulus-Sector Slicer Problem with dragging slicer elements on plot
4 participants