У меня есть словарь, который обновляется с помощью цикла for, я пытаюсь построить пары значений ключа на графике, который перемещается или перемещается по мере того, как количество пар значений ключа продолжает обновляться, а график просто показывает 50 текущих значений из словаря.
до сих пор я сделал:
for k,v in plot.items():
plt.barh(k,v , color='blue')
plt.pause(0.3)
plt.show()
Проблема в том, что значения продолжают добавляться, а графики продолжают расти. Есть ли способ показать только последние 50 k, v пар из словаря и продолжать обновлять график. Я также попробовал функцию:
def live_plotter(x_vec,y1_data,line1,identifier='',pause_time=0.1):
if line1==[]:
# this is the call to matplotlib that allows dynamic plotting
plt.ion()
#fig = plt.figure(figsize=(13,6))
#ax = fig.add_subplot(111)
# create a variable for the line so we can later update it
line1, = plt.plot(x_vec,y1_data,'-o', alpha=0.8)
#update plot label/title
plt.ylabel('Cross-correlation')
plt.title('Title: {}'.format(identifier))
line1.set_data(x_vec, y1_data)
plt.pause(pause_time)
return line1
Но это также не обновляет график и просто добавляет к графику, как показано выше.
Я также попробовал функцию анимации:
fig = plt.figure()
def animate():
for k, v in plot:
print(k, v)
plt.barh(k, v, color='blue')
plt.pause(0.3)
ani = matplotlib.animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
Воспроизводимый пример:
import matplotlib.pyplot as plt
import matplotlib.animation
plot_base={'00002200': 986.11152642551519,
'00002201': 989.90915858383369,
'00002202': 992.87095144990781,
'00002203': 994.89971071876084,
'00002204': 992.92424216660561,
'00002205': 993.19845750930426,
'00002206': 988.88001766153957,
'00002207': 988.95062195981848,
'00002208': 993.17138084871465,
'00002209': 993.9863425202193,
'00002210': 993.43551440410283,
'00002211': 993.04540624076844,
'00002212': 991.40048097057559,
'00002213': 993.16124311517319,
'00002214': 994.06785011666204,
'00002215': 985.24294182260996,
'00002216': 990.5369409623512,
'00002217': 991.83512034302737,
'00002218': 993.43756392913269,
'00002219': 989.77919409784511,
'00002220': 988.09683378239572,
'00002221': 992.19961090836773,
'00002222': 992.69477342507912,
'00002223': 992.37890673842412,
'00002224': 991.55520651752556,
'00002225': 992.15414070360941,
'00002226': 991.49292821478309,
'00002227': 994.75013161999084,
'00002228': 991.54858727670728,
'00002229': 993.22846583401292,
'00002230': 993.88719133150084,
'00002231': 992.89934842358855,
'00002232': 991.10582582918869,
'00002233': 993.24750746833467,
'00002234': 992.6478137931806,
'00002235': 991.2614284514957,
'00002236': 994.38800336488725}
plot={}
for k,v in plot_base.items():
plot.update({k: v})
for k,v in plot.items():
bar, = plt.bar(k, v, color='blue')
plt.pause(0.3)
plt.plot()
'''
def animate(i):
bars = []
for k, v in plot.items():
bar, = plt.bar(k, v, color='blue')
bars.append(bar)
return bars
fig=plt.figure(figsize=(12 ,7))
ani = matplotlib.animation.FuncAnimation(fig, animate, interval=1000, blit=True)
plt.show()
'''
Когда мы запускаем этот код, значения из словаря продолжают добавляться к оси X, поэтому я хочу, чтобы он был в состоянии прокрутки (автопрокрутка), код с тройными кавычками показывает часть анимации, это заставляет весь график появляться сразу,
Используйте отдельный контейнер, чтобы сохранить данные, которые вы хотите отобразить, в виде кортежей (key,value)
, и это удобно, так как вы можете ограничить размер:
import collections
...
plotme = collections.deque(maxlen=50)
....
# in the loop that adds to the dictionary
yourdict[key] = value
plotme.append((key,value))
....
Вы можете перебирать деку так же, как вы делаете с yourdict.items()
:
>>> d
deque([(1, 1), (2, 2), (3, 3), (4, 4)], maxlen=4)
>>> for k,v in d:
print(f'key:{k}, value:{v}')
key:1, value:1
key:2, value:2
key:3, value:3
key:4, value:4
>>>
Я могу также получить данные из двух отдельных списков -
Если ваши данные уже находятся в двух отдельных списках, вы можете сделать что-то похожее, просто выберите последние 50 элементов в каждом списке
for key, value in zip(keylist[-50:], valuelist[-50:]):
#plot here ?
Я не думаю, что понимаю структуру данных, используемую здесь, так что это фокусируется на анимации. Предположим, у вас есть функция store.get_last_20_values
из которой можно получить данные, которые вы хотите построить. Тогда анимация будет выглядеть так:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
fig, ax = plt.subplots()
def animate(i):
cat, val = store.get_last_20_values()
ax.clear()
ax.barh(cat, val)
ani = FuncAnimation(fig, animate, interval=1000)
plt.show()
Для полноты, вот как могла бы выглядеть эта функция, чтобы сделать вышеуказанный работоспособным.
class Store():
x = []
y = []
def update(self):
n = np.random.randint(0,5)
x = np.random.randint(100000,999999, size=n).astype(str)
y = np.random.randint(50,999, size=n)
self.x.extend(x)
self.y.extend(y)
self.x = self.x[-20:]
self.y = self.y[-20:]
def get_last_20_values(self):
# Some function to return 20 values. Need to adapt to custom needs.
self.update()
return self.x, self.y
store = Store()
FuncAnimation
запускает цикл для вас в том смысле, что он неоднократно вызывает функцию animate
. Вы хотели бы, чтобы цикл работал независимо и позволял matplotlib отображать «моментальные снимки» текущего состояния цикла?