Python Several problems of produce GIF by using animation.FuncAnimation - python

I encountered several problems when I was trying to produce a GIF by using animation function in Python.
Here is my code:
import matplotlib.pyplot as plt
import random
import matplotlib.animation as animation
xdata = []
ydata = []
fig, ax = plt.subplots()
line, = ax.plot(xdata, ydata, marker='o', markeredgewidth=9)
n = -1
def data_gen():
global n
while True:
xdata.clear()
ydata.clear()
for i in range(3):
xdata.append(random.randint(0, 10))
ydata.append(random.randint(0, 10))
n += 1
print('The', n, 'generation')
yield xdata, ydata
def init():
plt.grid()
line.set_linestyle('None')
ax.set_xlim(0, 20)
ax.set_ylim(0, 20)
return line,
def animate(data):
line.set_data(data)
print('data', data)
return line,
ani = animation.FuncAnimation(fig=fig, func=animate, frames=data_gen, init_func=init, interval=200, blit=False)
ani.save('clear list.gif', writer='imagemagick')
plt.show()
Problem 1: There has been a pause (about 10 seconds) since the code started running, in the stage of 0–pause, the GIF can be saved, however, there is a black flash on saved GIF.
Problem 2: At the stage start–pause, I can not see the plot on the screen, after this pause, the plot appeared, the program goes into the normal stage.
Problem 3: I put the code plt.grid() in the function init. When the code is running, I cannot see grid on the plot, however, grid can be seen on the saved plot, why? If I add another code plt.grid() before the last code plt.show(), at this time, the grid will be shown on the plot.
Can someone tell me why this happens?
The code runs in:
IDE: Pycharm 2019.3.4 Professional Edition
Interpreter: Python 3.7
OS: Windows 10
Figure captured when the black shadow appears:

Related

Matplotlib and Celluloid show strange behavior on Jupyter notebook

I am trying to animate the results of a simulation performed with Python. To do so, I'm using matplotlib to generate the frames of the animation and then I collect them with the Camera class from celluloid library. The code that generates the animation is the following:
fig = plt.figure()
ax = plt.gca()
ax.set_aspect('equal')
camera = Camera(fig)
for i in range(result.t.size):
if i % 10 == 0:
x = result.y[0, i]
y = result.y[1, i]
plt.scatter(x, y, s = 100, c = 'red')
plt.xlim(-3, 3)
plt.ylim(-3, 3)
plt.grid()
camera.snap()
animation = camera.animate(blit = False, interval = 10)
HTML(animation.to_html5_video())
The last part that generates an HTML5 video allows for watching the animation in a Jupyter notebook on the web. However, I get the following output:
The first output is the corresponding animation, which is working good. The second is just a static empty plot. So I have two questions:
Where does the second plot come from and how can I remove it?
The animation is not showing any grid, though I requested it via plt.grid() on each frame. Why is that happening?
Thanks in advance for any help.

plot not showing properly using matplotlib in jupyter notebook

I am following a tutorial to plot in real time using python, for some reason my plot is not showing fully. I have no idea why because it is only 3 lines of code and they are exactly the same as the tutorial!
I want to run the code below but as expected I can see it moving but I can't see the entire graph. What is happening here?!
x = []
y = []
i = 0
plt.show()
while True:
x.append(i)
y.append(C3[i])
ax.plot(x, y, color='b')
fig.canvas.draw()
ax.set_xlim(left=max(0, i-50), right=i+50)
time.sleep(0.1)
i += 1
[edit]
Whenever I run
fig = plt.figure()
ax = fig.add_subplot(111)
fig.show()
I get
[IPKernelApp] WARNING | No such comm: bba1ac5ea0484ec7a6446924a4ff37a0
In my terminal

How to display an animated graph using Matplotlib.animation.FuncAnimation in PyCharm on macOS?

I am trying to use matplotlib.animation.FuncAnimation to display an animated graph (not through the terminal). I am using PyCharm Professional 2019.2 on macOS 10.14.6
I haven't found any solutions that would work for PyCharm on macOS.
I've tried a couple of things:
Using an alternative to FuncAnimate Animating with matplotlib without animation function
Adding
import matplotlib
matplotlib.use("TkAgg")
as suggested in Matplotlib animation not displaying in PyCharm. This causes my PyCharm to crash and brings me to the macOS login screen.
import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# Create figure for plotting
figure = plt.figure()
axis = figure.add_subplot(1, 1, 1)
xs = []
ys = []
# This function is called periodically from FuncAnimation
def animate(i, xs, ys):
# Add x and y to lists
xs.append(dt.datetime.now().strftime('%H:%M:%S.%f'))
ys.append(dt.datetime.now().strftime('%H:%M:%S.%f'))
# Limit x and y lists to 20 items
xs = xs[-20:]
ys = ys[-20:]
# Draw x and y lists
axis.clear()
axis.plot(xs, ys)
# Format plot
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.title('Data over Time')
plt.ylabel('Data')
# Set up plot to call animate() function periodically
ani = animation.FuncAnimation(figure, animate, fargs=(xs, ys), interval=1000)
plt.show()
This code just simply graphs a linear function based on time (both axes)
When compiling through the terminal, the graph is working flawlessly. PyCharm for some reason doesn't want to graph it. Any solutions for macOS?

How to save an animation as gif and show it at the same time?

I wrote a code that generates and shows a matplotlib animation. I am also able to save the animation as gif.
However when I do these two actions sequentially (first saving the gif, and then showing the animation, because plt.show() is a blocking call, the shown animation doesn't start from the beginning; it seems it's first used by the gif saving routine.
My idea is to show the animation in the window using plt.show(), and save the same animation as a gif to disk (before, or ideally during the animation). I've tried to solve this using Threads or creating new figure, but I wasn't able to pull it off - the shown animation was always modified by the saving routine. Also, putting plt.show into a thread didn't work (because it handles drawing to screen, I suppose, so it needs to be in a main thread).
Here's the code I'm using:
import matplotlib.pyplot as plt
from matplotlib import animation
from visualizer import visualize
import updater
def run(k, update_func=updater.uniform,
steps=1000, vis_steps=50,
alpha_init=0.3, alpha_const=100, alpha_speed=0.95,
diameter_init=3, diameter_const=1, diameter_speed=1,
xlim=(-1, 1), ylim=(-1, 1),
points_style='ro', lines_style='b-',
save_as_gif=False):
fig = plt.figure()
ax = fig.add_subplot(111, xlim=xlim, ylim=ylim)
global curr_alpha, curr_diameter, points, lines
points, = ax.plot([], [], points_style)
lines, = ax.plot([], [], lines_style)
curr_alpha = alpha_init
curr_diameter = diameter_init
def update_attributes(i):
global curr_alpha, curr_diameter
if i % alpha_const == 0:
curr_alpha *= alpha_speed
if i % diameter_const == 0:
curr_diameter *= diameter_speed
def init():
lines.set_data([], [])
points.set_data([], [])
def loop(i):
for j in range(vis_steps):
update_func(k, curr_alpha=curr_alpha, curr_diameter=curr_diameter)
update_attributes(i * vis_steps + j)
visualize(k, points, lines)
return points, lines
anim = animation.FuncAnimation(fig, loop, init_func=init, frames=steps // vis_steps, interval=1, repeat=False)
if save_as_gif:
anim.save('gifs/%s.gif' % save_as_gif, writer='imagemagick')
plt.show()

MatPlotLib's ion() and draw() not working

I am trying to plot figures in real time using a for loop. I have the following simple code:
import matplotlib.pyplot as plt
plt.ion()
plt.figure()
for i in range(100):
plt.plot([i], [i], 'o')
plt.draw()
plt.pause(0.0001)
This code does not show the figure until it has finished computing, which I don't want. I want it to draw the figure after every loop. If I replace plt.draw() with plt.show, multiple figures are output in real time, but I want them all to appear in the same figure. Any ideas?
EDIT:
I downloaded PyCharm with Anaconda and everything works fine. I guess it's a problem with Spyder since I tried a few different versions of it without success. If anyone has any clue what is causing this problem in Spyder, let me know!
Adapted for your case from : Python realtime plotting
import matplotlib.pyplot as plt
import numpy as np
import time
fig = plt.figure()
ax = fig.add_subplot(111)
# some X and Y data
x = [0]
y = [0]
li, = ax.plot(x, y,'o')
# draw and show it
fig.canvas.draw()
plt.show(block=False)
# loop to update the data
for i in range(100):
try:
x.append(i)
y.append(i)
# set the new data
li.set_xdata(x)
li.set_ydata(y)
ax.relim()
ax.autoscale_view(True,True,True)
fig.canvas.draw()
time.sleep(0.01)
except KeyboardInterrupt:
plt.close('all')
break
This solution example has worked for me on multiple machines. Try adjusting plt.pause(...)
import matplotlib.pyplot as plt
import numpy as np
F = lambda x: np.sin(2*x)
plt.ion()
x = np.linspace(0, 1, 200)
plt.plot(x, F(x))
for i in range(100):
if 'ax' in globals(): ax.remove()
newx = np.random.choice(x, size = 10)
ax = plt.scatter(newx, F(newx))
plt.pause(0.05)
plt.ioff()
plt.show()
Hey I was having the same problem, I checked other questions and my issue was solved when I plugged a pause into my solution. Here's some example code that worked for me.
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
x = np.arange(0, 4*np.pi, 0.1)
y = [np.sin(i) for i in x]
plt.plot(x, y, 'g-', linewidth=1.5, markersize=4)
plt.pause(0.0001)
plt.plot(x, [i**2 for i in y], 'g-', linewidth=1.5, markersize=4)
plt.pause(0.0001)
plt.plot(x, [i**2*i+0.25 for i in y], 'r-', linewidth=1.5, markersize=4)
plt.pause(0.0001)
The solution was posted here:
Matplotlib ion() and subprocesses
The problem - and the solution - is highly dependent on the plot.draw() function within the Python environment and back end, and may even vary in different product releases. It manifests itself in different ways depending on the environment. The problem shows up in many places on stackoverflow with some solutions working for some people and not for others.
The gold standard on my Windows laptop is running the Python from the command line - no IDE, just plain vanilla Python3. draw() as shown in the example always works fine there.
If I try it in Jupyter notebook on the same machine, no amount of draw(), plot.pause(), plot.show(), or any other suggestion works. I tried %matplotlib with notebook, widget and ipympl. Nothing gets drawn until complete end of cell code execution.
Some other sources on stackoverflow suggested using figure.canvas.flush_events(). I had some success with that and investigated further.
The best solution turned out to be to run the draw() at the figure.canvas level instead of the axes or plot level.
You can get the figure by creating your plot with command:
fig, graph, = plt.subplots()
or, if you've already created the plot, as in the code at the top of the ticket, put the following outside the loop:
fig = plt.gcf() #get current figure
Inside the loop, instead of plt.draw(), use
fig.canvas.draw()
It's proven reliable in my Jupyter Notebook environment even when running multiple axes/plots across multiple figures. I can drop in sleep() statements and everything appears when expected.
Your mileage may vary.

Categories