How to add a timer in an animation.FuncAnimation (), using pandas/Geopandas? - python

I am creating an animation by using GeoPandas and everything is going well but I'd like to include a timer, in order to know the time corresponding to my visualization.
I think the way is by means of set_text, but I think everything is lost in the update done by Geopandas to plot (ax=ax).
So, the instruction time_text is the one that is not working on my code. Please any help/suggestion/idea? Thanks in advance!!
Here the important part of my code:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import geopandas as gpd
import pandas as pd
from shapely.geometry import Point
fig = plt.figure()
ax = plt.axes(xlim=(2.5, 7), ylim=(48, 52))
time_text = ax.text(2.8, 50.,"",transform = ax.transAxes, ha="right")
ax.legend()
t=0
bel = gpd.read_file('....')
def init():
global inicio
inicio = bel.plot( ax=ax, color='black', markersize=5)
time_text.set_text("")
return inicio, time_text
data = pd.read_csv('.....')
legend = plt.legend(loc='lower left',prop={'size': 7})
def animate(i):
global inu, iterar, t
t += 1
ax.clear()
inu = bel.plot( ax=ax, color='lightgray', linewidth=1., edgecolor='black')
cond = geo_data[ geo_data['newdate'].dt.minute == i]
iterar = cond.plot(ax=ax,marker='s',color='yellow', markersize=7.,alpha=0.3,label='Max >= 60 Tonne');
legend = plt.legend(loc='lower left',prop={'size': 7})
time_text.set_text("time = "+str(t))
return iterar,inu,time_text
anim = animation.FuncAnimation(fig, animate, init_func=init,frames=60, interval=500, blit=False)
plt.show()

Related

Animating a kdeplot python

Im trying to annimate a kdeplot in python.
The idea is to evaluate actions over time.
The script below almost works as planned, but instead of updating the plot, it overlaps the plots and becomes very slow after a few runs.
So I can see that my problem might be that i dont really understand the animate func and have now becom very lost in trying to understand the problem.
So i hope that soembody can see the problem and help me.
import numpy as np
from matplotlib import animation
import matplotlib.pyplot as plt
import pandas as pd
import cmasher as cmr
from mplsoccer import VerticalPitch
df = pd.DataFrame(np.random.randint(0,100,size=(1000, 2)), columns=list('xy'))
#%%
pitch_dark = VerticalPitch(line_color='#cfcfcf', line_zorder=2, pitch_color='#122c3d')
fig, ax = pitch_dark.draw()
#kdeplot_dark = pitch_dark.kdeplot([], [], ax=ax, cmap=cmr.voltage, shade=True, levels=100)
def init():
kdeplot_dark = pitch_dark.kdeplot(0,0, ax=ax, cmap=cmr.voltage, shade=True, levels=100)
def animate(i):
x = df.x.iloc[i:i+20]
y = df.y.iloc[i:i+20]
kdeplot_dark = pitch_dark.kdeplot(x,y, ax=ax, cmap=cmr.voltage, shade=True, levels=100)
anim = animation.FuncAnimation(fig, animate, init_func=init)
plt.show()

Plotting vertical lines in matplotlib.animation over a scatter plot

I am wanting to use matplotlib.annimation to sequentially plot data points and plot vertical lines as they become known.
What I have at the moment is the following:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = np.arange(len(data))
y = data
fig = plt.figure()
plt.xlim(0, len(data))
plt.ylim(-8, 8)
graph, = plt.plot([], [], 'o')
def animate(i):
# line_indicies = func(x[:i+1])
graph.set_data(x[:i+1], y[:i+1])
# then I would like something like axvline to plot a vertical line at the indices in line indices
return graph
anim = FuncAnimation(fig, animate, frames=100, interval=200)
# anim.save('basic_animation.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()
I would like to plot vertical lines outputted from a function as described in the comments in the animate function.
The lines are subject to change as more data points are processed.
I wrote the code with the understanding that I wanted to draw a vertical line along the index of the line graph. I decided on the length and color of the vertical line, and wrote the code in OOP style, because if it is not written in ax format, two graphs will be output.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
data = np.random.randint(-8,8,(100,))
x = np.arange(len(data))
y = data
fig = plt.figure()
ax = plt.axes(xlim=(0, len(data)), ylim=(-8, 8))
graph, = ax.plot([], [], 'o')
lines, = ax.plot([],[], 'r-', lw=2)
def init():
lines.set_data([],[])
return
def animate(i):
graph.set_data(x[:i+1], y[:i+1])
# ax.axvline(x=i, ymin=0.3, ymax=0.6, color='r', lw=2)
lines.set_data([i, i],[-3, 2])
return graph
anim = FuncAnimation(fig, animate, frames=100, interval=200)
# anim.save('basic_animation.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()

Show only one frame at a time using matplotlib.animation.FuncAnimation

I've got some code similar to this
from matplotlib import animation
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
def animate(i):
x0,y0 = np.random.random(size=(2,))*4-2
x = np.random.normal(loc=x0, size=(1000,))
y = np.random.normal(loc=y0, size=(1000,))
for layer in prevlayers:
layer.remove()
prevlayers[:] = []
hexlayer = ax.hexbin(x,y, gridsize=10, alpha=0.5)
# the following line is needed in my code
hexlayer.remove()
prevlayers.append(hexlayer)
return hexlayer,
prevlayers = []
ani = animation.FuncAnimation(fig, animate, frames=12)
ani.save('teste.gif', writer='PillowWriter')
I'm trying to show only one frame at a time, but the code that I have written uses two ax.hexbin() calls and I have to remove one of them in order to show the correct graph. Is there a way to show one hexbin layer at a time using FuncAnimation?
You only need ax.clear() for each frame
from matplotlib import animation
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
def animate(i):
ax.clear()
x0,y0 = np.random.random(size=(2,))*4-2
x = np.random.normal(loc=x0, size=(1000,))
y = np.random.normal(loc=y0, size=(1000,))
hexlayer = ax.hexbin(x,y, gridsize=10, alpha=0.5)
return ax
ani = animation.FuncAnimation(fig, animate, frames=12)
ani.save('teste.gif', writer='PillowWriter')
this code produces

Previous frames not cleared when saving matplotlib animation

I am making a matplotlib animation in which a quiver arrow moves across the page. This cannot be achieved in the usual way (creating one Quiver object and updating it with each frame of the animation) because although there is a set_UVC method for updating the u, v components, there is no equivalent method for changing the x, y position of the arrows. Therefore, I am creating a new Quiver object for each frame.
This works fine when I do a plt.show() and the animation is drawn on the screen. The arrow moves from left to right across the page, and when one arrow appears the previous one disappears, which is what I want. However, when I save as a gif or mp4 the previous arrows are not cleared, so I end up with a whole line of arrows appearing. How can I fix this?
My code is as follows:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation
n = 21
x = np.linspace(-1.0, 1.0, num=n)
def animate(i):
q = plt.quiver(x[i:i+1], [0], [1], [0])
return q,
plt.gca().set_xlim([-1, 1])
anim = matplotlib.animation.FuncAnimation(plt.gcf(), animate, frames=n,
repeat=True, blit=True)
plt.show()
#anim.save('anim.gif', dpi=80, writer='imagemagick')
#anim.save('anim.mp4', dpi=80, writer='ffmpeg')
The solution is found here, as suggested by Jean-Sébastien above. My code now reads:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation
n = 21
x = np.linspace(-1.0, 1.0, num=n)
q = plt.quiver(x[:1], [0], [1], [0])
def animate(i):
q.set_offsets([[x[i], 0]])
return q,
plt.gca().set_xlim([-1, 1])
anim = matplotlib.animation.FuncAnimation(plt.gcf(), animate, frames=n,
repeat=True, blit=True)
plt.show()
#anim.save('anim.gif', dpi=80, writer='imagemagick')
#anim.save('anim.mp4', dpi=80, writer='ffmpeg')
Try to clear the frame every time in your animate function. The code below worked well to me.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation
n = 21
x = np.linspace(-1.0, 1.0, num=n)
fig = plt.figure()
def animate(i):
fig.clear() # clear fig
q = plt.quiver(x[i:i+1], [0], [1], [0])
plt.gca().set_xlim([-1, 1])
return q,
anim = matplotlib.animation.FuncAnimation(plt.gcf(), animate, frames=n,
repeat=True, blit=True)
# plt.show()
# anim.save('anim.gif', dpi=80, writer='imagemagick')
anim.save('anim.mp4', dpi=80, writer='ffmpeg')

How to animate a seaborn's heatmap or correlation matrix?

I am relatively new to python (coming from Matlab). As one project, I am trying to create an animated plot of a correlation matrix over time. To make the plots nice, I am trying seaborn. I struggled to get the animation done at all (having issues with Matplotlib backend on a mac), but a very basic animation now works using this code from the web:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
nx = 50
ny = 50
fig = plt.figure()
data = np.random.rand(nx, ny)
im = plt.imshow(data)
def init():
im.set_data(np.zeros((nx, ny)))
def animate(i):
#xi = i // ny
#yi = i % ny
data = np.random.rand(nx, ny)
im.set_data(data)
return im
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=50, repeat = False)
Now, I was trying to adapt this to seaborn, but did not succeed. It seems that seaborn works on subplots and to animate these was far harder. The best thing I got once was a kind of recursive plot, where seaborn.heatmaps were plotted on top of each other. Also, the im.set_data method was not available.
Any suggestions are highly appreciated.
I replaced plt.imshow (casting data via set_data didn't work) with seaborn.heatmap.
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib import animation
fig = plt.figure()
data = np.random.rand(10, 10)
sns.heatmap(data, vmax=.8, square=True)
def init():
sns.heatmap(np.zeros((10, 10)), vmax=.8, square=True, cbar=False)
def animate(i):
data = np.random.rand(10, 10)
sns.heatmap(data, vmax=.8, square=True, cbar=False)
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=20, repeat = False)
This creates the recursive plot I struggled with.
In addition to your answer above, I wanted to do this from a list of dataframes and save as a gif. So, using your code and Serenity's answer to Matplotlib animation iterating over list of pandas dataframes
fig = plt.figure()
def init():
sns.heatmap(np.zeros((10, 10)), vmax=.8, square=True, cbar=False)
def animate(i):
data = data_list[i]
sns.heatmap(data, vmax=.8, square=True, cbar=False)
data_list = []
for j in range(20):
data = np.random.rand(10, 10)
data_list.append(data)
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=20, repeat = False)
savefile = r"test3.gif"
pillowwriter = animation.PillowWriter(fps=20)
anim.save(savefile, writer=pillowwriter)
plt.show()
Thanks!!!
Here's a complete example (tested with Matplotlib 3.0.3).
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
def animate_heat_map():
fig = plt.figure()
nx = ny = 20
data = np.random.rand(nx, ny)
ax = sns.heatmap(data, vmin=0, vmax=1)
def init():
plt.clf()
ax = sns.heatmap(data, vmin=0, vmax=1)
def animate(i):
plt.clf()
data = np.random.rand(nx, ny)
ax = sns.heatmap(data, vmin=0, vmax=1)
anim = animation.FuncAnimation(fig, animate, init_func=init, interval=1000)
plt.show()
if __name__ == "__main__":
animate_heat_map()
Based on the answer of r schmaelzle I created animated seaborn heatmap with annotaion.
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib import animation
class Heatmap:
def __init__(self):
self.fig, self.ax = plt.subplots()
self.anim = None
def animate(self):
def init():
sns.heatmap(np.zeros((10, 10)), vmax=.8, ax=self.ax)
def animate(i):
self.ax.texts = []
sns.heatmap(np.random.rand(10, 10), annot=True, vmax=.8, cbar=False, ax=self.ax)
self.anim = animation.FuncAnimation(self.fig, animate, init_func=init, frames=20, repeat=False)
if __name__ == '__main__':
hm = Heatmap()
hm.animate()
The trick to update annotations is to make empty ax.texts = [].
I hope it will help others! :)

Categories

Resources