69

I am trying to generate an interactive plot that depends on widgets. The problem I have is that when I change parameters using the slider, a new plot is done after the previous one, instead I would expect only one plot changing according to the parameters.

Example:

from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets

import matplotlib.pyplot as plt
%matplotlib inline

import numpy as np

def plot_func(freq):
    x = np.linspace(0, 2*np.pi)
    y = np.sin(x * freq)
    plt.plot(x, y)

interact(plot_func, freq = widgets.FloatSlider(value=7.5,
                                               min=1,
                                               max=5.0,
                                               step=0.5))

After moving the slider to 4.0, I have:

enter image description here

while I just want one figure to change as I move the slider. How can I achieve this?

(I am using Python 2.7, matplotlib 2.0 and I have just updated notebook and jupyter to the latest version. let me know if further info is needed.)

3 Answers 3

76

As you want to change the figure, instead of creating a new one, may I suggest the following way:

  1. Use an interactive backend; %matplotlib notebook
  2. Update the line in the plot, instead of drawing new ones.

So the code could look something like this:

%matplotlib notebook
from ipywidgets import *
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
line, = ax.plot(x, np.sin(x))

def update(w = 1.0):
    line.set_ydata(np.sin(w * x))
    fig.canvas.draw_idle()

interact(update);

enter image description here

Alternatively you may use plt.show() as in this answer.

Sign up to request clarification or add additional context in comments.

6 Comments

Why is there a comma after line ? in line line, = ax.plot(x, np.sin(x))
@ImportanceOfBeingErnest As soon as I click the widget and try to slide it, it disappears. Any idea why? Jupyter version info: The version of the notebook server is 4.3.1 and is running on Python 3.6.6, IPython 5.1.0
@vestland I just tested with Python 3.6.6, jupyter core 4.4.0, notebook server 5.6.0, jupyter_client 5.2.3, jupyter_console 5.2.0, Ipython 6.5.0, ipywidgets 7.4.2 (not sure which is relevant here), and it works as expected.
For me, fig.canvas.draw_idle() works better as rapid parameter changes do not leave ghost plots.
|
8

For completion, here is an answer that makes use of more than one slider bar and sets the default parameters as well as the interval lengths.

%matplotlib notebook
from ipywidgets import *
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-10, 10,100)

def f(x, A, B, C):
    return A*x**2 + B*x + C

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
line, = ax.plot(x, f(x, A=1, B=1, C=1))

def update(A = 1, B = 0, C = 0):
    line.set_ydata(f(x,A,B,C))
    fig.canvas.draw_idle()
    
interact(update, A = (-4,4,0.1), B = (-4,4,0.1), C = (-4,4,0.1));

enter image description here

2 Comments

How about updating a scatter plot?
Yes, I'd have that question too...
3

This is an issue (?) introduced in the last version of jupyter and/or ipywidgets. One workaround I found was to add the line plt.show() at the end of plot_func.

3 Comments

This will create a new figure for every silder update, right? So, it seems to be the most inefficient of all solutions?
@ImportanceOfBeingErnest Creating a new figure for every slider update is clearly not efficient. Your approach is (+1). I only added this answer as it resolves the issue to the (inefficient) approach of the OP. TBH, I do find this inefficient approach more convenient for a quick and dirty view of a function's properties.
I see, maybe you add that argument to the answer?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.