I'm trying to understand how Matplotlib.animation works by drawing a simple circle, but I don't understand what I am doing wrong
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(-10,10),ylim=(-10,10))
line, = ax.plot([], [],)
def init():
line.set_data([], [])
return line,
def animate(i):
x = 3*np.sin(np.radians(i))
y = 3*np.cos(np.radians(i))
line.set_data(x, y)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=360, interval=20, blit=True)
plt.show()
It doesn't draw anything and I don't know why.
x and y need to be arrays of values to plot the line.
You seem to be creating single floats in your animate function.
If you are trying to show the circle gradually appearing, one way to do it would be to create an array of X and Y values at the start, perhaps explicitly from an array of radian values, something like this:
rads = np.arange(0, 2*np.pi, 0.01)
x = 3*np.sin(rads)
y = 3*np.cos(rads)
Then in animate, you assign just a portion of the x and y arrays to the line data.
line.set_data(x[0:i], y[0:i])
The number of steps for a full circle will no longer be 360, it will be 2Pi/0.01.
You can change the size of the interval, or change the number of animation frames to adjust this.
Related
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):
I have two arrays containing x and y values. Each array has 1274 values in it. I essentially want to create a matplotlib animation where these points are being plotted and also connected by a line. I tried doing this with FuncAnimation, but ran into a lot of trouble. Imagine that x and y are the two arrays that I'm referring to. Rest of the code is what I tried so far.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from os import getcwd, listdir
gif_path = getcwd() + "/gifs"
fig = plt.figure()
graph, = plt.plot([], [], 'o')
def animate(i):
if i > len(x) - 1:
i = len(x) - 1
graph.set_data(x[:i+1], y[:i+1])
return graph
ani = FuncAnimation(fig, animate, interval=200)
ani.save(f"{gif_path}/sample_region.gif", writer="imagemagick")
Any help would kindly be appreciated. Thanks.
Your code seems to be following an example from matplotlib, you just need a few extra changes:
x = range(100)
y = np.random.rand(100)
fig, ax = plt.subplots()
ax.set_xlim(0, 100)
ax.set_ylim(0, 1)
graph, = plt.plot([], [], '-')
def init():
return graph,
def animate(i):
graph.set_data(x[:i],y[:i])
return graph,
ani = FuncAnimation(fig, animate, frames=range(len(x)), interval=50, save_count=len(x),
init_func=init, blit=True)
ani.save('ani.gif', writer='PillowWriter')
This produces this GIF. The changes are:
set up an Axes on fig with set axis limits
change the o to -
add an init function for initializing the animation
add a frames argument to pass indexes used to select data
update animate to handle those frames
But I tried making this with an array of 1200 points, and it didn't seem like my computer could complete it... You can try but you might need to trim the data or plot more data each frame.
I'm approximating functions with Fourier Series and I would like to make, hopefully in a simple way, an animated gif of the different approximations. With a for and plt.savefig commands I generate the different frames for the gif but I haven't been able to animate them. The idea is to obtain something like this
This can be done using matplotlib.animation.
EDIT
I'm going to show you how to plot even powers of x like x^2, x^4 and so on. take a look at following example :
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# Setting up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(-10, 10), ylim=(-10, 1000))
line, = ax.plot([], [], lw=2)
# initialization method: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation method. This method will be called sequentially
pow_ = 2
def animate(i):
global pow_
x = np.linspace(-10, 10, 1000)
y = x**pow_
pow_+=2
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=10, interval=200, blit=True)
# if you want to save this animation as an mp4 file, uncomment the line bellow
# anim.save('basic_animation.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()
I would like to plot point-by-point a sine wave in Python via Matplotlib, for which, each point, is added every x milliseconds, in order to obtain a smooth animation of the drawing.
This is my attempt:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from math import sin
fig, ax = plt.subplots()
x = [0]
line, = ax.plot(x, np.asarray(0))
def animate(i):
x.append(x[-1]+0.04)
line.set_xdata(np.asarray(x)*2*np.pi/5)
line.set_ydata(np.sin(np.asarray(x)*2*np.pi/5))
plt.draw()
def init():
line.set_ydata(np.ma.array(x, mask=True))
return line,
ani = animation.FuncAnimation(fig, animate, 10, init_func=init, interval=40, blit=True)
plt.show()
Which raises:
RuntimeError: The animation function must return a sequence of Artist objects.
What did I mistaken? What is, in your opinion, the most efficient way to obtain this effect?
PS The time axis should stay fixed and not move, so it should be wider than the plot
Firstly you are getting the error because your animate(i) is not returning anything. You need to return line,. Secondly you are not using the iin animate(i) aswell.
Here is a simple sine curve animation from https://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# First set up the figure, the axis, and the plot element we want to
animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have
changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
plt.show()
There is additional inspiration in the link which might help you further.
Animate should return a sequence of artist objects:
You should add:
return line, to the end of the animate function
def animate(i):
x.append(x[-1]+0.04)
line.set_xdata(np.asarray(x)*2*np.pi/5)
line.set_ydata(np.sin(np.asarray(x)*2*np.pi/5))
return line,
Source:
Another answer
Simple Example
There was a similar question here but I'm not having the same issue. Below is a snapshot of my dataset:
Essentially, I'd like to animate the drop off coordinates over time. As you can see the dates are sorted by dropoff_datetime. Here is my code (very similar to the question above).
fig = plt.figure(figsize=(10,10))
ax = plt.axes(xlim=xlim, ylim=ylim)
points, = ax.plot([], [],'.',alpha = 0.4, markersize = 0.05)
def init():
points.set_data([], [])
return points,
# animation function. This is called sequentially
def animate(i):
x = test["dropoff_longitude"]
y = test["dropoff_latitude"]
points.set_data(x, y)
return points,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()
Similar to the issue in the problem linked above, my plot is just showing up empty. I believe i'm coding it properly and unlike the link above, I do see the that coordinates are changing over time. I'm not sure why the plot is empty.
Per default one pixel is either 1 point or 0.72 points (depending on whether you run the code in a jupyter notebook or as a standalone plot). If you create a plot with a markersize of 0.05, each marker will thus have a size of 0.05 pixels or 0.07 pixels, respectively. Since it is already quite hard to see 1 pixel on a screen, especially if the alpha is set to 0.4, observing one twentieth of a pixel is simply not possible.
Solution: Set markersize = 5 or higher.
A full working example:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import pandas as pd
test = pd.DataFrame({"dropoff_longitude": [-72,-73,-74,-74],
"dropoff_latitude": [40,41,42,43]})
xlim=(-71,-75)
ylim=(39,44)
fig = plt.figure(figsize=(10,10))
ax = plt.axes(xlim=xlim, ylim=ylim)
points, = ax.plot([], [],'.',alpha = 1, markersize =5)
def init():
points.set_data([], [])
return points,
# animation function. This is called sequentially
def animate(i):
x = test["dropoff_longitude"]
y = test["dropoff_latitude"]
points.set_data(x, y)
return points,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()