1

As the title describe, my plot disappear when the option blitting is On. I explain a bit further : I am making animations to diplay the solution of some differential equations and the code will become more and more heavy. I need the blitting option to have a smooth animation but I also need a button to start/stop the animation. I am using FuncAnimation. The thing is when I stop the animation with the "myAnimation.event_source.stop()" command, the plot disappear as long as the animation is on pause and comes back animated when I restart with "myAnimation.event_source.start()". I've tried to find the issue in matplotlib documentation : https://matplotlib.org/3.2.1/_modules/matplotlib/animation.html#FuncAnimation however this is too much for me to corner what could be modified. Do you have an idea how to solve my problem ? Code : (funcanimation part and stop button part, A is a matrice for my specific code)

def update(self,i):
    self.myAnimation.event_source.interval = self.Constants['interv']
    self.k = i%10
    self.n[:,self.k] = self.A*self.n[:,self.k-1]
    self.p.set_ydata(self.n[:,self.k])
    return self.p,
def _stopp(self,event):
    if self.Launch:
        self.myAnimation = aniamtion.FuncAnimation(self.fig, self.update, frames=range(1,self.Constants['N']), interval=self.Constants['interv'],repeat=False)
        self.Launch=False
    else:
        if self.anim_running:
            self.myAnimation.event_source.stop()
            self.anim_running = False 
        else:
            self.myAnimation.event_source.start()
            self.anim_running = True
def add_button(self,left,name):
    axbutton=plt.axes([left,0.88, 0.12, 0.05])
    bstop = Button(axbutton, name)
    self.Launch=True
    self.Button.append(bstop)
1
  • When stopped the animation disconnect from all the events including the callback "self.event_source.remove_callback(self._step) self.event_source = None" The problem might be that the cache used to blit is lost there and that the fig update itself and therefore find nothing to draw. I can't find for the moment where I could change this behaviour. Commented Jun 18, 2020 at 15:10

1 Answer 1

1

The kind developpers of Matplotlib answered me. "https://matplotlib.org/3.3.0/tutorials/advanced/blitting.html#sphx-glr-tutorials-advanced-blitting-py is probably of use here.

The issue is that when using bliting, we mark the artists as "animated" via obj.set_animated(True) which means they are excluded from the normal draw process (so that you can get a "clean" background). In FuncAnimation we enable this (just to be on the safe side) to prevent artifacts where a previous data is "stuck" in the animation. When you pause the animation you do not un-set this state so when the figure redraws it skips rendering the plots (because it is the problem of what ever is managing the animation to do the render + blit)."

Initial code :

import matplotlib.pyplot as plt
import matplotlib.animation as animation

class plotanimation:
    def __init__(self):
        self.fig,self.ax=plt.subplots()
        self.x=np.linspace(-10,10,1000)
        self.N=200
        self.interv=50
        self.n0=1./(4*np.pi*2e-4*0.1)**0.5 * np.exp(-self.x**2/(4*2e-4*0.1))  
        self.p,=self.ax.plot(self.x,self.n0)
        self.anim_running = True
        self.Myanimation=animation.FuncAnimation(self.fig, self.update,frames=self.N,interval=self.interv,blit=True)
    def update(self,i):
        self.n0+=i/100
        self.p.set_ydata(self.n0)
        return self.p,
    def animate(self):
        pause_ax = self.fig.add_axes((0.7, 0.025, 0.1, 0.04))
        pause_button = Button(pause_ax, 'pause', hovercolor='0.975')
        pause_button.on_clicked(self._pause)
        plt.show()
    def _pause(self, event):
        if self.anim_running:
            self.Myanimation.event_source.stop()
            self.anim_running = False
        else:
            self.Myanimation.event_source.start()
            self.anim_running = True


animated_plot = plotanimation()
animated_plot.animate() 

Solution (notice the self.p.set_animated(False/True)):

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.widgets import Button


class PlotAnimation:
    def __init__(self):
        self.fig, self.ax = plt.subplots()
        self.x = np.linspace(-10, 10, 1000)
        self.N = 200
        self.interv = 50
        self.n0 = (
            1.0
            / (4 * np.pi * 2e-4 * 0.1) ** 0.5
            * np.exp(-self.x ** 2 / (4 * 2e-4 * 0.1))
        )
        (self.p,) = self.ax.plot(self.x, self.n0)
        self.anim_running = True
        self.Myanimation = animation.FuncAnimation(
            self.fig, self.update, frames=self.N, interval=self.interv, blit=True
        )

    def update(self, i):
        self.n0 += i / 100 % 5
        self.p.set_ydata(self.n0 % 20)
        return (self.p,)

    def animate(self):
        pause_ax = self.fig.add_axes((0.7, 0.025, 0.1, 0.04))
        pause_button = Button(pause_ax, "pause", hovercolor="0.975")
        pause_button.on_clicked(self._pause)
        plt.show()

    def _pause(self, event):
        if self.anim_running:
            self.Myanimation.event_source.stop()
            self.p.set_animated(False)
            self.anim_running = False
            self.fig.canvas.draw_idle()
        else:
            self.p.set_animated(True)
            self.Myanimation.event_source.start()
            self.anim_running = True


animated_plot = PlotAnimation()
animated_plot.animate()
Sign up to request clarification or add additional context in comments.

Comments

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.