Як вбудувати matplotlib у pyqt - для чайників


77

На даний момент я намагаюся вбудувати графік, який я хочу побудувати, у розроблений мною інтерфейс користувача pyqt4. Оскільки я майже повністю новачок у програмуванні - я не розумію, як люди виконували вбудовування в приклади, які я знайшов - цей (внизу) та той .

Було б чудово, якби хтось міг опублікувати покрокове пояснення або принаймні дуже маленький, дуже простий код, лише створюючи, наприклад, графік та кнопку в одному графічному інтерфейсі pyqt4.

Відповіді:


113

Насправді це не так складно. Відповідні віджети Qt є matplotlib.backends.backend_qt4agg. FigureCanvasQTAggі NavigationToolbar2QTзазвичай є тим, що вам потрібно. Це звичайні віджети Qt. Ви розглядаєте їх як будь-який інший віджет. Нижче наведено дуже простий приклад з Figure, Navigationі одна кнопка , яка малює випадкові дані. Я додав коментарі, щоб пояснити речі.

import sys
from PyQt4 import QtGui

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure

import random

class Window(QtGui.QDialog):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        # a figure instance to plot on
        self.figure = Figure()

        # this is the Canvas Widget that displays the `figure`
        # it takes the `figure` instance as a parameter to __init__
        self.canvas = FigureCanvas(self.figure)

        # this is the Navigation widget
        # it takes the Canvas widget and a parent
        self.toolbar = NavigationToolbar(self.canvas, self)

        # Just some button connected to `plot` method
        self.button = QtGui.QPushButton('Plot')
        self.button.clicked.connect(self.plot)

        # set the layout
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.toolbar)
        layout.addWidget(self.canvas)
        layout.addWidget(self.button)
        self.setLayout(layout)

    def plot(self):
        ''' plot some random stuff '''
        # random data
        data = [random.random() for i in range(10)]

        # create an axis
        ax = self.figure.add_subplot(111)

        # discards the old graph
        ax.clear()

        # plot data
        ax.plot(data, '*-')

        # refresh canvas
        self.canvas.draw()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)

    main = Window()
    main.show()

    sys.exit(app.exec_())

Редагувати :

Оновлено з урахуванням коментарів та змін API.

  • NavigationToolbar2QTAgg змінився з NavigationToolbar2QT
  • Безпосередньо імпортувати Figureзамістьpyplot
  • Замінити застаріле ax.hold(False)наax.clear()

14
Зверніть увагу, що відповідно до цієї примітки щодо SO не слід імпортувати pyplot під час вбудування. Він робить такі забавні речі, як запуск власного графічного інтерфейсу із власним основним циклом. Є приклад Matplotlib щодо вбудовування
Лоуренс Біллінгем,

9
У мене помилка: MatplotlibDeprecationWarning: Цей клас застарів у версії 1.4, оскільки він не має додаткової функціональності NavigationToolbar2QT. Будь ласка, змініть свій код, щоб використовувати NavigationToolbar2QTзамість mplDeprecation)
GSandro_Strongs

5
@ gs_developer_user3605534 заміна NavigationToolbar2QTAggна NavigationToolbar2QTвбиває повідомлення
SAAD

Коли я використовую цей код, він створює два вікна, одне головне вікно Qt і одну фігуру matplotlib. Як я можу цього уникнути, щоб воно створило лише одне головне вікно Qt? Я використовую python 3.4 32bit, matplotlib 1.5.3 та PyQt4 (мені також довелося перейти NavigationToolbar2QTAggна NavigationToolbar2QT). Я виявив, що одним із рішень є використання IPython
C Winkler

Я використовую це для розміщення QVBoxLayoutвсередині головного вікна. Чи можна отримати полотно та фігуру, щоб заповнити високий прямокутник (приблизно у 1,5 рази вищий, ніж він широкий)?
Кайса

73

Нижче наведено адаптацію попереднього коду для використання під PyQt5 та Matplotlib 2.0 . Існує ряд невеликих змін: замінено структуру підмодулів PyQt, інші підмодулі з matplotlib, застарілий метод ...


import sys
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayout

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt

import random

class Window(QDialog):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        # a figure instance to plot on
        self.figure = plt.figure()

        # this is the Canvas Widget that displays the `figure`
        # it takes the `figure` instance as a parameter to __init__
        self.canvas = FigureCanvas(self.figure)

        # this is the Navigation widget
        # it takes the Canvas widget and a parent
        self.toolbar = NavigationToolbar(self.canvas, self)

        # Just some button connected to `plot` method
        self.button = QPushButton('Plot')
        self.button.clicked.connect(self.plot)

        # set the layout
        layout = QVBoxLayout()
        layout.addWidget(self.toolbar)
        layout.addWidget(self.canvas)
        layout.addWidget(self.button)
        self.setLayout(layout)

    def plot(self):
        ''' plot some random stuff '''
        # random data
        data = [random.random() for i in range(10)]

        # instead of ax.hold(False)
        self.figure.clear()

        # create an axis
        ax = self.figure.add_subplot(111)

        # discards the old graph
        # ax.hold(False) # deprecated, see above

        # plot data
        ax.plot(data, '*-')

        # refresh canvas
        self.canvas.draw()

if __name__ == '__main__':
    app = QApplication(sys.argv)

    main = Window()
    main.show()

    sys.exit(app.exec_())

Дуже корисне оновлення, працює нормально! Не могли б ви дати посилання на ax.holdте, що вас припинили? Крім того, чому б не використовувати ax.clearдля повторного використання екземпляра Axes?
П'єр Х.

3
Я вважаю, що це не найкраща практика імпортувати matplotlib.pyplotпри вбудовуванні matplotlib у pyqt (будь ласка, виправте мене, якщо я помиляюся в цій ситуації). Якщо я правильно, я вмонтував свій Matplotlib , використовуючи цей метод на цьому SO пост, який робить імпорт pyplot: stackoverflow.com/questions/43947318 / ...
hhprogram

Як нанести зображення на полотно?
Neeraj Kumar

2

Для тих, хто шукає динамічне рішення для вбудовування Matplotlib у PyQt5 (навіть побудова даних за допомогою перетягування та перетягування). У PyQt5 вам потрібно використовувати супер у класі головного вікна, щоб прийняти краплі. Функцію dropevent можна використовувати для отримання імені файлу, а відпочинок простий:

def dropEvent(self,e):
        """
        This function will enable the drop file directly on to the 
        main window. The file location will be stored in the self.filename
        """
        if e.mimeData().hasUrls:
            e.setDropAction(QtCore.Qt.CopyAction)
            e.accept()
            for url in e.mimeData().urls():
                if op_sys == 'Darwin':
                    fname = str(NSURL.URLWithString_(str(url.toString())).filePathURL().path())
                else:
                    fname = str(url.toLocalFile())
            self.filename = fname
            print("GOT ADDRESS:",self.filename)
            self.readData()
        else:
            e.ignore() # just like above functions  

Для початку посилальний повний код дає такий результат: введіть тут опис зображення

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.