Это работает для первого кадра.
Вы вызываете autolabel(rects, ax)
на первом графике, поэтому метка размещена правильно.
Последующие кадры анимации возвращаются к отображению метки внутри гистограммы для отрицательных целых чисел.
Положение метки последующих кадров устанавливается label.set_y(yi)
. yi
взято из data[i]
, вы не учли здесь отрицательное значение.
Я создаю функцию с именем get_label_position(height)
, чтобы вычислить правильную позицию метки для заданной высоты. Он использует глобальную переменную y_height
. И вызовите эту функцию перед label.set_y()
.
import matplotlib.pyplot as plt
from matplotlib import animation
import pandas as pd
import numpy as np
def get_label_position(height):
p_height = (height / y_height)
label_position = 0
if p_height > 0.95:
label_position = height - (y_height * 0.05) if (height > -0.01) else height + (y_height * 0.05)
else:
label_position = height + (y_height * 0.01) if (height > -0.01) else height - (y_height * 0.05)
return label_position
def autolabel(rects, ax):
# Get y-axis height to calculate label position from.
ts = []
(y_bottom, y_top) = ax.get_ylim()
y_height = y_top - y_bottom
for rect in rects:
height = 0
if rect.get_y() < 0:
height = rect.get_y()
else:
height = rect.get_height()
p_height = (height / y_height)
if p_height > 0.95:
label_position = height - (y_height * 0.05) if (height > -0.01) else height + (y_height * 0.05)
else:
label_position = height + (y_height * 0.01) if (height > -0.01) else height - (y_height * 0.05)
t = ax.text(rect.get_x() + rect.get_width() / 2., label_position,
'%d' % int(height),
ha='center', va='bottom')
ts.append(t)
return ts
def gradientbars(bars, ax, 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
vmin = -6
vmax = 6
cmap = 'PRGn'
data = np.random.randint(-5,5, size=(10, 4))
x = [chr(ord('A')+i) for i in range(4)]
fig, ax = plt.subplots()
ax.grid(False)
ax.set_ylim(vmin, vmax)
rects = ax.bar(x,data[0])
labels = autolabel(rects, ax)
imgs = gradientbars(rects, ax, cmap=cmap, vmin=vmin, vmax=vmax)
(y_bottom, y_top) = ax.get_ylim()
y_height = y_top - y_bottom
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(get_label_position(yi))
img.set_clip_path(rect)
anim = animation.FuncAnimation(fig, animate, frames = len(data), interval = 500)
plt.show()