Matplotlib not animating azimuth unless I click on the plot - python

I am trying to animate the point of view of a scatter plot, that is coming from a sequence of data arrays. I am currently stuck because the animation runs only if I keep clicking on the plot. It seems to animate in the background with correct timing but only displaying when I click on it.
I tried other animation examples and they were ok, so I guess there must be some problem with my code. Thanks for the help.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
data = [np.random.random_sample((300, 3)) for _ in range(10)]
x, y, z = data[0][:, 0], data[0][:, 1], data[0][:, 2]
def update_pov(num):
ax.view_init(elev=10., azim=num % 360)
return graph,
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111, projection="3d")
graph = ax.scatter(x, y, z, color='orange')
ax.set_xlim3d(0, 1)
ax.set_ylim3d(0, 1)
ax.set_zlim3d(0, 1)
ani = animation.FuncAnimation(fig, update_pov, frames=200, interval=50, blit=False)
plt.show()

Related

Animate labels using FuncAnimation in Matplotlib

I am not able to make (animated) labels using FuncAnimation from matplotlib. Please find below a minimal code that I made. ax.annotate has no effect at all - the animation itself works though. What can I change to get animated labels/titles, which are different for each frame?
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
fig.clear()
steps = 10
data = np.random.rand(20,20,10)
imagelist = [data[:,:,i] for i in range(steps) ]
im = plt.imshow(imagelist[0], cmap='Greys', origin='lower', animated=True)
plt.colorbar(shrink=1, aspect=30, label='Counts')
# does not work
ax.annotate("Frame: %d " % steps,(0.09,0.92),xycoords ='figure fraction')
def updatefig(j):
im.set_array(imagelist[j])
return [im]
ani = animation.FuncAnimation(fig, updatefig, frames=range(steps), interval=200, blit=True)
plt.show()
Two problems overall:
The annotation text never gets updated in updatefig()
The canvas gets cleared+blitted, which wipes out annotations
Five steps to resolve:
Remove fig.clear() to preserve annotations
Save the initial annotation's handle
Update the annotation's text in updatefig()
Include the annotation in the return of updatefig()
Set blit=False to preserve annotations
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
#1 do NOT call fig.clear()
steps = 10
data = np.random.rand(20, 20, steps)
im = plt.imshow(data[:, :, 0], cmap='Greys', origin='lower', animated=True)
plt.colorbar(shrink=1, aspect=30, label='Counts')
#2 annotate frame 0 and save handle
annot = ax.annotate('Frame: 0', (0.09, 0.92), xycoords='figure fraction')
def updatefig(j):
im.set_array(data[:, :, j])
#3 update annotation text
annot.set_text(f'Frame: {j}')
#4 include annotation when returning
return im, annot
#5 set blit=False
anim = animation.FuncAnimation(fig, updatefig, frames=steps, blit=False)

Saved matplotlib animation file (mp4, gif) corrupted

I have a python script that animates a curve and shades the area underneath the curve. The code is pretty much the same as for the example with the sine wave below, but the time evolution of the curve is read from a file. The animation that pops up when the program is done is fine, but the mp4 that is saved has issues with the shading beneath the curve: it accumulates. This is only the case for the curve that I read from the file and not for the simple sine wave. It also doesn't work if I save it as a gif with the writer set to imagemagick.
I wonder why my particular case fails and what I could try to fix it?
Here's the working example:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
plt.rcParams["figure.figsize"] = [7.50, 3.50]
plt.rcParams["figure.autolayout"] = True
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
p = plt.fill_between(x, y, 0, facecolor="slateblue")
return line, p,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True)
anim.save("testanimateion.mp4", writer='ffmpeg')
plt.show()
and a screenshot of the saved animation (it should be a wavy surface, the numerical solution of the linearized 1D shallow water equations):

How to trace the path of a patches.Rectangle object in matplotlib animation?

I am trying to animate a simple patches.Rectangle object using matplotlib. I want to plot the path traced by the said object (or the area swiped by it) in the animation. I could see that people are tracing paths of a single particle by appending all its previous positions to a list, but I am not sure how to do that for, say, a Rectangle .
One way to do that (I guess) would be to plot the Rectangle in the new positions without wiping out the Rectangle from the previous frames. But I don't know how to do that.
I am using the following code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib import animation
# x and y go from 0 to 1 in 100 steps
x = [i/100 for i in range(100)]
y = [i/100 for i in range(100)]
# Angle goes from 0 to pi/2 in 100 steps
orientation = [(1.57)*i/100 for i in range(100)]
fig = plt.figure()
plt.axis('equal')
plt.grid()
ax = fig.add_subplot(111)
ax.set_xlim(-10, 10)
ax.set_ylim(-10, 10)
patch = patches.Rectangle((0, 0), 0, 0, fc='r')
def init():
ax.add_patch(patch)
return patch,
def animate(i):
patch.set_width(5.0)
patch.set_height(2.0)
patch.set_xy([x[i], y[i]])
patch.angle = np.rad2deg(orientation[i])
return patch,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=len(x),
interval=5, blit=True, repeat_delay=500)
plt.show()
In other words, I want to see the trace of the rectangle as it moves in addition to just the rectangle moving. Ideally, the solution should be easily applicable to other patches objects (Polygon, Ellipse, etc.) also.
To keep the object in the animation, you don't need to initialize it, just add the object to an empty list, specify it as Patch_collection, and set it to add_collection(). I believe this can be diverted to other objects as well; a reference example of PatchCollection can be found here.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib import animation
from matplotlib.collections import PatchCollection
# x and y go from 0 to 1 in 100 steps
x = [i/100 for i in range(100)]
y = [i/100 for i in range(100)]
# Angle goes from 0 to pi/2 in 100 steps
orientation = [(1.57)*i/100 for i in range(100)]
fig = plt.figure()
plt.axis('equal')
plt.grid()
ax = fig.add_subplot(111)
ax.set_xlim(-10, 10)
ax.set_ylim(-10, 10)
patch = patches.Rectangle((0, 0), 0, 0, fc='r')
def init():
ax.add_patch(patch)
return patch,
items = []
def animate(i):
patch.set_width(5.0)
patch.set_height(2.0)
patch.set_xy([x[i], y[i]])
patch.angle = np.rad2deg(orientation[i])
items.append(patch)
fig = ax.add_collection(PatchCollection(items, fc='r', ec='white', alpha=x[i]))
return fig,
anim = animation.FuncAnimation(fig, animate, frames=len(x), interval=200, blit=True, repeat=False)
plt.show()

Matplotlib y axis is not ordered

I'm getting data from serial port and draw it with matplotlib. But there is a problem. It is that i cannot order y axis values.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from deneme_serial import serial_reader
collect = serial_reader()
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xs=[]
ys=[]
def animate(i, xs, ys):
xs = collect.collector()[0]
ys = collect.collector()[1]
ax.clear()
ax.plot(xs)
ax.plot(ys)
axes=plt.gca()
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.title('TMP102 Temperature over Time')
plt.ylabel('Temperature (deg C)')
ani = animation.FuncAnimation(fig, animate, fargs=(xs,ys), interval=1000)
plt.show()
Below graph is result of above code
This happened to me following the same tutorial.
My issue was the variables coming from my instrument were strings. Therefore, there is no order. I changed my variables to float and that fixed the problem
xs.append(float(FROM_INSTRUMENT))

Syntax for plotting three points' movement using FuncAnimation

My code:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
def animate(i):
ax.set_data(ax.scatter(ptx1, pty1, ptz1, c='red'),
ax.scatter(ptx2, pty2, ptz2, c='blue'),
ax.scatter(ptx3, pty3, ptz3, c='green'))
ani = FuncAnimation(fig, animate, frames=10, interval=200)
plt.show()
I'm trying to plot the movement of three points. Each ptx/y/z/1/2/3 is a list of floats giving the coordinates of the point. I'm just not sure how to use FuncAnimation to animate my points. Any help would be greatly appreciated!
Simple example. animate is called many times and everytime you have to use different data to see animation.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import random
# create some random data
ptx1 = [random.randint(0,100) for x in range(20)]
pty1 = [random.randint(0,100) for x in range(20)]
fig = plt.figure()
ax = fig.add_subplot(111)
def animate(i):
# use i-th elements from data
ax.scatter(ptx1[:i], pty1[:i], c='red')
# or add only one element from list
#ax.scatter(ptx1[i], pty1[i], c='red')
ani = FuncAnimation(fig, animate, frames=20, interval=500)
plt.show()

Categories