I've been trying to animate a series of plots using matplotlib.animation
to no avail. My data are currently stored in a Pandas dataframe and I want to iterate through a category (in this case, colors) and plot the data corresponding to each color as the following:
import pandas as pd
import seaborn as sns
import matplotlib.animation as animation
def update_2(i):
plt.clf()
fil_test = test[test['color'] == iterations[i]]
sns.scatterplot(x = 'size',y = 'score',hue = 'shape',ci = None,
palette = 'Set1',data = fil_test)
ax.set_title(r"Score vs. Size: {} Shapes".format(
iterations[i]),fontsize = 20)
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5),prop={'size': 12})
test = pd.DataFrame({'color':["red", "blue", "red",
"yellow",'red','blue','yellow','yellow','red'],
'shape': ["sphere", "sphere", "sphere",
"cube",'cube','cube','cube','sphere','cube'],
'score':[1,7,3,8,5,8,6,2,9],
'size':[2,8,4,7,9,8,3,2,1]})
iterations = test['color'].unique()
i = 0
fig2 = plt.figure(figsize = (8,8))
ax = plt.gca()
plt.axis()
ax.set_xlabel("size",fontsize = 16)
ax.set_ylabel("score",fontsize = 16)
ax.set_xlim(0,10)
ax.set_xlim(0,10)
ax.set_xticks(np.linspace(0,10,6))
ax.set_yticks(np.linspace(0,10,6))
ax.tick_params(axis='both', which='major', labelsize=15)
ani = animation.FuncAnimation(fig2,update_2,frames = len(iterations))
ani.save("test.mp4", dpi=200, fps=1)
However, 4 issues arise from this code:
Even though I saved my animation to the ani
variable, it doesn't seem to display the data associated with each different color.
The title doesn't show up/update appropriately for each color.
Calling on ax.legend
produces the following error/Warning: No handles with labels found to put in legend.
Trying to save the animation produces the following Error: MovieWriterRegistry' object is not an iterator
Could someone explain why these issues currently pop up and is there a better way to write/format my code for animated plots?
Have a look to this code:
import pandas as pd
import seaborn as sns
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np
test = pd.DataFrame({'color': ['red', 'blue', 'red', 'yellow', 'red', 'blue', 'yellow', 'yellow', 'red'],
'shape': ['sphere', 'sphere', 'sphere', 'cube', 'cube', 'cube', 'cube', 'sphere', 'cube'],
'score': [1, 7, 3, 8, 5, 8, 6, 2, 9],
'size': [2, 8, 4, 7, 9, 8, 3, 2, 1]})
iterations = test['color'].unique()
fig, ax = plt.subplots(figsize = (10, 8))
fig.subplots_adjust(top = 0.88, right = 0.85, bottom = 0.11, left = 0.12)
def update(i):
ax.cla()
fil_test = test[test['color'] == iterations[i]]
fil_test = fil_test.sort_values(by = ['shape'])
sns.scatterplot(x = 'size', y = 'score', hue = 'shape', ci = None, palette = 'Set1', data = fil_test)
ax.set_title(f'Score vs. Size: {format(iterations[i]):>6} Shapes', fontsize = 20)
ax.legend(loc = 'center left', bbox_to_anchor = (1, 0.5), prop = {'size': 12})
ax.set_xlabel('size', fontsize = 16)
ax.set_ylabel('score', fontsize = 16)
ax.set_xlim(0, 10)
ax.set_xlim(0, 10)
ax.set_xticks(np.linspace(0, 10, 6))
ax.set_yticks(np.linspace(0, 10, 6))
ax.tick_params(axis = 'both', which = 'major', labelsize = 15)
ani = animation.FuncAnimation(fig, update, frames = len(iterations))
ani.save('test.mp4', dpi=200, fps=1)
plt.show()
I edited some things:
plt.clf()
with ax.cla()
in order to clean the axis at each frameset_xlabel
, set_xlim
, set_xticks
and so on) inside update
function: in this way the figure is adjusted every cycle so it is fixed throughout the animationfil_test
, the legend and color association will change with respect to the first value present in that dataframe. In order to avoid that, I added fil_test = fil_test.sort_values(by = ['shape'])
: in this way the color-legend association for 'cube'
and 'sphere'
is fixed throughout the animationfig.subplots_adjust(top = 0.88, right = 0.85, bottom = 0.11, left = 0.12)
in order to make some space for the legendset_title
in order to fix the length of the title so as to improve its readabilityResult:
Your issue is that you are deleting the ax
object in your loop by calling plt.clf()
. Instead, you should call plt.cla()
which clear the content of the axes, but not the Axes themselves.
However, since you are clearing the axes, they go back to their original state, so you will probably want to reset the axes limit and formatting in the animate
function as well
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.