pythonmatplotlibanimationbar-chartstacked-bar-chart

How do I create an animated stacked bar chart using matplotlib


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 Animated stacked bar elements

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

Solution

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

    enter image description here

    Or this asynchronous version :

    enter image description here

    How it works in the first animation ?

    enter image description here