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

Improved selection widget #3502

Merged
merged 18 commits into from Nov 13, 2014

Conversation

blink1073
Copy link
Member

This is in preparation for enhancing the selection widgets as per #3486.

This expands the new _Selector class from #3376 and normalizes the API for the three current selection widgets: RectangleSelector, LassoSelector, and SpanSelector.

The only known API change is that the ignore criteria from the RectangleSelector are now used for all three, since they were the most complete and robust.

This also adds tests for all three widgets.

@blink1073
Copy link
Member Author

@tacaswell, @fariza, here we go...

@tacaswell tacaswell added this to the v1.5.x milestone Sep 12, 2014
@fariza
Copy link
Member

fariza commented Sep 12, 2014

@blink1073
For the moment I would keep the draw_rubberband out of this and get everything in shape.
It can be done later with another PR.

Just for future reference
The draw_rubberband can not be "hard coded" here, it has to be implemented in each backend (it's already like that). By the way the method that you used is from the qt backend, it is different for each backend.
The idea to use the draw_rubberband method is to be faster, better, etc.. (#3475 (comment)) and use it (if available) instead of the matplotlib.patches.Rectangle that you are using in RectangleSelector

@blink1073
Copy link
Member Author

I removed draw_rubberband. I see now that I will have to use self.canvas.toolbar.draw_rubberband when I integrate that behavior.

@tacaswell
Copy link
Member

@blink1073 This needs (at minimum) a re-base.

@blink1073
Copy link
Member Author

Rebase complete.

@@ -0,0 +1,161 @@
from __future__ import (absolute_import, division, print_function,
Copy link
Member

Choose a reason for hiding this comment

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

GUI tests? madness!

Copy link
Member Author

Choose a reason for hiding this comment

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

Ha, I had already written these tests for scikit-image, but yes, it was a pain...

Copy link
Member

Choose a reason for hiding this comment

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

You need to white-list this file to be run in

default_test_modules = [

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@jenshnielsen
Copy link
Member

Some tests are failing on Travis

@blink1073
Copy link
Member Author

I'm at a bit of a loss here. I tested on both Python 2.7 and 3.4 with Ubuntu 14.04 64bit. The build is not only failing two of my tests but some outside of the reach of this PR as well: mpl_toolkits.tests.test_mplot3d.test_bar3d.test. I ran the tests on my machine using nosetests test_widget.py. I'm having a really hard time following the magic incantation you're using in your .travis.yml file.

assert ax._got_onselect


def test_rectangle_selector():
Copy link
Member

Choose a reason for hiding this comment

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

Add a @cleanup (from matplotlib.testing.decorators) to this. I suspect that the other failing tests are due the artists form this test leaking out.

@tacaswell
Copy link
Member

I can reproduce the failures locally running the tests like they are run on travis:

(conda27)tcaswell@eowyn:matplotlib$ python tests.py matplotlib.tests.test_widgets
FEF
======================================================================
ERROR: matplotlib.tests.test_widgets.test_span_selector
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcaswell/.virtualenvs/conda27/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 135, in test_span_selector
    check_span('horizontal', minspan=10, useblit=True)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/testing/decorators.py", line 110, in wrapped_function
    func(*args, **kwargs)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 128, in check_span
    assert ax._got_onselect
AttributeError: 'AxesSubplot' object has no attribute '_got_onselect'

======================================================================
FAIL: matplotlib.tests.test_widgets.test_rectangle_selector
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcaswell/.virtualenvs/conda27/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 94, in test_rectangle_selector
    check_rectangle(useblit=True, button=1)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/testing/decorators.py", line 110, in wrapped_function
    func(*args, **kwargs)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 83, in check_rectangle
    tool.onmove(event)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/widgets.py", line 1618, in onmove
    self.update()
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/widgets.py", line 1195, in update
    self.ax.draw_artist(artist)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/axes/_base.py", line 2103, in draw_artist
    assert self._cachedRenderer is not None
AssertionError

======================================================================
FAIL: matplotlib.tests.test_widgets.test_lasso_selector
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcaswell/.virtualenvs/conda27/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 164, in test_lasso_selector
    check_lasso_selector()
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/testing/decorators.py", line 110, in wrapped_function
    func(*args, **kwargs)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 155, in check_lasso_selector
    tool.onmove(event)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/widgets.py", line 1714, in onmove
    self.update()
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/widgets.py", line 1195, in update
    self.ax.draw_artist(artist)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/axes/_base.py", line 2103, in draw_artist
    assert self._cachedRenderer is not None
AssertionError

----------------------------------------------------------------------
Ran 3 tests in 0.484s

FAILED (errors=1, failures=2)

I get (slightly different) failures if I run just the widget tests via nosetest:

(conda27)tcaswell@eowyn:tests$ nosetests test_widgets.py
FEF
======================================================================
ERROR: matplotlib.tests.test_widgets.test_span_selector
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcaswell/.virtualenvs/conda27/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 135, in test_span_selector
    check_span('horizontal', minspan=10, useblit=True)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/testing/decorators.py", line 110, in wrapped_function
    func(*args, **kwargs)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 123, in check_span
    tool.onmove(event)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/widgets.py", line 1427, in onmove
    self.update()
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/widgets.py", line 1196, in update
    self.canvas.blit(self.ax.bbox)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/backends/backend_qt5agg.py", line 158, in blit
    self.repaint(l, self.renderer.height-t, w, h)
AttributeError: 'FigureCanvasQTAgg' object has no attribute 'renderer'

======================================================================
FAIL: matplotlib.tests.test_widgets.test_rectangle_selector
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcaswell/.virtualenvs/conda27/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 94, in test_rectangle_selector
    check_rectangle(useblit=True, button=1)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/testing/decorators.py", line 110, in wrapped_function
    func(*args, **kwargs)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 83, in check_rectangle
    tool.onmove(event)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/widgets.py", line 1618, in onmove
    self.update()
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/widgets.py", line 1195, in update
    self.ax.draw_artist(artist)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/axes/_base.py", line 2103, in draw_artist
    assert self._cachedRenderer is not None
AssertionError

======================================================================
FAIL: matplotlib.tests.test_widgets.test_lasso_selector
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcaswell/.virtualenvs/conda27/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 164, in test_lasso_selector
    check_lasso_selector()
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/testing/decorators.py", line 110, in wrapped_function
    func(*args, **kwargs)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/tests/test_widgets.py", line 155, in check_lasso_selector
    tool.onmove(event)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/widgets.py", line 1714, in onmove
    self.update()
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/widgets.py", line 1195, in update
    self.ax.draw_artist(artist)
  File "/home/tcaswell/other_source/matplotlib/lib/matplotlib/axes/_base.py", line 2103, in draw_artist
    assert self._cachedRenderer is not None
AssertionError

----------------------------------------------------------------------
Ran 3 tests in 0.562s

FAILED (errors=1, failures=2)

@blink1073
Copy link
Member Author

Funny, now that I added the @cleanup decorators, I get the errors locally as well, investigating...

xdata = min(x1, xdata)
ydata = max(y0, ydata)
ydata = min(y1, ydata)
event.xdata = xdata
Copy link
Member

Choose a reason for hiding this comment

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

This smells like something that is going to introduce race-condition/transient bugs if more than one callback is using the same event.

Copy link
Member Author

Choose a reason for hiding this comment

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

Should events have a lock attribute perhaps? Then you could use with event.lock():.

Copy link
Member Author

Choose a reason for hiding this comment

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

I found the right solution: use a utility method to calculate the bounds as needed, and use a copy of the events for the onselect callback.

@blink1073
Copy link
Member Author

Passing all tests now.

@tacaswell
Copy link
Member

Catching AssertionErrors makes me a little nervous as the asserts can be optimized out (in principle...does anyone actually use pyo?) which will presumably cause AttributeErrors or similar later. draw_artist should be changed to raise a different type of Exception in case of the cached renderer being None, probably a custom exception....

maintence

@blink1073
Copy link
Member Author

Sure, but I have no idea what the error means or what to do about it...

@tacaswell
Copy link
Member

@blink1073 See PR against your branch.

@blink1073
Copy link
Member Author

@tacaswell, I am offended and pleased by your GIF.

@tacaswell
Copy link
Member

Why offended?

@blink1073
Copy link
Member Author

@tacaswell, assuming I didn't dork up the rebase, this should be good to go.

@blink1073
Copy link
Member Author

@tacaswell, it looks like the build failed due to some unrelated network problems, do you want to restart it?

tacaswell added a commit that referenced this pull request Nov 13, 2014
@tacaswell tacaswell merged commit 0efdf2f into matplotlib:master Nov 13, 2014
@blink1073 blink1073 deleted the improved-selection-widget branch November 13, 2014 01:08
@blink1073
Copy link
Member Author

What's next, the new RectangleSelector?

@tacaswell
Copy link
Member

If by new you mean moving over what you have in skimage, then yes!

On Wed Nov 12 2014 at 8:08:47 PM Steven Silvester notifications@github.com
wrote:

What's next, the new RectangleSelector?


Reply to this email directly or view it on GitHub
#3502 (comment)
.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants