Search code examples
pythonmatplotlibjupyteripywidgets

refresh matplotlib in Jupyter when updating with ipywidget


I want to draw a line in a Jupyter notebook, which can be moved using an ipywidget slider. I also want to have the mouse coordinates displayed, for which I'm using %matplotlib notebook. Here is what I have so far :

%matplotlib notebook
from ipywidgets import interact


fig, ax = plt.subplots()

@interact(n=(-200, 0))
def show(n):
    # fig.clear() #doesn't show anything
    y = -n+x
    ax.plot(x, y)
    
    plt.show()

When moving the line using the slider, the plot doesn't refresh, all previous positions of the line remain visible: enter image description here

I tried to refresh using fig.clear(), but then noting shows.

How can I solve this?


Solution

  • I have an extensive answer about this here: Matplotlib figure is not updating with ipywidgets slider

    but the short of my recommendations are:

    1. use ipympl %matplotlib ipympl instead of notebook as this will play nicer with ipywidgets
    2. Use mpl-interactions to handle making plots controlled by sliders.
      • It will do the optimal thing of using set_data for you rather than clearing and replotting the lines.
      • It also interprets the shorthand for numbers in a way that (I think) makes more sense when making plots (e.g. using linspace instead of arange) see https://mpl-interactions.readthedocs.io/en/stable/comparison.html for more details.

    So for your example I recommend doing:

    install libraries

    pip install ipympl mpl-interactions
    
    %matplotlib ipympl
    from ipywidgets import interact
    import matplotlib.pyplot as plt
    from mpl_interactions import ipyplot as iplt
    
    x = np.linspace(0,100)
    fig, ax = plt.subplots()
    
    def y(x, n):
        return x - n
    ctrls = iplt.plot(x, y, n=(-200,0))
    

    it got a bit longer because I added the imports you left out of your question and also defined x.

    Which gives you this:

    gif of mouse interacting with slider and line updates

    That said if you don't want to use those I think what you want is ax.cla() I think when you do fig.clear you are also removing the axes which is why nothing shows up.

    %matplotlib notebook
    from ipywidgets import interact
    
    
    fig, ax = plt.subplots()
    
    @interact(n=(-200, 0))
    def show(n):
        y = -n+x
        ax.cla()
        ax.plot(x, y)
    
        plt.show()