Экспорт pyqtgraph из API в виджете PyQt4 завершается сбоем / сбоем python

У меня есть небольшое приложение, которое я создал с использованием PyQt4 и pyqtgraph. Я хочу поместить несколько кнопок в этот вызов экспортеров, доступных с помощью pyqtgraph (вместо или даже в дополнение к использованию контекстного меню, которое появляется, когда пользователь щелкает правой кнопкой мыши на графике).

Однако до сих пор мне не удалось заставить это работать.

Вот упрощенная версия приложения:

from PyQt4 import QtCore, QtGui
import pyqtgraph as pg
import pyqtgraph.exporters
import numpy as np
import sys


class SimpleUI(QtGui.QWidget):

    def __init__(self):
        QtGui.QWidget.__init__(self)

        self.resize(1500, 1000)
        self.plot_widget = pg.GraphicsLayoutWidget(self)
        self.layout = QtGui.QVBoxLayout(self)

        data = np.arange(10)
        self.plt = self.plot_widget.addPlot()
        self.plt.plot(data)

        self.export_btn = QtGui.QPushButton("Export")
        self.export_btn.clicked.connect(self.export)

        self.layout.addWidget(self.plot_widget)
        self.layout.addWidget(self.export_btn)

    def export(self):
        img = pg.exporters.ImageExporter(self.plt)
        img.export()


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = SimpleUi()
    ex.show()
    sys.exit(app.exec_())

При нажатии на кнопку «Экспорт» в этом случае диалоговое окно быстро появляется, а затем исчезает.

Если вместо этого я поставлю

img.export(copy=True)

И попробуйте вставить что-нибудь из буфера обмена во что-нибудь (Paint, что угодно), python.exe вылетает.

Как ни странно, экспорт через контекстное меню, доступное по умолчанию в pyqtgraph, работает просто отлично. Кроме того, просто работая в терминале, я могу просто копировать/сохранять plotItems, используя те же строки кода, что и выше. То есть:

import numpy as np
import pyqtgraph as pg
import pyqtgraph.exporters

plt = pg.plot(np.arange(10))
img = pg.exporters.ImageExporter(plt.plotItem)
img.export()

Это означает, что экспортеры работают нормально, но происходит какое-то странное взаимодействие, когда они вызываются из виджета pyqt4 так, как я их вызываю.

Я пробовал как pyqtgraph 0.9.8, так и основную ветку на github. Очень растерялся, в чем тут дело

Спасибо


person dan_g    schedule 17.12.2014    source источник


Ответы (1)


Похоже, вы нигде не храните img, поэтому он собирается, как только возвращается вызов export().

Объяснение:

  1. Объекты в Python хранятся в памяти только до тех пор, пока они необходимы. Когда Python определяет, что объект больше не нужен, он удаляет этот объект.

  2. Как Python узнает, что объект больше не нужен? По подсчету ссылок. Когда вы выполняете img = ImageExporter(...), создается новый объект с одной ссылкой: локальная переменная img.

  3. Переменные, созданные внутри функции, считаются локальными по отношению к области действия этой функции. Когда функция завершается, переменная img исчезает, что приводит к тому, что счетчик ссылок объекта ImageExporter падает до 0, что приводит к тому, что Python удаляет объект.

  4. Установив self.img = ImageExporter(...), вы назначаете ссылку на объект, который не является локальным для области действия функции (поскольку объект SimpleUI, называемый self, продолжает существовать после возврата из функции). Это позволяет объекту сохраняться до тех пор, пока SimpleUI все еще содержит ссылку.

person Luke    schedule 17.12.2014
comment
Таким образом, изменение img на переменную экземпляра (например, self.img) устраняет проблему. Хотя мне непонятно почему. Я уверен, что это относительно простой вопрос по CS, но не могли бы вы объяснить, что происходит? Например, если я добавляю print(img) в функцию экспорта, я получаю объект экспортера в ячейке памяти. Почему, поскольку img.export() вызывается в той же функции, этот объект не сохраняется/не используется? - person dan_g; 17.12.2014
comment
Спасибо за объяснение. Я думал, что хорошо разбираюсь во всем этом, но, похоже, нет. Я предполагаю, что, вызывая img.export(), мы выходим из области действия моей функции экспорта, поэтому объект img теряется? - person dan_g; 17.12.2014
comment
Нет, вызов img.export() только открывает диалоговое окно файла, а затем немедленно возвращается, после чего SimpleUI.export() также возвращается, а img удаляется. - person Luke; 17.12.2014
comment
Я понимаю, что img теряется после возврата SimpleUI.export(). Что мне трудно понять, так это то, почему это важно. Цель img.export() — создать файл из img (или добавить png в буфер обмена), правильно? Это действие завершается, когда возвращается img.export(), не так ли? Вот почему я не понимаю, почему img должен сохраняться после завершения SimpleUI.export(). Извините, если то, что происходит, должно быть очевидным, но спасибо, что нашли время объяснить - person dan_g; 18.12.2014
comment
когда я говорю создать файл из img, я имею в виду из plotItem, который передается при создании экземпляра img класса ImageExporter - person dan_g; 18.12.2014
comment
При вызове img.export() отображается диалоговое окно файла и выполняется немедленный возврат. Фактический экспорт не происходит до тех пор, пока пользователь не выберет имя файла и не нажмет кнопку «Сохранить», после чего img уже удален. - person Luke; 18.12.2014