Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Allow Rectangle and Ellipse selectors to be rotated #19864

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

Closed
wants to merge 6 commits into from

Conversation

dstansby
Copy link
Member

@dstansby dstansby commented Apr 4, 2021

PR Summary

This PR allows RectangleSelector and EllipseSelector to be rotated about their anchor point. This is enabled by default with the 'r' modifier key. Example:

Screen.Recording.2021-04-04.at.21.55.32.mov

PR Checklist

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (run flake8 on changed files to check).
  • New features are documented, with examples if plot related.
  • [ x Documentation is sphinx and numpydoc compliant (the docs should build without error).
  • Conforms to Matplotlib style conventions (install flake8-docstrings and run flake8 --docstring-convention=all).
  • New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).

Copy link
Member

@QuLogic QuLogic left a comment

Choose a reason for hiding this comment

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

There should be tests for resizing after the selector has rotated, which is a thing that could not occur before.

@dstansby dstansby force-pushed the rotate-selector branch from 4186848 to ca2abb3 Compare May 8, 2021 14:10
@dstansby
Copy link
Member Author

dstansby commented May 8, 2021

Thanks for the review - I marked all the minor changes as resolved, and have addressed the other points too.

Copy link
Member

@QuLogic QuLogic left a comment

Choose a reason for hiding this comment

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

Still needs a test of resizing after rotation.

@dstansby
Copy link
Member Author

Still needs a test of resizing after rotation.

Thanks for catching that, it revealed a (now fixed) bug in how I was calculating the resizing. I've also paramatrized the test so it runs for both Rectangle and Ellipse selectors.

xc, yc = self.corners
self._corner_handles = ToolHandles(self.ax, xc, yc, marker_props=props,
useblit=self.useblit)

self._edge_order = ['W', 'N', 'E', 'S']
self._edge_order = ['W', 'S', 'E', 'N']
Copy link
Member

Choose a reason for hiding this comment

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

This order hurts my brain ;-) Cardinal directions should be clockwise and start w/ north!. But, I don't think it really matters here....

@QuLogic
Copy link
Member

QuLogic commented May 19, 2021

OK, I tried this out with the rectangle selector example, and it does not work at all in a way I'd expect. One edge barely rotated, while the other turns much more. Sometimes, the rectangle is a completely different aspect ratio. It becomes a parallelogram instead of a rotated rectangle.

@dstansby
Copy link
Member Author

That's because the rectangle is defined in axes coordinates, not figure coordinates. If you do ax.set_aspect('equal') it should work as expected. I think it would take quite a bit more work to convert RectangleSelector to be drawn in figure coordinates instead of axes coordinates, but happy to give it a go if people think it's worth blocking this PR on.

@jklymak
Copy link
Member

jklymak commented May 19, 2021

Yeah I was just getting the point of wondering about that. Is it defined in axes coordinates or data coordinates? If data coordinates, I'm not clear how this is useful.

@dstansby
Copy link
Member Author

I've had a bit of a think about this, and would like to advocate for it to be included as is, with a note (or warning) in the docstring that it doesn't work as expected when the axes aspect ratio != 1. My reasoning is:

  • It doesn't break or modify any existing behavior
  • The motivating use case for this PR was selecting regions in astronomical images. These are almost always displayed with an aspect ratio of 1, where rotating selectors works.

Is it defined in axes coordinates or data coordinates?

It is defined in data coordinates, sorry for the confusion in my earlier comment.

@jklymak
Copy link
Member

jklymak commented May 24, 2021

@dstansby I understand your use case. OTOH I think its going to be confusing for everyone else when this rotation is not in figure/axes space... Is it hard to put in figure space?

@jklymak
Copy link
Member

jklymak commented May 26, 2021

@dstansby did you want a definitive answer on this? We could discuss on the call. I guess I'm -0.25 the way the PR is now. Can you implement outside of core?

@dstansby
Copy link
Member Author

Is it hard to put in figure space?

I suspect the answer is technically not hard, but it will take a reasonable amount of development time to disentangle everything to maintain backwards compatibility

Can you implement outside of core?

What do you mean by this? In another package?

I think the deciding question is: Would it be okay to release this as is, and then in the future change (ie. fix) the behavior for aspect!=1 without warning? If not, I'm happy to take a dive into moving the widgets from data to axes coordinates before merging this, but it might take a while.

@jklymak
Copy link
Member

jklymak commented Jun 8, 2021

I personally think this should be in figure space, but wouldn't block over it.

@timhoffm
Copy link
Member

timhoffm commented Jun 9, 2021

We should not inroduce broken rotations. That's rather confusing.

If you cannot make this work for the general case right now, I propose to only enable rotations on equal-aspect Axes. This should be easy to check via self.ax.get_aspect() == 1.

@jklymak jklymak marked this pull request as draft June 9, 2021 22:22
@dstansby dstansby marked this pull request as ready for review June 27, 2021 20:02
@dstansby
Copy link
Member Author

If you cannot make this work for the general case right now, I propose to only enable rotations on equal-aspect Axes. This should be easy to check via self.ax.get_aspect() == 1.

Sounds good to me 👍

For a non-equal aspect axes, trying to rotate now does nothing and raises a warning. I've added an extra test to check this works as intended, and updated the docs.

Copy link
Member

@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

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

Is it possible with reasonable effort to rotate about the center? The tilting over an edge is quite surprising and I don't know any other application doing this.

@jklymak jklymak marked this pull request as draft July 7, 2021 20:22
@dstansby
Copy link
Member Author

Is it possible with reasonable effort to rotate about the center? The tilting over an edge is quite surprising and I don't know any other application doing this.

I just spent 5 minutes trying to work out if there was an easy way, and couldn't work it out, so I think changing this would take a reasonable amount of effort. This is mainly because a Rectangle patch is defined by a corner coordinate and rotation, so it's non trivial (but possible) if one wants to set the rotation angle to be about the center, as a new rotation angle about the corner and corner coordinate has to be calculated for the rectangle at the same time.

@dstansby
Copy link
Member Author

I've rebased this, so should be good for re-review.

@dstansby dstansby marked this pull request as ready for review July 22, 2021 16:58
@timhoffm
Copy link
Member

I just spent 5 minutes trying to work out if there was an easy way, and couldn't work it out, so I think changing this would take a reasonable amount of effort. This is mainly because a Rectangle patch is defined by a corner coordinate and rotation, so it's non trivial (but possible) if one wants to set the rotation angle to be about the center, as a new rotation angle about the corner and corner coordinate has to be calculated for the rectangle at the same time.

Isn't the new location simply: x' = x + d - Md where x is the position vector of the rectangle corner, d is the connection vector from the corner to the center, and M is the rotation matrix?

@dstansby
Copy link
Member Author

Isn't the new location simply: x' = x + d - Md where x is the position vector of the rectangle corner, d is the connection vector from the corner to the center, and M is the rotation matrix?

Possibly? One also needs to work out the new rotation (about the patch corner). If someone wants to take a go at this feel free, I don't currently have the bandwidth to work out the maths or where it needs changing in the code.

@timhoffm
Copy link
Member

timhoffm commented Jul 23, 2021

One also needs to work out the new rotation (about the patch corner).

I think, you can just do the rotation and then shift the rectangle as proposed.

@ericpre
Copy link
Member

ericpre commented Aug 18, 2021

#20839 is an alternative PR to add selector rotation.

@ericpre
Copy link
Member

ericpre commented Dec 8, 2021

Done in #20839.

@ericpre ericpre closed this Dec 8, 2021
@dstansby dstansby deleted the rotate-selector branch December 9, 2021 10:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants