问题
I am trying to use widget events to make an interactive graph.
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import ipywidgets as widgets
def myplot(n):
x = np.linspace(-5, 5, 30)
y = x**n
fig, ax = plt.subplots(nrows=1, ncols=1);
ax.plot(x, y)
ax.set_xlabel('x')
ax.set_ylabel('y')
plt.show()
Interact works as expected (it changes the figure interactively):
widgets.interact(myplot, n=(0,5));
However the following snippet creates several figures that appear below as you interact with the slider.
n_widget = widgets.IntSlider(
value=2,
min=0,
max=5)
def on_value_change(change):
myplot(n=n_widget.value)
n_widget.observe(on_value_change)
display(n_widget)
Can I update the plot as if I were using widgets.interact()?
My current installation is with conda and Python 3.6 (windows machine).
ipywidgets 7.1.0
jupyter 1.0.0
jupyter_client 5.2.1
jupyter_console 5.2.0
jupyter_core 4.4.0
matplotlib 2.1.1
notebook 5.3.1
numpy 1.14.0
回答1:
Note that the below is a working solution for ipywidgets version < 7.0. For a solution with ipywidgets >= 7.0 see this GitHub issue.
While in many simple cases plt.show()
works nicely replacing the output of a cell, this is not always the case. When using interactive elements in Jupyter it is often more helpful to use IPython.display.display
.
Here you may not want to create a new plot for each interaction. Instead just setting new data to the plot is enough. Then you may autoscale the plot for the new data and display the figure. You may use IPython.display.clear_output
to clear the output once a new figure would be displayed. This ensures to have always a single plot present in the output cell, independent of the use of interact
or observe
.
def myplot(n):
line.set_ydata(x**n)
ax.relim()
ax.autoscale()
display(fig)
clear_output(wait=True)
Comlpete notebook:
# cell 1
%%capture
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import display, clear_output
import ipywidgets as widgets
fig, ax = plt.subplots(nrows=1, ncols=1);
x = np.linspace(-5, 5, 30)
y = x**0
line, = ax.plot(x, y)
ax.set_xlabel('x')
ax.set_ylabel('y')
def myplot(n):
line.set_ydata(x**n)
ax.relim()
ax.autoscale()
display(fig)
clear_output(wait=True)
#cell2
widgets.interact(myplot, n=(0,5));
#cell3
n_widget = widgets.IntSlider(
value=2,
min=0,
max=5)
def on_value_change(change):
myplot(n=n_widget.value)
n_widget.observe(on_value_change)
display(n_widget)
来源:https://stackoverflow.com/questions/48380967/interact-and-plotting-with-ipywidgets-events-produces-many-graphs