Почему mpl_connect не работает при вызове в __init__ класса? - PullRequest
0 голосов
/ 26 апреля 2019

Я работаю над созданием интерактивного графа pyplot с "fig.canvas.mpl_connect (event, function)", когда нажаты клавиши или мышь. Работает как положено. Однако, чтобы сделать его легко импортируемым, мне нужно сжать функции в класс. Функция mpl_connect будет вызываться в функции __init__ класса. Но это заставляет его не работать. Только когда mpl_connect вызывается вне класса со ссылкой на функции внутри класса, он работает.

Конечно, я пытался назвать это без классов, и это работает, как и ожидалось. И чтобы показать, что проблема возникает внутри функции класса __init__, я вызвал mpl_connect вне класса в связи с функцией внутри класса.

Вот сжатая, утконтская версия того, чего я пытаюсь достичь. Это простой обработчик событий, который заставляет консоль печатать «да», когда вы щелкаете мышью по графику pyplot. :

-> РАБОТАЕТ, хотя классов нет! Ненадежен при импорте в другие программы.

import matplotlib.pyplot as plt
def abc(event):
   print("yes")
fig, ax = plt.subplots()
fig.canvas.mpl_connect("button_press_event",abc)
plt.show()

-> НЕ РАБОТАЕТ, не печатает «да» (даже если используется self.fig.)

import matplotlib.pyplot as plt
class test():
    def __init__(self):
        fig, ax = plt.subplots()
        fig.canvas.mpl_connect("button_press_event",self.abc)
    def abc(self, event):
        print("Yes")
test()
plt.show()

-> РАБОТАЕТ, теперь с классом, хранящим функцию, но следует использовать ссылки на класс, и это не выглядит красиво:

import matplotlib.pyplot as plt
class test():
    def __init__(self):
        self.FIG, ax = plt.subplots()
    def abc(self, event):
        print("Yes")  
A = test()
A.FIG.canvas.mpl_connect("button_press_event",A.abc)
plt.show()

Я ожидаю, что будет напечатано «да», когда я нажму на график, когда функция mpl_connect вызывается во время инициализации класса, нормальным, логическим питоническим способом. Я считаю, что это ошибка. Спасибо.

РЕДАКТИРОВАТЬ, исправлено добавлением слабой ссылки.

import matplotlib.pyplot as plt
class test():
    def __init__(self):
        self.fig, ax = plt.subplots()
        self.cid_abc = self.fig.canvas.mpl_connect("button_press_event",self.abc)
    def abc(self, event):
        print("Yes")
mytest = test()
plt.show()

1 Ответ

0 голосов
/ 26 апреля 2019

Вам необходимо сохранить ссылку на идентификатор обратного вызова, созданный mpl_connect. Как строка CallbackRegistry doc формулирует:

На практике всегда следует отключать все обратные вызовы, когда они больше не нужны, чтобы избежать висячих ссылок (и, следовательно, утечек памяти). Однако реальный код в Matplotlib редко делает это, и из-за его дизайна довольно сложно разместить этот код. Чтобы обойти это и предотвратить этот класс утечек памяти, мы вместо этого храним слабые ссылки только на связанные методы, поэтому, когда целевой объект должен умереть, CallbackRegistry не будет поддерживать его в живых .

Другими словами, вам необходимо присвоить возврат mpl_connect переменной экземпляра, например

self.cid = fig.canvas.mpl_connect("button_press_event", self.abc)

аналогично тому, как вы найдете это в руководстве по обработке событий .

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