-
Notifications
You must be signed in to change notification settings - Fork 210
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
PolygonROI #3030
PolygonROI #3030
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## RELEASE_next_minor #3030 +/- ##
======================================================
+ Coverage 81.12% 81.37% +0.24%
======================================================
Files 146 147 +1
Lines 22129 22403 +274
Branches 4934 5002 +68
======================================================
+ Hits 17953 18230 +277
+ Misses 2989 2984 -5
- Partials 1187 1189 +2 ☔ View full report in Codecov by Sentry. |
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.
From a quick look, this seems to be on the right track. I suspect that the most difficult part is to generate the mask, which is already done here. Do you wan to add the matplotlib polygon widget in this PR? I think that it shouldn't be too much code.
Since the masking tools are targeted for RELEASE_next_major, this PR is as well. However, this would also be suitable for a minor release, so I can close this PR and move the functionality to target RELEASE_next_minor if preferred.
I think that it would be unlikely that they will be a minor release between the major release.
While this PR has some masking functionality, I do not want it to interfere with #2375, so let me know if I should
As I understand, even if both PR are dealing with mask, their focus are different.
The implementation is very similar to CircleROI, but uses a mask from rasterizing a polygon rather than a circle.
I guess that it would be good to make a base class for mask-ROI classes, as I would imagine that in the future, they could be more mask-ROI classes?
Thanks for the look!
I think I can draft the implementation of this pretty soon and decide after the scope of it is clear.
Yes, there is a bit of shared code that could be useful to put in its own class. It might have to involve multiple inheritance, as |
Though I had some difficulties, I have finished a working prototype for integrating The interface for the MPL widgets are quite different from the existing HyperSpy ones, so I added a base class |
Hello, I currently have a working implementation of the PolygonROI and accompanying PolygonWidget. I ended up spending quite some more time developing this, as I found it useful the option of having multiple polygons as a ROI, which is now implemented. Let me know what you think! Here is a minimal example of how it works, with
"Escape" resets the currently constructed polygon, "shift"+click to move it, grab the vertex handles to move the vertices. Click outside the finished polygon to start another one. You can also get a boolean mask from the ROI, which is useful for interfacing with other libraries:
I have tested that it works with the same interface/behaviour as the other ROIs, in particular CircleROI which is quite similar. I have checked and found it seems to work with Here is an example of using it interactively with a histogram:
The public interface of Hope this will be of use, and thank you for any feedback! There are perhaps some things still that I would like to go over once more. Plus some tests. (Here is my example signal)
|
This looks very promising! :) It is quite a bit to review but I will try to do in the coming weeks. |
9203c67
to
aac2fea
Compare
I have reviewed some of the functionality recently, and have explored one particular issue with the plotting of a lazy signal after using |
@sivborg would this not be fixed by just having the compute navigator function call Using the center chunk of the signal for computing the navigator is nice but does introduce some potential inconsistencies/ potential strange behavior. |
@CSSFrancis Using Though in my use cases, the centre chunk is often uniformly nan, as I choose multiple polygon at large distances, leaving the middle as NaN. So another way to choose default I have made a quick working solution, although I am not sure it is worth it to change so much of the existing functionality, potentially introducing some bugs, to fix a visual problem. A user could also fix this themselves by replacing an NaN with zeroes before plotting. |
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.
This look already fairly good and sorry for coming back on this only now.
The API needs to be made consistent with the API of existing widgets - there are some comments in my review on that.
One thing that I find surprising in the current implementation of PolygonROI
is that it consist of several polygons and once there are fixed, they can't be changed interactively... I think that this is a significant inconsistency with the existing behaviour of other ROIs. If the aim of this PR is to be able to select/mask areas with several polygons, then this should be done by adding a different functionality which will take care of combining multiple ROIs, but special casing a type of ROIs.
The rest should be small details!
Thank you for taking a look through! Regarding not being capable of editing existing polygons, an earlier commit actually had that possibility! However it used some "private" features in the |
Why do you need to access private API? In the following example, you can edit the polygon: import matplotlib.pyplot as plt
from matplotlib.widgets import PolygonSelector
fig, ax = plt.subplots()
selector2 = PolygonSelector(ax, lambda *args: None) |
It is mostly a problem in the case where you have multiple polygons. It is possible to attach multiple |
This is an important point which is not consistent with other ROIs and I don't think that it is a good idea to introduce a different behaviour for this ROI. There is currently no pattern to handle multiple ROI in hyperspy and this is true that in some situations (ROI overlapping) multiple ROI doesn't play together. However, this is issue should be handle separately from the |
I am working on reimplementing an older commit where there was only one polygon in the ROI, for consistency. I am a bit busy currently but hope to have it done early next month! |
Re-opening because this has been closed automatically by mistake! |
for more information, see https://pre-commit.ci
I expected that it would be possible to add vertices manually after creating the polygon, in which case, the number of vertices could be changed once a polygon is completed, but this isn't to be the case - vertices can only be removed, not added. This is a shame and this is something that would be useful in matplotlib. Can you add example in the gallery? I will try to review in the coming days. |
Yes, that is true. Although it might not be too difficult to add at some point in the future.
I have added an example to use PolygonROI in the examples folder. Although this example is only on signal axes, so perhaps it would be interesting to expand it to show how it can be used in 4D, by slicing either the signal or navigation space. |
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 push a few commits to:
- fix and improve documentation - readthedocs is still failing which is surprising
- start to add some tests - more are needed to increase the coverage in the
roi.py
module - improve some code.
When using multiple selectors, they all moved together and this behaviour should be fixed in matplotlib/matplotlib#29027.
What is left is to increase the test coverage as highlighted by the codecov warning in the "files changes" tab.
I have now added some further test coverage, with only a couple |
I should have now fixed the bug in the polygon construction. It was created since the update of the ROI was moved from the |
64f1444
to
00ef7b0
Compare
Thank you @sivborg, it wasn't an easy task to implement this type of ROI! If there are things that need tweaking, this can be done in follow up PRs. |
And thank you for the feedback and help, @ericpre ! |
This is part of the implementation of #2993 , where the aim is to integrate GUI masking into HyperSpy from matplotlib widgets.
As a step forward, I have extended the ROI functionality to a two-dimensional polygonal region-of-interest. Since this step is independent of the GUI, and to keep the PRs in more manageable scopes, I decided to merge this functionality in first.
Moreover, this feature reuses a lot of code from
CircleROI
as the principle is very similar.Since the masking tools are targeted for
RELEASE_next_major
, this PR is as well. However, this would also be suitable for a minor release, so I can close this PR and move the functionality to targetRELEASE_next_minor
if preferred.While this PR has some masking functionality, I do not want it to interfere with #2375, so let me know if I should
Description of the change
PolygonROI
region-of-interest class that can be used to mask areas as defined by a polygonboolean_mask
function that can retrieve the ROI as a boolean numpy array, which can be passed on to methods requiring a mask.Progress of the PR
upcoming_changes
folder (seeupcoming_changes/README.rst
),readthedocs
doc build of this PR (link in github checks)Minimal example of the bug fix or the new feature
Technical details.
The implementation is very similar to CircleROI, but uses a mask from rasterizing a polygon rather than a circle.
As a polygon is not directly available as a widget in HyperSpy, I have omitted the interactive functionality for now. As the functionality is added to the GUI,
PolygonROI
can be extended to support this.The algorithm used to rasterize the polygon into an array has a few limitations:
Compared to other ROIs, this one does not have a fixed amount of parameters as a polygon can have as many points as necessary. This changes some of the conventions by displaying the parameters. Currenly, this is how the class behaves: