Холст tkinter matplotlib обновляется слишком медленно для данных в реальном времени - PullRequest
9 голосов
/ 10 июля 2020

Я работаю с устройством, которое отправляет 100 показаний в секунду, и я хочу, чтобы на моем GUI был график этих данных, показывающий последние 300 собранных точек. Однако я обнаружил, что:

  1. добавление новой точки данных в очередь оси Y

  2. удаление уже существующего графика

  3. построение нового списка данных

  4. перерисовка холста

после каждой точки занимает примерно 0,2 - 0,4 секунд, что невероятно медленно.

Это код, который я использую в настоящее время. Некоторое время l oop продолжает проверять очередь, и как только в нее помещается новый элемент, он вызывает update с этим элементом в качестве параметра. Сможет ли кто-нибудь предложить некоторые улучшения эффективности или альтернативы matplotlib?

class GraphFrame:
    def __init__(self,root,channel,index):
        self.root=root
        self.frame=tk.Frame(self.root)
        self.frame.pack(side=tk.LEFT)
     
        self.y = Queue(maxsize = 300)
        
        self.fig, self.axes = plt.subplots(1,1)
        self.axes.plot(list(self.y.queue))

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, padx=5, pady=5)

    def update(self, new_point):
        if self.y.full():
            self.y.get()
        self.y.put(new_point)
        self.fig.axes[0].clear()
        self.fig.axes[0].plot(list(self.y.queue))
        self.canvas.draw()

Edit: удалось решить проблему с помощью блиттинга для matplotlib и замены холста Tkinter меткой с изображением графика . Постараюсь выложить код на github и связать его.

1 Ответ

5 голосов
/ 13 июля 2020

Вместо того, чтобы перестраивать вашу фигуру для каждой новой точки, я бы изменил LineArtist, который у вас уже есть.

class GraphFrame:
    def __init__(self,root,channel,index):
        self.root=root
        self.frame=tk.Frame(self.root)
        self.frame.pack(side=tk.LEFT)
     
        self.y = Queue(maxsize = 300)
        
        self.fig, self.axes = plt.subplots(1,1)

        # capture the artist
        self.line, = self.axes.plot(list(self.y.queue))

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, padx=5, pady=5)

    def update(self, new_point):
        if self.y.full():
            self.y.get()
        self.y.put(new_point)
        
        # update the artist
        self.line.set_xdata(list(range(len(self.y))))
        self.line.set_ydata(list(self.y.queue))

...