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

[Bug]: Exception not handled in widgetlock() #23324

Closed
delsuc opened this issue Jun 22, 2022 · 5 comments · Fixed by #23373
Closed

[Bug]: Exception not handled in widgetlock() #23324

delsuc opened this issue Jun 22, 2022 · 5 comments · Fixed by #23373
Labels
Difficulty: Medium https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues Good first issue Open a pull request against these issues if there are no active ones! status: confirmed bug
Milestone

Comments

@delsuc
Copy link

delsuc commented Jun 22, 2022

Bug summary

( This bug was originally issued in ipympl: matplotlib/ipympl#471 )

I want to use a selector matplotlib.widgets.RectangleSelector , it is incompatible with zoom and pan
So I try to call widgetlock to prevent user from using zoom when the selector is active, hoping that the zoom or pan tools will not be blocked.
This does not work, but crashes rather.

Code for reproduction

import matplotlib.pyplot as plt
fig,ax = plt.subplots()
ax.plot([0,1],[0,1])
fig.canvas.widgetlock(ax)   # get the widget lock
plt.show()

Actual outcome

if you then hit the zoom or pan matplotlib button, which also try to get the lock, you get

Traceback (most recent call last):
  File "/home/mad/anaconda3/lib/python3.8/site-packages/matplotlib/backends/backend_qt5.py", line 762, in zoom
    super().zoom(*args)
  File "/home/mad/anaconda3/lib/python3.8/site-packages/matplotlib/backend_bases.py", line 3110, in zoom
    self.canvas.widgetlock(self)
  File "/home/mad/anaconda3/lib/python3.8/site-packages/matplotlib/widgets.py", line 41, in __call__
    raise ValueError('already locked')
ValueError: already locked
Aborted (core dumped)

Expected outcome

The lock is grabbed by the Selector, when zoom it tries to grab the lock, an exception is raised which is the normal behaviour of the lock, however the zoom tool should handle the exception and give-up.

Additional information

100% reproducible in my set-up

Operating system

Ubuntu 20.04

Matplotlib Version

3.3.2

Matplotlib Backend

Qt5Agg

Python version

3.8.5

Jupyter version

N/A

Installation

conda

@tacaswell tacaswell added this to the v3.6.0 milestone Jun 24, 2022
@tacaswell tacaswell added Good first issue Open a pull request against these issues if there are no active ones! Difficulty: Medium https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues labels Jun 24, 2022
@tacaswell
Copy link
Member

Good first issue because there is no API choices here, but medium because it requires understanding locks in the UI and making sure that the pan/zoom mode are left in a good (non-selected) state when this fails.

@delsuc
Copy link
Author

delsuc commented Jun 25, 2022

In my code, I do the following to deactivate zoom and pan when entering the selector:

        if self.fig.canvas.toolbar.mode == backend_bases._Mode.PAN:
            self.fig.canvas.toolbar.pan()                # pan() and zoom() are toggles
        elif self.fig.canvas.toolbar.mode == backend_bases._Mode.ZOOM:
            self.fig.canvas.toolbar.zoom()

where self.fig is my matplotlib Figure.

it works fine, I just want to be sure that the user does not enter zoom or pan while in the selector.
However in backend_nbagg I also have to do

        self.fig.canvas.toolbar._current_action = ''   # deselect pan/zoom buttons - see backend_nbagg

otherwise, the button and greyed even though the action is not activated. (did not check other backends...)

@kianelbo
Copy link
Contributor

kianelbo commented Jun 30, 2022

I did a little bit of tinkering and came up with a very naive fix (my very first contribution!). Would you take a look at my PR please? I still haven't figured out how to prevent pan and zoom from being toggled in the toolbar.

@jklymak
Copy link
Member

jklymak commented Jun 30, 2022

@delsuc, can you possibly test #23373 and see if it works as a fix for you?

@delsuc
Copy link
Author

delsuc commented Jul 10, 2022

I was able to test the PR in jupyter notebook (the environment I need the feature)

the following code passes successfuly:

# This code show how you can temporary disable the zoom/pan modes
# when using an interactive selector
 
# In[1]:
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.widgets as mwidgets
from matplotlib import backend_bases
import numpy as np

# In[2]:
matplotlib._version.version   # check version

# In[3]:
get_ipython().run_line_magic('matplotlib', 'notebook')

# In[4]:
fig, ax = plt.subplots()
x = np.linspace(0,10,100)
plt.plot(x, np.sin(x) )
rect_selected = [0,0]
def on_select(mini, maxi):
    "selector callback, returns xmin, xmax, in data unit"
    global rect_selected
    rect_selected = [mini, maxi]

# In[5]:
rect = mwidgets.RectangleSelector(ax, on_select, button=3, interactive=True)

print("deactivating Zoom/Pan modes, but Home and History are still available")
if fig.canvas.toolbar.mode == backend_bases._Mode.PAN:
    fig.canvas.toolbar.pan()      # pan() and zoom() are toggles
elif fig.canvas.toolbar.mode == backend_bases._Mode.ZOOM:
    fig.canvas.toolbar.zoom()
fig.canvas.toolbar._current_action = ''   # deselect pan/zoom buttons - see backend_nbagg
# then get the lock 
fig.canvas.widgetlock(rect)

print ('Now select a zone of the plot with the right mouse button')

# In[7]:
# show selected entries
print(rect_selected[0],'\n',rect_selected[1])

# In[8]:
# clear, release the lock and delete
rect.set_visible(False)
fig.canvas.widgetlock.release(rect)
del rect

as you see it works fine when in %matplotlib notebook mode, however I was not able to test it yet with %matplotlib widget which I need, because conda install ipympl downgrades matplotlib to 3.5.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Difficulty: Medium https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues Good first issue Open a pull request against these issues if there are no active ones! status: confirmed bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants