Reputation: 201
I created an animated plot using FuncAnimation
from the Matplotlib Animation class, and I want to save it as a .gif file. When I run the script, the output looks normal, and looks like this (the animation works fine):
However, when I try to save the animated plot as a .gif file using ImageMagick or PillowWriter, the plot looks like the following graph:
The lines are clearly much thicker, and in general, just looks very bad. The problem is attributed to the points (the purple, and red circles). Thus it seems like the plot is writing over each frame (which I think is the case). I can avoid this by just getting rid of them all together. But I don't want to do that as it would be hard to see the lines.
Here is the code:
line, = ax.plot([], [], color = 'blue', lw=1)
line2, = ax.plot([], [], color = 'red', lw=1)
line3, = ax.plot([], [], color = 'purple', lw=1)
def animate(i):
line.set_data(x1[:i], y1[:i])
line2.set_data(x2[:i], y2[:i])
line3.set_data(x3[:i], y3[:i])
point1, = ax.plot(x1[i], y1[i], marker='.', color='blue')
point2, = ax.plot(x2[i], y2[i], marker='.', color='red')
point3, = ax.plot(x3[i], y3[i], marker='.', color='purple')
return line, line2, line3, point1, point2, point3,
ani = animation.FuncAnimation(fig, animate, interval=20, blit=True, repeat=False, frames=1000, save_count=1000)
ani.save("TLI.gif", writer='imagemagick',fps=60)
The arrays x1, y1, x2, y2, x3, y3
are all 1D arrays that contain the x, y coordinates.
So why is this happening? Why is it that the .gif file doesn't show what the plot shows when I run it directly? And also, how can I fix this?
I am also aware of this Stack Overflow question: matplotlib animation save is not obeying blit=True but it seems to work just fine in plt.show() which means the problem is definitely attributed to blitting. However, reading the answer of that question did not solve my problem because that only refers to ax.text
opposed to a regular point plotted via ax.plot
.
Upvotes: 13
Views: 28722
Reputation: 404
See if this works. I don't have Imagemagick so I used Pillow.
To prevent the animation showing stacked frames (i.e., dot traces), the trick is to clear the axes to refresh each frame. Then set xlim
and ylim
for each frame, and plot the incremental lines using ax.plot(x1[0:i], y1[0:i]...
To improve the image resolution, set the output dpi to a suitable value. I played around with it and settled on 300 to get sharp lines and axes lines/numbers.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter
import numpy as np
x1 = np.arange(0, -0.2, -0.002)
y1 = np.arange(0, -0.2, -0.002)
x2 = np.arange(3.9, 3.7, -0.002)
y2 = np.arange(0, 1, 0.01)
x3 = np.arange(0, 1.8, 0.018)
y3 = np.array(x3**2)
fig,ax = plt.subplots()
def animate(i):
ax.clear()
ax.set_xlim(-4,4)
ax.set_ylim(-4,4)
line, = ax.plot(x1[0:i], y1[0:i], color = 'blue', lw=1)
line2, = ax.plot(x2[0:i], y2[0:i], color = 'red', lw=1)
line3, = ax.plot(x3[0:i], y3[0:i], color = 'purple', lw=1)
point1, = ax.plot(x1[i], y1[i], marker='.', color='blue')
point2, = ax.plot(x2[i], y2[i], marker='.', color='red')
point3, = ax.plot(x3[i], y3[i], marker='.', color='purple')
return line, line2, line3, point1, point2, point3,
ani = FuncAnimation(fig, animate, interval=40, blit=True, repeat=True, frames=100)
ani.save("TLI.gif", dpi=300, writer=PillowWriter(fps=25))
Upvotes: 20