Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
186 views
in Technique[技术] by (71.8m points)

python - FuncAnimation doesn't show outside of function

I gave an answer on this thread, talking about fading point on matplotlib. And I got curious about ImportanceOfBeingErnest's answer. So I tried to play around with his code.

First, here is my code.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation
from matplotlib.colors import LinearSegmentedColormap

def get_new_vals():
    x = 0
    y = 0
    while True:
        if x >= .9:
            x = 0
            y = 0
        x += .1
        y += .1
        yield x, y

def update(t, x_vals, y_vals, intensity, scatter, gen):
    #   Get intermediate points
    new_xvals, new_yvals = gen.next()
    x_vals.extend([new_xvals])
    y_vals.extend([new_yvals])

    #   Put new values in your plot
    scatter.set_offsets(np.c_[x_vals, y_vals])

    #   Calculate new color values
    for index in range(len(intensity)):
        if intensity[index] < .1:
            intensity[index] = 0
        intensity[index] *= .6
    intensity.extend(1 for _ in xrange(len([new_xvals])))

    intens_dup = np.array(intensity)

    """
    intensity = np.concatenate((np.array(intensity) * .6, np.ones(len(new_xvals))))
    """
    scatter.set_array(intens_dup)

    # Set title
    axis.set_title('Time: %0.3f' % t)

def anim_random_points(fig, axis):
    x_vals = []
    y_vals = []
    intensity = []
    iterations = 100

    colors = [ [0, 0, 1, 0], [0, 0, 1, 0.5], [0, 0.2, 0.4, 1] ]
    cmap = LinearSegmentedColormap.from_list("", colors)
    scatter = axis.scatter(x_vals, y_vals, c=[], cmap=cmap, vmin=0, vmax=1)

    gen_values = get_new_vals()

    ani = matplotlib.animation.FuncAnimation(fig, update, frames=iterations,
        interval=50, fargs=(x_vals, y_vals, intensity, scatter, gen_values),
        repeat=False)

    #   Position 1 for plt.show()
    plt.show()

if __name__ == '__main__':

    fig, axis = plt.subplots()
    axis.set_xlabel('X Axis', size = 12)
    axis.set_ylabel('Y Axis', size = 12)
    axis.axis([0,1,0,1])

    anim_random_points(fig, axis)

    #   Position 2 for plt.show()
    # plt.show()

I, then, noticed an odd thing. At least for me. Notice the Position 1 and Position 2 (at the end of code). The position 1 is placed just after the animation function, the other one is placed just after code-wise, since the function ends after position 1 and therefore goes to position 2.

Since FuncAnimation requires the figure to run the animation on, I am wondering why the plt.show() works on Position 1, but not on Position 2.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The matplotlib documentation states about FuncAnimation

It is critical to keep a reference to the instance object. The animation is advanced by a timer (typically from the host GUI framework) which the Animation object holds the only reference to. If you do not hold a reference to the Animation object, it (and hence the timers), will be garbage collected which will stop the animation.

If you put plt.show() outside of the anim_random_points function, the variable ani, which holds the reference to the animation, will be garbage collected and there will be no animation to be shown any more.

The solution for that case would be to return the animation from that function

def anim_random_points(fig, axis):
    # ...
    ani = matplotlib.animation.FuncAnimation(...)
    return ani

if __name__ == '__main__':
    # ...
    ani = anim_random_points(...)
    plt.show()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...