TransWikia.com

Animate gradient bar chart - matplotlib

Stack Overflow Asked by jonboy on August 4, 2020

The following code animates a bar chart. I’m trying to apply a gradient and text labels to this animation though. The autolabel() function aims to add the text label and the gradientbars()functions aims to add the gradient. When applying here functions however, the animation just produces a still image.

I’m also hoping to adjust the gradient to a fixed point. Specifically, rather than applying the gradient to the extent of the individual bar height, I’m hoping to apply a max level of 6. Please see figure below regarding this.

I’ve commented out the specific functions below so the code works but applying them will produced the figure attached.

fig, ax = plt.subplots()
ax.grid(False)

data = np.random.randint(5, size=(10, 5))

x = ['A','B','C','D','E']
plt.ylim(0, 6)

rects = plt.bar(x, data[0])

def autolabel(rects):

    '''
    Attach a text label above each bar displaying its height
    '''
    for rect in rects:
        height = rect.get_height()
        ax.text(rect.get_x() + rect.get_width()/2., 1.05 * height,
                '%d' % int(height),
                ha = 'center', va = 'bottom')

def gradientbars(bars):

    grad = np.atleast_2d(np.linspace(0,5,256)).T

    cmap = 'Blues'
    
    ax = bars[0].axes
    lim = ax.get_xlim() + ax.get_ylim()

    for bar in bars:
    
        bar.set_zorder(1)
        bar.set_facecolor("none")
    
        x,y = bar.get_xy()
        w,h = bar.get_width(), bar.get_height()    
   
        ax.imshow(grad, extent = [x, x + w, y, y + h], aspect = "auto", zorder = 0, cmap = cmap)
    
    ax.axis(lim)

#autolabel(rects)

#gradientbars(rects)

def animate(i):

    for rect, yi in zip(rects, data[i]):
        rect.set_height(yi)

anim = animation.FuncAnimation(fig, animate, frames = len(data), interval = 100)

plt.show()

One Answer

This is how I would do this:

def autolabel(rects):
    '''
    Attach a text label above each bar displaying its height
    '''
    ts = []
    for rect in rects:
        height = rect.get_height()
        t = ax.text(rect.get_x() + rect.get_width()/2., 1.05 * height,
                '%d' % int(height),
                ha = 'center', va = 'bottom')
        ts.append(t)
    return ts

def gradientbars(bars, cmap, vmin, vmax):
    g = np.linspace(vmin,vmax,100)
    grad = np.vstack([g,g]).T
    xmin,xmax = ax.get_xlim()
    ymin,ymax = ax.get_ylim()
    ims = []
    for bar in bars:
        bar.set_facecolor('none')
        im = ax.imshow(grad, aspect="auto", zorder=0, cmap=cmap, vmin=vmin, vmax=vmax, extent=(xmin,xmax,ymin,ymax))
        im.set_clip_path(bar)
        ims.append(im)
    return ims

Nbars=5
Nframes=10
vmin=0
vmax=6
cmap = 'Blues'
data = np.random.choice([0,1,2],size=(Nframes,Nbars))
data = data.cumsum(axis=1)
data[data>6] = 6
x=[chr(ord('A')+i) for i in range(Nbars)]
print(x)
print(data)

fig, ax = plt.subplots()
ax.grid(False)
plt.ylim(vmin, vmax)
rects = plt.bar(x,data[0])
labels = autolabel(rects)
imgs = gradientbars(rects, cmap=cmap, vmin=vmin, vmax=vmax)

def animate(i):
    for rect,label,img,yi in zip(rects, labels, imgs, data[i]):
        rect.set_height(yi)
        label.set_text('%d'%int(yi))
        label.set_y(yi)
        img.set_clip_path(rect)

anim = animation.FuncAnimation(fig, animate, frames = len(data), interval = 500)
plt.show()

enter image description here

Correct answer by Diziet Asahi on August 4, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP