Skip to content

Plot disappear when blit is on #17685

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Luluser opened this issue Jun 19, 2020 · 4 comments
Closed

Plot disappear when blit is on #17685

Luluser opened this issue Jun 19, 2020 · 4 comments

Comments

@Luluser
Copy link

Luluser commented Jun 19, 2020

Already posted on stackoverflow but here should be more appropriate.

Bug report

Bug summary

First, good morning.
As the title describes, my plot disappears when the blitting option is on. I explain a bit further : I am making animations to display the solution of some differential equations and the code will become more and more heavy. I need the blitting option to have smooth animations
and not to "render" the widgets everytime 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 linked to a widget button, the plot disappears (in some cases the moment my mouse cursor gets out of the pause button, some cases as soon as I press the button). The ax stays empty as long as the animation is on pause and the plot comes back animated when I restart with "myAnimation.event_source.start()".
python_2020-06-19_10-04-11
Code for reproduction
A mock version of the code that is not the code I'm trying to write but simplifies the computations and makes it more readable.

import numpy as np
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()
# If applicable, paste the console output here
#
#

Expected outcome

The paused plot on the fig. Not an empty ax.

Matplotlib version

  • Operating system: W10
  • Matplotlib version: (3.1.2)
  • Matplotlib backend : TkAgg
  • Python version: v3.8.1:1b293b6
  • Jupyter version (if applicable): None
  • Other libraries: Numpy, scipy

Matplotlib was installed with pip. Conda is not installed.
Thank you a lot.

@tacaswell
Copy link
Member

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).

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()

works as expected.

I really like this example! This is probably something that should be generalized and added to the Animation classes.

@Luluser
Copy link
Author

Luluser commented Jun 19, 2020

Thank you a lot for your solution, this is great help ! I had never found this page during my research, maybe you should attach a link on the doc page https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.animation.FuncAnimation.html .

Glad to read, feel free to use it !

Also I have posted a logarithmic slider solution on stackoverflow (2nd answer to the question) : https://stackoverflow.com/questions/39960791/logarithmic-slider-with-matplotlib/62326375#62326375
I think it would be great to have logarithmic sliders in matplotlib (as well as integer sliders, it's easy to make one but it often leads to rounding errors), I've used as much linear as log_10 sliders to be honest. I have feedback that my solution has a problem with the argument "orientation" that is not well recognized, maybe because I have not used an init function, I am not sure.
Well again feel free to use it the way you want and to generalize to more log base if you like my recommendation.

Thanks again.

@tacaswell
Copy link
Member

@Luluser Can you open a PR with the text in the FuncAnimation docs that would have saved you and a PR adding the SliderLog?

@tacaswell
Copy link
Member

and that link went live last night (that text was merged as part of the 3.3.0 release of which we just tagged RC1), it was just very good timing ;)

I'm going to close this as resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants