matplotlib / ipympl

Matplotlib Jupyter Integration
https://matplotlib.org/ipympl/
BSD 3-Clause "New" or "Revised" License
1.57k stars 226 forks source link

Include interactive_plot function from ipympl-interactions #251

Closed ianhi closed 4 years ago

ianhi commented 4 years ago

Following a discussion on gitter: https://gitter.im/jupyter-widgets/Lobby?at=5f223f6efe6ecd288882102f

In a separate library (https://github.com/ianhi/ipympl-interactions#ipympl-interactions) I have written an ipympl-aware interact function that removes the need to write boilerplate updating that connects an ipywidgets slider to the contents of an ipympl figure. Using the standard interact function you are responsible for:

  1. Defining the function to plot f(x,...) => y
  2. Handling the plotting logic (plt.plot, fig.cla, ax.set_ylim, etc)

In contrast, with the interactive_plot function you only need provide f(x, ...) => y and the plotting and updating boilerplate are handled for you.

Given that this function is specific to the ipympl backend what are the feelings on including in this repo? It could for example live in ipympl/interactions.py.

If the feeling is that it should live here then it would be good to get some input on the remaining improvements I envisioned for it:

It would also be good to create a 2D version: https://github.com/ianhi/ipympl-interactions/issues/15

ping: @martinRenou @tacaswell @thomasaarholt

ianhi commented 4 years ago

and a fourth improvement: https://github.com/ianhi/ipympl-interactions/issues/26

Also so there's less clicking through to do here is a comparison of the methods of plotting interactivity: plain interact

fig, ax = plt.subplots()
x = np.linspace(0,6,100)
beta = np.linspace(0,5*np.pi)
slider =  widgets.SelectionSlider(options = [("{:.2f}".format(i), i) for i in beta],description='tau')
def f(x, beta):
    ax.cla()
    ax.plot(x, np.sin(x*4+beta))
    fig.canvas.draw_idle()
interact(f,x=widgets.fixed(x),beta=slider)

Manual interact I prefer this over the former because it allows the function f to be useful for other things. This is basically what the third example automates.

plt.ioff(); fig, ax = plt.subplots(); plt.ion()
x = np.linspace(0,6,100)
beta = np.linspace(0,5*np.pi)
def f(x, beta):
    return np.sin(x*4+beta)
line = ax.plot(x, f(x, beta[0]))[0]
slider =  widgets.SelectionSlider(options = [("{:.2f}".format(i), i) for i in beta],description='tau')
def update_plot(change):
    line.set_data(x, f(x, slider.value))
    fig.canvas.draw_idle()
slider.observe(update_plot, names='value')
display(slider)
display(fig.canvas)

proposed solution

x = np.linspace(0,6,100)
beta = np.linspace(0,5*np.pi)
def f(x, beta):
    return np.sin(x*4+beta)
interactive_plot(f, x=x, beta=beta)

and a gif:

which also comes with some extra niceties like different options for handling how the y axis is re-limmed (i.e. does it stretch? does it autoscale every time, is it fixed?), automatically setting the legend attributes, and being able to directly pass numpy arrays as arguments.

ianhi commented 4 years ago

Two counterpoints to the above:

  1. If this backend is ever re-incorporated to matplotlib-core then these functions may not have a great home
  2. Turns out the interact functions do not need to depend on the ipympl backend (https://github.com/ianhi/ipympl-interactions/commit/b35a216fc58c1ed58928f207870b653a49155d9c)
    • Though they seem to have much better performance with ipympl than qt5

qt5

Given those two points I now think it probably make more sense to keep interactive_plot separate from ipympl. Though I remain happy to donate it if people think that it would be more appropriate for it to live here. In that absence of any such complaints I am going to rename my repo to mpl-interactions, restructure the code into jupyter and generic submodules and publish it on pypi.

ianhi commented 4 years ago

I was indeed swayed by my own counterpoints. It's now available on pypi via pip install mpl_interactions. But I am making sure to hype up ipympl in the nascent documentation :)

link for convenience: https://github.com/ianhi/mpl-interactions