ipympl
ipympl copied to clipboard
ipympl not working nicely with interact
Trying to follow some simple examples of Jupyter widgets with matplotlib, but I'm having issues when using the ipympl backend. The first update to a plot produces a second plot (overplotted), and the second update just erases the figure window altogether. This does not happen when using inline.
Here's some simple code to reproduce the issue:
%matplotlib ipympl
import matplotlib.pyplot as plt
from ipywidgets import interact
def f(n):
plt.plot([0,1,2],[0,1,n])
plt.show()
interact(f,n=(0,10));
If I use inline, this will update the line plot. With ipympl it fails.
I am using ipympl 0.1.0 from Anaconda, together will other packages:
ipywidgets 7.0.0 py36_intel_0 [intel] intel
ipympl 0.1.0 py36_1 conda-forge
matplotlib 2.0.2 np113py36_intel_1 [intel] intel
ipython 6.1.0 py36_intel_0 [intel] intel
jupyter 1.0.0 py36_intel_5 [intel] intel
jupyter_client 5.1.0 py36_intel_0 [intel] intel
jupyter_console 5.1.0 py36_intel_0 [intel] intel
jupyter_core 4.3.0 py36_intel_1 [intel] intel
On a second look, this seems to happen because this small example (and nearly all in the ipywidgets examples) are just calling a new plot all the time. Catching the objects and using methods like ax.set_ydata seems to get it working, and is probably better code.
My method for this is to generate the figure and axis objects outside interact, and then clearing the axes and redrawing the plot. It is slightly more convenient then generating the line objects first and then updating them. The interactive mode has to be activated for this to work (plt.ion()), in the previous iteration (%matplotlib notebook), it seems the interactive mode was enabled by default.
Maybe the example notebook could contain the canonical method for plotting with interact?
import ipympl
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact
plt.ion()
fig, ax = plt.subplots()
fig.show()
@interact
def plot_me(x:(0.1, 5)):
ax.clear()
ax.plot(np.sin(np.linspace(0, x)))
Great idea to include an example. The interact decorator is really designed for output that is regenerated every time controls change, so it's awkward to use it with ipympl. ipympl works better if it is shown once and then updated when controls change, which is a different approach.
I think it would be great to have an easier way to set up a set of controls and trigger a side effect like updating an ipympl plot, sort of like interactive, without having an associated output widget.
Not sure if this is related, but I recently tried the Lorentz-attactor example from here: https://github.com/jupyter-widgets/ipywidgets/blob/master/docs/source/examples/Lorenz%20Differential%20Equations.ipynb
This works fine in Jupyter notebook (i.e. shows both the slider widgets and the plot).
However the slider widgets do not show up in Jupyter lab (this happens both with %matplotlib inline and %matplotlib ipympl):

Is there a recommend fix for this issue?
@RemiLehe, this issue with Jupyterlab should be fixed if you update the @jupyter-widgets/jupyterlab-manager extension.
You probably have a version from before the beta?
Thanks for the prompt answer!
I now see that I had ipywidgets 7.1.0 instead of ipywidgets 7.1.2. Upgrading solved my issue.
Thanks for your help!
Edit: Confusion, see below.
I tried the original code without the %matplotlib xxx and plt.show():
import matplotlib.pyplot as plt
from ipywidgets import interact
def f(n):
plt.plot([0,1,2],[0,1,n])
interact(f,n=(0,10));
And it almost works perfectly: first the plot is not shown, but the first update shows it and from there it's OK. I'm using latest JupyterLab and npm extensions.
In general, I feel that it's difficult to know when do we need %matplotlib inline or nothing, because in recent Jupyter versions I've noticed it's not necessary, but I cannot find the corresponding change in notebook, ipython or matplotlib.
Edit: My confusion is only related to inline, I understood that ipympl is the new interactive backend
@Juanlu001 I do not get a plot without invoking the magic commands (%matplotlib ipympl / inline). Are you certain that you get this, especially if you restart the kernel first?
@thomasaarholt you're right, I double checked and one still needs either a %matplotlib inline/ipympl or a plt.show(). I'm editing my comment, sorry for the confusion.
I think it would be great to have an easier way to set up a set of controls and trigger a side effect like updating an ipympl plot, sort of like interactive, without having an associated output widget.
I implemented just this in https://github.com/ianhi/mpl-interactions. It has a function interactive_plot that uses set_data under the hood and otherwise behaves very similarly to the ipywidgets interactive function. (other difference is that tuples are passed to linspace rather than arange)
I had also proposed incorporating that function into ipympl in https://github.com/matplotlib/ipympl/issues/251 but currently have settled on keeping in a separate library so I can more easily change(accidentally break...) things. It's on pypi as well now for convenience.
p.s. I feel deeply weird posting the above as it feels somewhat self promotional. But I'm trying to get over that feeling so that I can effectively share the solution I found to the problem we are all suffering. In that spirit does it it make sense to include an example using mpl-interactions in the ipympl examples? Also, if anyone tries it out I'd love to hear your feedback on how to improve it.