Сделать прокручиваемый график из словаря, обновляемого в цикле for

1

У меня есть словарь, который обновляется с помощью цикла 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, поэтому я хочу, чтобы он был в состоянии прокрутки (автопрокрутка), код с тройными кавычками показывает часть анимации, это заставляет весь график появляться сразу,

  • 0
    Делаете ли вы что-нибудь с данными, которые вы не хотите строить? Это может быть отброшено? Должны ли данные быть в словаре?
  • 0
    Я хочу создать график с возможностью прокрутки, чтобы данные, которые были обновлены при запуске цикла for, также можно было проверить, если это возможно.
Показать ещё 15 комментариев
Теги:
matplotlib
python-3.x

2 ответа

1

Используйте отдельный контейнер, чтобы сохранить данные, которые вы хотите отобразить, в виде кортежей (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 ?

https://docs.python.org/3/library/functions.html#zip

0

Я не думаю, что понимаю структуру данных, используемую здесь, так что это фокусируется на анимации. Предположим, у вас есть функция 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()
  • 0
    @ImpoatanceOfBeingErnest, спасибо за предложенное решение, но проблема в том, что я пытаюсь получить значения из цикла for, я немного запутался, как извлечь эти значения из функции обновления, я добавляю значения к двум отдельные списки внутри цикла for, если я добавляю значения вне цикла for, то я жду, пока цикл завершится, чтобы получить значения. Есть ли способ получить значения в реальном времени во время работы цикла.
  • 0
    В принципе, FuncAnimation запускает цикл для вас в том смысле, что он неоднократно вызывает функцию animate . Вы хотели бы, чтобы цикл работал независимо и позволял matplotlib отображать «моментальные снимки» текущего состояния цикла?
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню