Cách nhúng matplotlib vào pyqt - dành cho Dummies


77

Tôi hiện đang cố gắng nhúng biểu đồ mà tôi muốn vẽ vào giao diện người dùng pyqt4 mà tôi đã thiết kế. Vì tôi gần như hoàn toàn mới trong việc lập trình - tôi không hiểu mọi người đã nhúng như thế nào vào các ví dụ mà tôi tìm thấy - cái này (ở dưới cùng)cái kia .

Sẽ thật tuyệt vời nếu ai đó có thể đăng giải thích từng bước hoặc ít nhất là một đoạn mã rất nhỏ, rất đơn giản chỉ tạo ra ví dụ như một biểu đồ và một nút trong một pyqt4 GUI.

Câu trả lời:


113

Nó không phải là phức tạp thực sự. Các widget Qt có liên quan đang ở trong matplotlib.backends.backend_qt4agg. FigureCanvasQTAggNavigationToolbar2QTthường là những gì bạn cần. Đây là những vật dụng Qt thông thường. Bạn coi chúng như bất kỳ widget nào khác. Dưới đây là một ví dụ rất đơn giản với một Figure, Navigationvà một nút duy nhất mà rút ra một số dữ liệu ngẫu nhiên. Tôi đã thêm nhận xét để giải thích mọi thứ.

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_())

Chỉnh sửa :

Cập nhật để phản ánh nhận xét và thay đổi API.

  • NavigationToolbar2QTAgg thay đổi với NavigationToolbar2QT
  • Nhập trực tiếp Figurethay vìpyplot
  • Thay thế không dùng nữa ax.hold(False)bằngax.clear()

14
Lưu ý rằng theo ghi chú SO này , người ta không nên nhập pyplot khi nhúng. Nó thực hiện điều sôi nổi như chạy GUI riêng của mình với loop.There chính riêng của mình là một ví dụ Matplotlib trên nhúng
Laurence Billingham

9
Tôi gặp lỗi: MatplotlibDeprecationWarning: Lớp này đã không được chấp nhận trong phiên bản 1.4 vì nó không có chức năng bổ sung NavigationToolbar2QT. Vui lòng thay đổi mã của bạn để sử dụng NavigationToolbar2QTthay thế mplDeprecation)
GSandro_Strongs 26/10/15

5
@ gs_developer_user3605534 thay thế NavigationToolbar2QTAggbằng cách NavigationToolbar2QTloại bỏ thông báo
SAAD

Khi tôi sử dụng mã này, nó tạo ra hai cửa sổ, một cửa sổ chính Qt và một hình matplotlib. Làm cách nào để tránh điều đó để nó chỉ tạo một cửa sổ chính Qt? Tôi sử dụng python 3.4 32bit, matplotlib 1.5.3 và PyQt4 (tôi cũng đã phải thay đổi NavigationToolbar2QTAggthành NavigationToolbar2QT). Tôi thấy rằng một giải pháp đang sử dụng IPython
C Winkler

Tôi đang sử dụng cái này để đặt QVBoxLayoutbên trong cửa sổ chính. Có cách nào để khung và hình lấp đầy một hình chữ nhật cao (chiều cao xấp xỉ 1,5 lần chiều rộng)?
Kajsa

73

Dưới đây là sự điều chỉnh của mã trước đó để sử dụng trong PyQt5Matplotlib 2.0 . Có một số thay đổi nhỏ: cấu trúc của mô-đun con PyQt, mô-đun con khác từ matplotlib, phương thức không dùng nữa đã được thay thế ...


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_())

Cập nhật rất hữu ích, chạy tốt! Bạn có thể cung cấp tài liệu tham khảo cho ax.holdviệc không được dùng nữa không? Ngoài ra, tại sao không sử dụng ax.clearđể sử dụng lại cá thể Axes?
Pierre H.

3
Tôi nghĩ rằng cách tốt nhất không phải là nhập matplotlib.pyplotkhi nhúng matplotlib vào pyqt (vui lòng sửa cho tôi nếu tôi sai trong cách chọn này). Nếu tôi đúng, tôi nhúng matplotlib tôi sử dụng phương pháp này trên bài SO này, mà không làm pyplot nhập khẩu: stackoverflow.com/questions/43947318/...
hhprogram

Làm cách nào để vẽ các hình ảnh trên canvas?
Neeraj Kumar

2

Đối với những người đang tìm kiếm một giải pháp động để nhúng Matplotlib vào PyQt5 (thậm chí cả dữ liệu biểu đồ bằng cách sử dụng kéo và thả). Trong PyQt5, bạn cần sử dụng super trên lớp cửa sổ chính để chấp nhận các giọt. Hàm dropevent có thể được sử dụng để lấy tên tệp và phần còn lại rất đơn giản:

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  

Đối với người mới bắt đầu, tham chiếu hoàn chỉnh cung cấp đầu ra này: nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.