Память увеличивается с matplotlib и tkinter - PullRequest
0 голосов
/ 06 декабря 2018

Проблема:

У меня есть окно tkinter с графиком matplotlib, показывающим некоторые строки (часть гораздо более крупной программы).Периодически я добавляю новую строку, удаляя самую старую, чтобы ограничить количество отображаемых строк.К сожалению, программа постоянно увеличивается в размерах.Я видел это на Windows и Linux.

Вопрос:

Как мне написать долговременную графическую рамку, чтобы показать последние n строк, которые не занимают всю мою память?Желательно, изменив приведенный ниже код, но я готов к полной переписке, если потребуется.

Я удалил оскорбительные части и провел некоторое тестирование.

Важнейшим вызовом является canvas.draw().Даже если к рисунку не добавлено ни одной строки, используемая память постепенно увеличивается со временем.Без этого звонка память не увеличивается.Использование памяти увеличивается быстрее, когда на графике присутствует больше линий.Если оси не созданы (т. Е. Нет fig.add_subplot(1, 1, 1)), то увеличение памяти не происходит.

Удаление строк и восстановление памяти из matplotlib уже обсуждалось ранее ( Как удалить линии в графике Matplotlib).Более слабая ссылка на удаляемую линию подтверждает, что она удаляется, и, поскольку проблема все еще существует, даже если линии не нанесены, я подозреваю, что это не является основной причиной.

Кажется, самая близкая похожая проблема Объявление FigureCanvasTkAgg вызывает утечку памяти , где вызовы осей для построения (а не для pyplot) решили проблему.Похоже, что это не относится к этому случаю - я не использую pyplot для своего построения, я все еще вижу увеличение памяти, если я рисую непосредственно на осях (ax.plot(x, y, '.-')), и снова, я все еще вижу проблему, когда естьлинии не прорисованы.

Использование памяти отслеживалось с помощью mprof, и я также наблюдал, как это происходит с помощью диагностики системы в Windows7.Пример использования памяти, видимый mprof: mprof график увеличения использования памяти

Вот код, который я сейчас получил.Это было значительно урезано по сравнению с первоначальным вариантом использования (_refresh_plot обычно ничего не делает, если новые данные не были добавлены в очередь из другого потока и т. Д.), Но все равно показывает проблему.

import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib as mpl
import weakref

class PlotFrame:
    def __init__(self, parent):
        self.fig = mpl.figure.Figure()
        self.canvas = FigureCanvasTkAgg(self.fig, master=parent)
        self.canvas.get_tk_widget().pack()
        self.ax = self.fig.add_subplot(1, 1, 1)
        self.ax.set_ylim((0, 150))
        self.ax.set_xlim((0, 12))

        self.counter = 0

        timer = self.fig.canvas.new_timer(interval=20)
        timer.add_callback(self._refresh_plot, ())
        timer.start()

    def _refresh_plot(self, arg):
        if True:  # True to plot 1 or more lines, False for no lines at all
            if len(self.ax.lines) > 2:  # Remove the oldest line
                existing_lines = self.ax.get_lines()
                # r = weakref.ref(existing_lines[0])  # weakref to check that the line is being correctly removed
                old_line = existing_lines.pop(0)
                old_line.remove()
                del old_line, existing_lines
                # print('Old line dead? {}'.format(r() is None))  # Prints Old line dead? True

            # Define a line to plot
            x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
            y = [(v - abs(len(x) - self.counter % (2 * len(x)))) ** 2 for v in x]
            self.counter += 1

            new_line = mpl.lines.Line2D(x, y, linestyle='-', marker='.')
            self.ax.add_line(new_line)
            del new_line, x, y

        self.canvas.draw()

if __name__ == "__main__":
    root = tk.Tk()
    cpp = PlotFrame(root)
    root.mainloop()

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...