Skip to content

matplotlib>=3.3.2 breaks ipywidgets.interact #18638

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
casperdcl opened this issue Oct 2, 2020 · 8 comments · Fixed by #18639 or casperdcl/brainweb#11
Closed

matplotlib>=3.3.2 breaks ipywidgets.interact #18638

casperdcl opened this issue Oct 2, 2020 · 8 comments · Fixed by #18639 or casperdcl/brainweb#11

Comments

@casperdcl
Copy link
Contributor

casperdcl commented Oct 2, 2020

Bug report

Bug summary

Using ipywidgets.interact to update a figure works as expected in matplotlib<=3.3.1, but fails in matplotlib==3.3.2.

I don't think this is an ipywidgets issue since downgrading matplotlib fixes this issue.

Code for reproduction

In[1]:

%matplotlib notebook
import matplotlib as mpl
import matplotlib.pyplot as plt
import ipywidgets as ipyw
"works if %s <= 3.3.1" % mpl.__version__

In[2]:

fig = plt.figure()
@ipyw.interact(m=ipyw.FloatSlider(value=1, min=-10, max=10, step=0.01))
def update(m):
    plt.figure(fig.number, clear=True)
    plt.plot([m * x for x in range(-9, 10)])

Followed by moving the slider.

Actual outcome

  • when moving the slider, the figure does not update
  • a second figure is sometimes created instead
  • the second figure is usually blank, but sometimes updates instead

Expected outcome

  • the original figure updates as it does in matplotlib==3.3.1

Matplotlib version

  • Operating system: Ubuntu
  • Matplotlib version: 3.3.2 vs 3.3.1
  • Matplotlib backend (print(matplotlib.get_backend())): nbAgg
  • Python version: 3.7.8
  • Jupyter version (if applicable): jupyter-core==4.6.3
  • Other libraries: ipywidgets==7.5.1
  • Installation source: conda channel conda-forge
@QuLogic
Copy link
Member

QuLogic commented Oct 2, 2020

This has something to do with #18454. I guess interact replaces the OutputArea somehow.

@casperdcl
Copy link
Contributor Author

interesting, yes, if you split the cell just after fig = plt.figure() (so the ipywidget is placed in a different output cell) then it works.

Really should be able to put both in the same cell.

@tacaswell
Copy link
Member

Can you try with ipympl? The main source of the problem here is that nbagg is not aware of ipywidgets (we just grab the DOM and shove a bunch of divs and js into it!). If you use ipympl does it work better (ipympl is based on widgets and hence plays much nice with them).

@casperdcl
Copy link
Contributor Author

Just did conda install ipympl but can't even run the first two cells of https://github.com/matplotlib/ipympl/blob/master/examples/ipympl.ipynb

TypeError                                 Traceback (most recent call last)
~/py2/envs/py37/lib/python3.7/site-packages/ipympl/backend_nbagg.py in _handle_message(self, object, content, buffers)
    208     def _handle_message(self, object, content, buffers):
    209         # Every content has a "type".
--> 210         if content['type'] == 'closing':
    211             self._closed = True
    212         elif content['type'] == 'initialized':

TypeError: string indices must be integers

@tacaswell
Copy link
Member

tacaswell commented Oct 2, 2020

Can you please report that to ipympl?

QuLogic added a commit to QuLogic/matplotlib that referenced this issue Oct 2, 2020
In JavaScript, the event handlers are called for both the element and
also bubbled up from any children. If the Matplotlib figure is the only
thing in the output, that's fine, as closing the figure when one of the
`canvas` or `div`s clears is the same as when the `OutputArea` is
cleared. However, if there are other outputs, such as widgets, we do not
want to close the figure if one of them is cleared.

As there's no way to clear just the figure output, only close the figure
if the _entire_ `OutputArea` div is cleared (i.e., the element we've
attached to).

Fixes matplotlib#18638.
@casperdcl
Copy link
Contributor Author

casperdcl commented Oct 3, 2020

FYI this seems to be a temporary fix - essentially a decorator around plt.figure:

In[2]:

+def create_figure(*args, **kwargs):
+    out = ipyw.Output()
+    display(out)
+    with out:
+        return plt.figure(*args, **kwargs)
+
-fig = plt.figure()
+fig = create_figure()
 @ipyw.interact(m=ipyw.FloatSlider(value=1, min=-10, max=10, step=0.01))
 def update(m):
     plt.figure(fig.number, clear=True)
     plt.plot([m * x for x in range(-9, 10)])

casperdcl added a commit to casperdcl/brainweb that referenced this issue Oct 3, 2020
casperdcl added a commit to casperdcl/brainweb that referenced this issue Oct 3, 2020
@QuLogic
Copy link
Member

QuLogic commented Oct 5, 2020

This still needs fixing.

@QuLogic QuLogic reopened this Oct 5, 2020
@casperdcl
Copy link
Contributor Author

lol cross-org cross-repo close commands are now a thing? Interesting.

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