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):
Related
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()
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.
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()
I cannot run matplotlib animations using anaconda. I’m trying to run this on Spyder:
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()
But it gives me a blank plot. I'm using this directly off of the documentation website as an example and it is not working.
I think you're using Pycharm which have some bug.
you need to toggle off scientific mode off in preference->tools->python scientific-> show plots in tool window.
and add
%matplotlib qt5
before drawing