Matplotlib Animation showing up empty - python

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()

Related

Matplotlib Animation for Plotting Points Being Connected Given Arrays of X and Y values to be coordinates

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.

Trying to make a gif in Python

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()

Animation of drawing a circle

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.

Matplotlib Animation: how to dynamically extend x limits?

I have a simple animation plot like so:
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, 100), ylim=(0, 100))
line, = ax.plot([], [], lw=2)
x = []
y = []
# 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.append(i + 1)
y.append(10)
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()
Now, this works okay, but I want it to expand like one of the subplots in here http://www.roboticslab.ca/matplotlib-animation/ where the x-axis dynamically extends to accommodate the incoming data points.
How do I accomplish this?
I came across this problem (but for set_ylim) and I had some trial and error with the comment of #ImportanceOfBeingErnest and this is what I got, adapted to #nz_21 question.
def animate(i):
x.append(i + 1)
y.append(10)
ax.set_xlim(min(x), max(x)) #added ax attribute here
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=500, interval=20)
Actually in the web quoted by #nz_21 there is a similar solution.
There is a workaround for this even when blit=True if you send a resize event to the canvas, forcing MPL to flush the canvas. To be clear, the fact that the code in #fffff answer doesn't work with blit is a bug in the MPL codebase, but if you add fig.canvas.resize_event() after setting the new x-axis, it will work in MPL 3.1.3. Of course, you should only do this sporadically to actually get any benefit from blitting --- if you're doing it every frame, you're just performing the non-blit procedure anyway, but with extra steps.

Time dependent plot matplotlib

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

Categories