Mr. W.
Mr. W.

Reputation: 369

Is it possible to speed up interactive IPython Notebook plots by not generating new figures every time?

Every example I've seen of using widgets for interactive matplotlib plots in the notebook do something like this (adapted from here):

%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt
from IPython.html.widgets import interact
from IPython.display import display

def sigmoid_demo(a=5,b=1):
    x = np.linspace(0,10,256)
    s = 1/(1+np.exp(-(x-a)/(b+0.1))) # +0.1 to avoid dividing by 0
    sn = 100.0*(s-min(s))/(max(s)-min(s)) # normalize sigmoid to 0-100

    # Does this have to be in this function?
    fig, ax = plt.subplots(figsize=(24,6))

    ax.set_xticks([])
    ax.set_yticks([])
    plt.plot(x,sn,lw=2,color='black')
    plt.xlim(x.min(), x.max())

w=interact(sigmoid_demo,a=5,b=1)

I suspect that the responsiveness of the plot could be sped up hugely if you didn't have to create a brand new figure with plt.subplots() or plt.figure() each time a widget was adjusted.

I've tried a few things to move figure creation outside of the function being called by interact() but nothing has worked.

Upvotes: 6

Views: 1960

Answers (1)

tacaswell
tacaswell

Reputation: 87486

Some setup:

%matplotlib notebook
import matplotlib.pyplot as plt
from IPython.html.widgets import interactive
from IPython.display import display
import numpy as np

Create your objects:

fig, ax = plt.subplots()
ax.set_xlim(0, .25)
ax.set_ylim(-2.5, 2.5)
ax.set_title('beat frequencies')
lnA, = ax.plot([], [], color='r', label='A')
lnB, = ax.plot([], [], color='purple', label='B')
lnsum, = ax.plot([], [], color='k', label='signal')
ax.legend()
max_time = 3
rate = 8000
times = np.linspace(0,max_time,rate*max_time)

def beat_freq(f1=220.0, f2=224.0):

    A = np.sin(2*np.pi*f1*times)
    B = np.sin(2*np.pi*f2*times)
    sig = A + B

    lnA.set_data(times, A)
    lnB.set_data(times, B)
    lnsum.set_data(times, sig)

    plt.draw()

beat_freq(0, 0)

and the interactive (which I think needs to go in it's own cell)

interactive(beat_freq, f1=(200.0,300.0), f2=(200.0,300.0))

You can also poke at the objects from a different cell:

ax.set_xlim(0, .05)
ax.set_ylim(-2, 2)
plt.draw()

or

lnB.set_color('g')
ax.legend()
plt.draw()

Upvotes: 6

Related Questions