I have been trying to create an animated stacked bar chart using matplotlib. Although I have managed to animate each stack element, the output only shows one element at a time. I was also able to manage to get one column of stacked bar at a time. But what I want is to animate each stack element without the displayed element getting cleared before the next element. Will be grateful, if someone can help out. ps: I have tried both FuncAnimation and ArtistAnimation and failed.:( Rgds Nitin
Here is my code.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import pandas as pd
import numpy as np
def bstack(df, title, ylabel, xlabel):
pp = df.values.tolist()
fig, ax = plt.subplots()
ax.set_title(title)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
def animate(j):
axlist = []
for i in range(j):
yval = df.iloc[i,:].values.tolist()
stacklabel = df.iloc[i,:].index.tolist()
for y in range(len(yval)):
contain = ax.bar(i,yval[y], bottom = sum(yval[:y]), label = stacklabel[y])
axlist.append(contain)
return axlist
axlist = animate(df.shape[0])
anim = animation.ArtistAnimation(fig, axlist, interval=500)
anim.save("stack.gif", writer='ffmpeg')
df = pd.DataFrame({'col1':[1,2,3,4], 'col2':[4,3,2,1], 'col3':[5,6,7,8]})
bstack(df,"mygif","Myplot","Y-axis")
With a FuncAnimation
:
R, C = df.shape
ST = df.stack().to_numpy()
CS = df.T.shift(fill_value=0).cumsum().to_numpy()
plt.style.use("ggplot")
fig, ax = plt.subplots(
subplot_kw=dict(
xlim=(-0.5, R - 0.5),
ylim=(0, df.sum(axis=1).max() + 1),
xticks=df.index,
), figsize=(7, 3),
)
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
def stack(i):
if i == 0:
pass # empty frame
else:
vals = np.zeros(R)
vals[(i - 1) // C] = ST[i - 1]
ax.bar(df.index, vals, bottom=CS[(i - 1) % C], fc=colors[(i - 1) % C])
ani = FuncAnimation(fig, stack, frames=len(ST) + 1)
Or this asynchronous version :
How it works in the first animation ?